指针是什么
1.指针是内存中一个最小单元的编号,也就是地址
2.平时口头语中所说的指针,通常指的是指针变量,是用来存放地址的变量
总的来说,指针就是地址,口头中说的指针通常指的是指针变量
指针变量,用来存放地址的变量(存放在指针中的值都会被当成地址来处理)
1.内存被划分成一个个的内存单元,每个内存单元的大小是1个字节。
2.每个字节的内存单元都有一个编号,这个编号就是地址,地址在C语言中被称为指针。
3.地址要存储的话,存放在指针变量中。
4.每个内存单元都有一个唯一的地址来标识。
5.在32位机器上地址的大小是4个字节,所以指针变量的大小也是4个字节。
指针类型是有意义的,指针类型决定了指针+1 / -1跳过几个字节。
int*的指针 +1 跳过4个字节 short*的指针 +1跳过两个字节
char* 的指针 +1跳过一个字节 double*的指针 +1跳过8个字节
总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。
指针的类型决定了指针在解引用的时候有多大的权限(能操作几个字节)。
比如:char* 的指针解引用就只能够访问1个字节,而int*指针的解引用就能访问4个字节。
野指针——野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
int main()
{
int* p = (int*)0x11223344; //野指针的一种,随机给的地址
*p;
return 0;
}
int main()
{
int* p;//野指针的一种,指针未初始化
*p = 10;
return 0;
}
规避野指针的方法:
1.指针初始化(如果指针明确应该指向哪里,就初始化正确的地址)
int a = 10;
int* p = &a;
如果指针不知道初始化什么值,为了安全,初始化NULL
int* p = NULL;
2.小心指针越界
3.指针指向空间释放,及时置NULL
4.避免访问局部变量的地址
5.指针使用之前检查有效性
NULL——0
0作为地址的时候,该地址用户程序是不能够访问的
int main()
{
int* p = NULL;
if(p != NULL)
{...
}
return 0;
}
指针的运算
指针+ - 整数 指针-指针 指针的关系运算
C语言标准规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
关于strlen()函数的算法,指针版(运用了指针 - 指针等于元素之间个数)
size_t my_strlen(char* arr)
{
char* start = arr;
while (*arr)
{
if (*arr != '\0')//也可以去掉'\0'因为'\0'的ASCII码值就是0
{
arr++;
}
}
return arr - start;
}
int main()
{
char arr[] = "abcdefg";//abcdefg'\0';
size_t len = my_strlen(arr);
printf("%zd\n", len);
return 0;
}
指针和数组
指针就是指针,指针变量就是一个变量,存放的是地址,指针变量的大小是4个或者8个字节
数组就是数组,可以存放一组数,数组的大小是取决于元素的类型和个数
数组的数组名是数组首元素的地址,地址是可以放在指针变量之中的
但是有两个例外——1.sizeof(数组名),数组名单独放在sizeof内部,数组名表示的是整个数组,计算的是数组的大小,单位是字节
2.&数组名,此时数组名表示的是整个数组,取出的是数组的地址,数组的地址和数组的首元素的地址在值上面是一样的,但是类型和所表示的意义是不一样的
int main()
{
int arr[10] = { 0 };
printf("%p\n", arr);//数组首元素的地址
printf("%p\n", arr + 1);
printf("%p\n", &arr + 1);
printf("%p\n", &arr[0]);//数组首元素的地址
printf("%p\n", &arr);//数组的地址
printf("%d\n", sizeof(arr));
return 0;
}
通过指针可以访问一个数组的元素
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i < 10; i ++ )
{
printf("%p === %p\n", arr + i, p + i);
}
return 0;
}