一、数组与指针的关系
数组:数组是用于储存多个相同类型数据的集合。
指针:指针相当于一个变量,但是它和不同变量不一样,它存放的是其它变量在内存中的地址。
PS:使用const创建数组时必须初始化赋值,后续无法在进行赋值。
数组是实际上是一块连续的地址,而指针也是表示地址,所以说数组是特殊的指针,数组是const类型的指针,即数组的地址不可以赋值,在函数中,数组传参是会退化成指针。
看下面的例子:
#include<stdio.h>
#include<stdlib.h>
void show_1(int a[])
{
int i = 0;
while (a[i] != -1)
{
printf("%d\t", a[i++]);
}
printf("\n");
}
void show_2(int *a)
{
while (*a != -1)
{
printf("%d\t",*a++);
}
printf("\n");
}
int main()
{
int a[5] = { 1, 2, 3, 4, -1 }; //-1作为结束标志位
show_1(a);
show_2(a);
return 0;
}
可见对函数传递数组时可以使用指针进行操作。
二、指针
1.初始化
定义指针时最好初始化,可以这么初始化int *p = NULL; or int *q = 0;
或者直接指向一个向量地址如int i = 5; int *r = &i;
2.const位置
(1)如果const在号前面的话说明不能通过指针对指针所指地址里面的值进行修改;
(2)若果const在号后面的话就说明不能修改指针所指的地址;
下面这个例子就是两种const的错误示范:
int i = 5;
int k = 3;
const int *p = &i; //const数值
int * const q = &i; //const指针
*p = 132; //无法对指针所指地址里面的值进行修改
q = &k; //无法对指针进行重赋值
3.指针加1
我们知道对一个数值加1,比如1+1=2;这个很简单,但是对指针加1会是什么样子呢?我们先上一段代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
char b[] = { 1,2,3,4,5,6 };
int a[] = { 1,2,3,4,5,6 };
int *p1 = &a[0];
int *p2 = &a[5];
char *q1 = &b[0];
char *q2 = &b[4];
printf("%p\n", p1);
printf("%p\n", p2);
printf("%p\n", p1+1);
printf("%p\n", p2+1);
//选中代码段,先按住Ctrl+k,再按Ctrl+c,就可以进行如下注释
//printf("%p\n", q1);
//printf("%p\n", q2);
return 0;
}
我们运行程序可以看见p1和(p1+1)的值相差4;而q1和(q1+1)却只相差1。这是因为p1是int型的,在计算机中为四个字节,所以(p1+1)就表示增加了一个int,同理q1也是如此。
4.两个指针相减
#include<stdio.h>
#include<stdlib.h>
int main()
{
char b[] = { 1,2,3,4,5,6 };
int a[] = { 1,2,3,4,5,6 };
int *p1 = &a[0];
int *p2 = &a[5];
char *q1 = &b[0];
char *q2 = &b[4];
//printf("p1的地址 = %p\n", p1);
//printf("p1+1的地址 = %p\n", p1+1);
//printf("q1的地址 = %p\n", q1);
//printf("q1+1的地址 = %p\n", q1+1);
printf("%d\n", p2 - p1);
printf("%d\n", q2 - q1);
return 0;
}
得到结果
原因和第3点一样不重复说明。
PS:*p++指的是先取出p里面的值,然后再把地址加1。这条语句可以被某些CPU直接翻译成汇编语言,所以效率高。
5. 0地址
使用:
- 假设动态分配内存失败,则会返回一个NULL
- 指针初始化
int *p = NULL;
6. void* 和动态分配内存
void* 表示创建不知道指向什么的指针,假设我们刚开始不知道这个指针要指向什么,我们可以先这么创建,之后再利用强制转换改变类型。
malloc():动态分配内存。申请失败返回NULL or 0。
free():只能释放掉动态分配的内存。
两个一定要成对使用,避免内存越用越小,导致程序速度越来越慢。
#include<stdio.h>
#include<stdlib.h>
int main()
{
int len = 5;
int *p = (int*)malloc(sizeof(int) * len);
free(p);
return 0;
}
三、字符串
1. 字符串头文件
常用字符串函数都包含在头文件#include<string.h>
里面
2. 常用字符串函数
1、字符串的拷贝
/直接将源中的字符串复制到目标/
char *strcpy(char *dest, const char *src)
{
char *tmp = dest;
while ((*dest++ = *src++) != '\0');
return tmp;
}
/将源字符串中的前count 个字符复制到目标/
char *strncpy(char *dest, const char *src, size_t count)
{
char *tmp = dest;
while (count)、
{
if ((*tmp = *src) != 0)
src++;
tmp++;
count--;
}
return dest;
}
2、连接两个字符串
char *strcat(char *dest, const char *src)
{
char *tmp = dest;
while (*dest)
dest++;
while ((*dest++ = *src++) != '\0')
;
return tmp;
}
/将源字符串中的前count个字符附加到目标字符串的尾部/
char *strncat(char *dest, const char *src, size_t count)
{
char *tmp = dest;
if (count)
{
while (*dest)
dest++;
while ((*dest++ = *src++) != 0)
{
if (--count == 0)
{
*dest = '\0';
break;
}
}
}
return tmp;
}
3、比较两个字符串
int strcmp(const char *cs, const char *ct)
{
int res;
while (1)
{
if ((res = *cs - *ct++) != 0 || !*cs++)
break;
}
return res;
}
/只比较前count个字符/
int strncmp(const char *cs, const char *ct, size_t count)
{
signed char __res = 0;
while (count)
{
if ((__res = *cs - *ct++) != 0 || !*cs++)
break;
count--;
}
return __res;
}
4、在字符串中查找找一个字符
/在字符串中查找第一次出现要查找的字符/
char *strchr(const char *s, char c)
{
for (; *s != c; ++s)
if (*s == '\0')
return NULL;
return (char *)s;
}
/在字符串中查找最后一次出现要查找的字符/
char *strrchr(const char *s, int c)
{
const char *p = s + strlen(s);
do {
if (*p == (char)c)
return (char *)p;
} while (--p >= s);
return NULL;
}
/在有限制长度的字符串中查找第一次出现要查找的字符/
char *strnchr(const char *s, size_t count, char c)
{
for (; count-- && *s != '\0'; ++s)
if (*s == c)
return (char *)s;
return NULL;
}
5、求字符串的长度
size_t strlen(const char *s)
{
const char *sc;
for (sc = s; *sc != '\0'; ++sc);
return sc - s;
}
6、在源字符串中查找子字符串
char *strstr(const char *s1, const char *s2)
{
int l1, l2;
l2 = strlen(s2);
if (!l2)
return (char *)s1;
l1 = strlen(s1);
while (l1 >= l2) 、
{
l1--;
if (!memcmp(s1, s2, l2))
return (char *)s1;
s1++;
}
return NULL;
}