前言:
上文我们已经学习了指针的基本概念、内存单元地址的产生,以及指针和指针的类型。这时我们对指针已经有了一个初步的了解,接下来我们将继续深入的学习指针用法。
一. 野指针
(一)概念:
野指针就是指针指向的位置使不可知的(随机的、不正确的、没有明确限制的)
int main()
{int* p;//p没有初始化就意味着没有明确的指向//一个局部变量不初始化的话,放的是随机值;//会初始化为一部内容,一般是0xcccccccc这样的值//这时它就会把0xcccccccc当作是它的地址//但这个地址所指向的空间不是它的//也就是说它使用的地址是一个非法的地址*p = 10;//非法访问内存了,这里的p就是野指针return 0;
}
(二)野指针成因
1. 指针未初始化(就是上面那种)
2. 指针越界访问
int main()
{int arr[10] = { 0 };int* p = arr;for (int i = 0; i <= 10; i++){*p = i;p++;}//指针指到前面10个地址的时候还不是野指针//指针指到第10个地址后面的地址时就是野指针return 0;
}
3. 指针指向的空间释放
int* test()
{int a = 0;return &a;//a会在这里取好一个地址然后返回去//这时*p的地址就是a所取的这个地址
}//但是一旦出了test()函数的时候,//a就会立即销毁这个地址,//也就是将地址还给了操作系统,//这时这个空间已经不属于a和p了,//但是p依然保存着这个地址,//所以p还能找到这个空间,//当p再往下执行的时候就是野指针。
int main()
{int* p = test();return 0;
}
(三)如何尽量避免野指针的出现
1.指针初始化
2.小心指针越界
3.避免返回局部变量
4.指针使用之前有效性的检查
二. 指针与数组
int main()
{int arr[10] = { 0 };//arr是首元素的地址int* p = arr;//通过指针来访问地址return 0;
}
三. 指针的运用
1. 指针+-整数
//例:给数组初始化
//法一:
#define n 5
int main()
{float arr[n];float* a;for (a = &arr[0]; a < &arr[n];){*a++ = 1;}return 0;
}
//法二:
#define n 10
int main()
{int arr[n] = { 0 };int* p = arr;for (int i = 0; i < n; i++){*p = 1;p++;}return 0;
}
补充:*a++ 与(*a)++的区别是:前者是给地址++;后者是给指针所指向的对象进行++,比如*a所指向的对象是0,那么(*a)++执行一次后*a所指向的对象就变为1了。
2. 指针-指针
指针-指针得到绝对值的是指针和指针之间元素的个数,如下图
但不是所有的指针都能相减,只有指向同一块空间的两个指针相减才有意义。例如下面这种。
四. 二级指针
二级指针是用来存放一级指针变量的地址
int main()
{int a = 10;int* pa = &a;//pa是一个一级指针变量int** pi = &pa;//pi是一个二级指针变量**pi = 20;return 0;
}
五. 指针数组
存放指针的数组其实指针数组,如下图。
使用指针数组模拟二维数组: