文章目录
1.指针是什么
(1)指针
指针是内存中一个最小单元的编号即地址,口语中所说的指针一般是指针变量。
(2)指针变量
指针变量是用来存放地址的变量,存放在此变量中的值都被当成地址来处理。
(3)指针的大小
32位平台(x86环境下)下4个字节,64位平台(x64环境下)下8个字节.
2.指针和指针类型
(1)指针定义方式
定义方式:type+*
例如:字符型:char *p=NULL;
整形:int* p=NULL;
(2)指针的类型
指针的类型:整形指针、浮点型指针、字符指针、数组指针、函数指针等。【变量有什么类型,指针就有对应的指针】
(3)指针类型的意义
①决定执行操作——指针±整数,跳过多少个字节即决定步长是多少
②决定指针解引用后操作权限有多大——可以改变内存中某个字节的数
例如:char*
的解应用只能访问一个字节,而int*
的解引用可以访问4个字节,double*
的解引用可以访问8个字节
·后续有对应练习题
3.野指针
(1)野指针是什么
野指针就是指针变量中的值是非法的内存地址,野指针不是空指针(NULL)。
(2)野指针危害
野指针危害:会导致内存越界、段错误等问题。
另:合法的内存地址包括定义的变量的地址,malloc函数申请堆内存放回的地址但并未使用free释放.
(3)野指针的常见规避
①局部变量初始化
全局变量不初始化会自动赋值为0,但局部变量不会。
所以我们定义局部指针变量时最好将局部指针变量初始化NULL,局部变量初始化为0。
②不要在函数中返回局部/形式变量和局部/形式数组的地址。
函数中形参的地址在函数调用结束后、指针变量赋值前就立刻被销毁了,所以此时指向的地址时非法的。
③在将指针变量指向的地址释放之后将指针变量的值赋为NULL,不使用已经释放过的指针
④避免指针运算错误
操作指针不当会造成指针一块已经被别的进程使用的内存,为避免这种情况,一定确保字符数组要以'\0'
结尾,自己使用内存函数和编写的内存相关函数指定长度信息,防止内存越界。
⑤避免错误的强制类型转换
常出现的一种情况就是,在多层级的解引用操作下,(譬如:(int *)((int)a + 1)
)将int
或者整形的数据误认为一个地址强制转换成指针类型【指针变量内存放的数据本质上是一个整形】,导致指向非法空间。
4.指针运算
并非对指针的任何运算都是合法的,其实指针可进行的运算类型非常少,主要分为以下两大类三小种。
(1)指针的算术运算
C的指针运算只局限于以下两种形式:指针±整数、指针-指针。且前者标准定义只用于指向数组中某个元素的指针
①指针±整数
当一个指针和一个整数进行算数运算时,始终会根据合适的大小进行调整。这个合适的大小就是指针所指向类型的大小.
计算结果仍为指针。
//第一种
float x[5]={1,2,3,4,5};
float* p=&x[0];
p++;
//第二种
double a[5]={1,2,3,4,5};
double* pa=&a[0];
pa++;
此时p++
这里是指针p一次加上4个字节【float类型是4个字节】,pa++
这里是指针pa一次加上8个字节【double类型是8个字节】
②指针-指针
前提:当两个指针都指向同一个数组中的元素时才允许用一个指针-另外一个指针【 假设要求结果有意义】。
减法运算的值是两个指针在内存中的距离(以数组元素的长度为单位,而不是 以字节为单位!!!)
所以,计算结果为两指针间此种类型元素的个数。
(2)指针的关系运算
前提:<、>、>=、<=运算要求运算前后都指向同一个数组的元素。
常见使用场景
for(vp = &values[N_VALUES]; vp > &values[0];)
{
*--vp = 0;
}
另:指向数组元素指针只能允许指向数组内部元素,然而当由于错误操作导致数组越界时,当指针指向数组首元素前的那个内存位置时是不被允许的,编译器会直接报错——非法访问内存,而当指针指向数组最后一个元素之后的那个内存位置时虽然不会报错,但得出的结果一般会是随机值;允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
以上结果是由于标准和操作系统内存访问要求共同作用的结果。
5.指针和数组
(1)数组名含义
数组名含义:本质上是数组首元素地址,两种情况下除外——sizeof(数组名)
【计算的整个数组的大小】以及&数组名
【取的是整个数组的大小,类型为数组元素类型(*)[个数]
】
(2)可以通过指针访问数组
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i<sz; i++)
{
printf("%d ", *(p + i));
}
return 0; }
6.二级指针
指针变量本质上是变量,是变量就会有地址,内容为指针变量的地址的指针就是二级指针。
7.指针数组
本质是数组。类比:整形数组、字符数组等可知,前边时数组元素的类型,后边是本质。
故:指针数组就是每个数组元素都是指针的数组。