Day06.2021.11.3
空指针
指针变量指向内存中编号为0的空间
用于初始化指针变量(初始化一个指针,不知道指向哪,就指向空指针)
空指针指向的内存不可以访问
int* p = NULL; /* *p=100是错误的 */
野指针
指针变量指向非法的内存空间
比如把一个十六进制的数强转成一个指针变量,但这个指针对应的内存我们没有权利访问,这叫非法,执行会报错:访问权限冲突
//野指针:应避免出现 int* p1 = (int*)0x0010; cout << *p1 << endl;
const修饰指针
-
修饰指针:常量指针
-
修饰常量:指针常量
-
都修饰
-
常量指针:指针的指向可以改,但指针指向的值不可以改,图中可以从指向a改成指向b,但是值10不可以改
//常量指针:指向常量的指针(所以常量不可以变,但可以把指针指向改了) int a = 10; int b = 20; const int* p = &a; //*p = 30;报错 p = &b;
-
指针常量:指针的指向不可以改,但指针指向的值可以改,图中不可以从指向a改成指向b,但是值10可以改
//指针常量:指针本身就是一个常量(所以不能改指向,但可以改指向的值) int a = 10; int b = 10; int* const p = &a; //p = &b;报错 *p = 30;
据个人理解方式,const int* p常量指针;int* const p指针常量
也有说法是:const作用于左侧,const int* p由于左侧没东西所以作用在右侧,作用在int上,所以不能改值,int* const p作用在左侧*,作用在指针,所以不能改指向
-
既修饰指针又修饰常量
int a = 10; const int* const p = &a;
指针和数组
利用指针可以访问数组中的每个元素
int arrays[10] = {1,2,3,4,5,6,7,8,9,10}; cout << "第一个元素:" << arrays[0] << endl; int* p = arrays;//数组名就是数组首地址 cout << "第一个元素的地址:" << p << endl; cout << "解引用访问数组第一个元素:" << *p << endl; p++;//让指针向后偏移四个字节 cout << "解引用访问数组第二个元素:" << *p << endl;
利用指针遍历数组
int* a = arrays; for (int i = 0; i < 10; i++) { cout << *a << endl; a++; //或者直接一行下来cout << *(a++) << endl; }
指针和函数
值传递:形参里放的是实参的数值,形参改变不会影响实参(因为形参是创建新的内存单元,把实参的数据复制过来,操作复制的值,所以不会改变实参中的数据)
地址传递:通过解引用指针来直接操作指针对应的数据,直接操纵实参。
void swapPtr(int* a, int* b); int main() { //地址传递 int a = 10; int b = 20; swapPtr(&a, &b); cout << a << endl; cout << b << endl; system("pause"); return 0; } void swapPtr(int* a, int* b) { int index = *a; *a = *b; *b = index; }
指针、数组、函数
案例:封装一个函数,利用冒泡排序,实现对一个整型数组的升序排列
本来写成这样
void arraySort(int arrays[]); int main() { int arrays[] = { 2,5,6,7,9,1,4,8,10,3 }; arraySort(arrays); system("pause"); return 0; } void arraySort(int arrays[]) { for (int i = 0; i < ( sizeof(arrays) / sizeof(arrays[0])); i++) { for (int j = 0; j < ( sizeof(arrays) / sizeof(arrays[0]) - i - 1); j++) { if (arrays[j] < arrays[j + 1]) { int index = arrays[j]; arrays[j] = arrays[j + 1]; arrays[j + 1] = index; } } } for (int i = 0; i < ( sizeof(arrays) / sizeof(arrays[0])); i++) { cout << arrays[i] << " " << endl; } }
但是输出结果就只有一个2,找了很久原因,是这样写的:
如果在函数中定义数组A,sizeof(A)是所有数组元素所占用的内存空间字节数,因为编译器在将 C 代码转换成汇编代码时,自动将其替换成了实际的数值,因此可以通过sizeof(A)/sizeof(A[0])计算数组大小。
但是A实际是一个指针,表示的是这个数组首个元素的地址,不信你可以试着尝试cout<<A<<endl,你会发现输出的是一个地址。所以如果此数组在函数外定义,然后作为函数的输入参数传入,则传入的A只能表示指针,所以此时sizeof(A)为A[0]的地址的长度(x86地址长度为32位,即4个字节)。所以sizeof(A)/sizeof(A[0])为1(x86)。所以在我们传入这种数组做参数时,通常同时会再多传一个参数记录数组的长度
没理解的话参考一下
https://blog.csdn.net/qq_40692109/article/details/102766573
https://www.zhihu.com/question/30558041
https://blog.csdn.net/Helianthus_/article/details/54598665
注意:
这里别在排序函数里算数组长度len,通过将数组作为函数参数传递到函数中,以获得数组长度是不可行的。所以,sizoef(arr)的结果是指针变量arr占内存的大小,指针在32位下是4个字节。arr[0]是int类型,sizeof(arr[0])也是4个字节,所以,结果永远是1。这句话同样解释了上面的问题
#include"methodState.h" void arraySort(int arrays[],int length); int main() { int arrays[] = { 2,5,6,7,9,1,4,8,10,3 }; /*这里别在排序函数里算数组长度len,通过将数组作为函数参数传递到函数中,以获得数组长度是不可行的。 所以,sizoef(arr)的结果是指针变量arr占内存的大小,指针在32位下是4个字节。 arr[0]是int类型,sizeof(arr[0])也是4个字节,所以,结果永远是1。*/ int length = sizeof(arrays) / sizeof(arrays[0]); arraySort(arrays,length); system("pause"); return 0; } void arraySort(int arrays[],int length) { /*这里实际上可以写void arraySort(int* arrays,int length),因为在函数里数组以指针形式传进来,就可以直接传一个首地址和长度,循环中的arrays[i]都是通过指针访问数组元素*/ for (int i = 0; i < length; i++) { for (int j = 0; j < length - i - 1; j++) { if (arrays[j] > arrays[j + 1]) { int index = arrays[j]; arrays[j] = arrays[j + 1]; arrays[j + 1] = index; } } } for (int i = 0; i < length; i++) { cout << arrays[i] << " "; } cout << endl; }
P63结束
来源:b站黑马