东莞机电学校网站建设与管理,人工智能公众号,android简单开发app实例代码,市场营销论文选题方向指针的基本概念#xff1a; 指针是一个变量#xff0c;对应内存中唯一的一个地址指针在32位平台下的大小是4字节#xff0c;在64位平台下是8字节指针是有类型的#xff0c;指针类型决定该指针的步长#xff0c;即走一步是多长指针运算#xff1a;指针-指针表示的是两个指… 指针的基本概念 指针是一个变量对应内存中唯一的一个地址指针在32位平台下的大小是4字节在64位平台下是8字节指针是有类型的指针类型决定该指针的步长即走一步是多长指针运算指针-指针表示的是两个指针之间的元素个数 回顾完指针的初阶用法今天我们要来讲讲指针更高阶的用法
一、字符指针
字符指针就是一个指针指向一个字符
int main()
{char ch a;char* pc ch;printf(%c\n, *pc);//打印areturn 0;
}
还有另一种用法
int main()
{char* p abcdefg;printf(%c\n, *p);//打印areturn 0;
}
该怎么理解呢其实右边的abcdefg是一个字符常量p中存放的是该字符常量首元素的地址。也就是a的地址。
来看看一组练习
int main()
{char arr1[] abcdefg;char arr2[] abcdefg;char* arr3 abcdefg;char* arr4 abcdefg;if (arr1 arr2)printf(arr1和arr2相等\n);elseprintf(arr1和arr2不相等\n);if(arr3 arr4)printf(arr3和arr4相等\n);elseprintf(arr1和arr2不相等\n);return 0;
} 解答 二、指针数组
首先我们得明白指针数组是一个数组数组中的每个元素是指针类型
int main()
{int a 1;int b 2;int c 3;int d 4;int* p1[] { a,b,c,d };//数组中的每个元素是整型指针char ch1 a;char ch2 b;char ch3 c;char ch4 d;char* p2[] { ch1,ch2,ch3,ch4 };//数组中的每个元素是字符指针return 0;
}
指针数组可以用来模拟实现一个二维数组代码如下
int main()
{int arr1[] { 1,2,3,4,5 };int arr2[] { 2,3,4,5,6 };int arr3[] { 3,4,5,6,7 };int* arr[3] { arr1,arr2,arr3 };for (int i 0; i 3; i){for (int j 0; j 5; j){printf(%d , arr[i][j]);}printf(\n);}return 0;
}
打印时arr[i]相当于每行首元素的地址通过下标j就可以依次访问每个整型数组中的元素了。
在内存中对应的关系如下
。
指针数组还有另一种用法
int main()
{char* arr[] { baiyahua,dashidai,tassel };for (int i 0; i 3; i){printf(%s , arr[i]);}return 0;
}
我们得知道arr中存的是字符bdt的地址因此分别打印三个字符长常量。 三、数组指针 3.1数组指针的定义
要同前面的指针数组区别开数组指针本质上是一个指针该指针指向一个数组。
int arr[] { 1,2,3,4,5 };
拿这个代码举例我们想要将该数组的地址存一个指针当中得到的那个指针就是一个数组指针。要完成这个操作需要解决两个问题。
1.怎么取出数组的地址
2.数组指针的类型改怎么写
对于第一个问题我们先来梳理一下数组名的概念 数组名表示首元素的地址两个情况除外 sizeof(数组名)表示整个数组的大小单位是字节数组名表示取出整个数组的地址 到这里第一个问题就解决了要得到一个数组的地址只需要数组名就行了。
对于第二个问题C语言规定的语法是这样写的
int(*p)[5] arr;int *p[5] arr;//错误的写法
注意不能写成下面的形式因为p首先会跟[]结合表明这是一个数组数组中的每个元素是int*类型p就变成了一个指针数组了。所以一定要将*和p括号起来。
对于上面的形式我们可以这样理解p首先跟*结合表明这是一个指针在跟[]结合表明指针指向一个数组数组中的每个元素是int类型就是一个数组指针了。 3.2数组名和数组名
刚刚我们提到平常的数组名表示的是数组首元素的地址而数组名表示的是整个数组的地址在内存中怎么体现出来呢
还记得我们最开始讲的指针类型决定该指针的步长如果是数组指针那么1会跳过一个数组。
int main()
{int arr[5] { 1,2,3,4,5 };printf(%p\n, arr);printf(%p\n, arr 1);printf(\n);printf(%p\n, arr[0]);printf(%p\n, arr[0] 1);printf(\n);printf(%p\n, arr);printf(%p\n, arr 1);printf(\n);return 0;
} 可以看到虽然arr和arrarr[0]的值相等当时它们1的步长不同这是因为arr取出数组的地址1跳过了整个数组。 3.3数组指针的使用
理解完数组指针就该谈谈数组指针的使用了实际写代码中数组指针一般用在二维数组。
一般的二维数组打印
void Print(int arr[3][5], int row, int col)
{int i row;for (i 0; i row; i){int j col;for (j 0; j col; j){printf(%d , arr[i][j]);}printf(\n);}
}int main()
{int arr[3][5] { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };Print(arr,3,5);return 0;
}
这里的数组传参形参我们用了数组的形式实参部分我们传了二维数组的数组名数组名是首元素的地址只不过对于二维数组数组的首元素是第一行的地址也就是说实参传了一个数组的地址那形参是不是就可以用我们刚刚学的数组指针来接受了。于是就有了第二种写法
void Print(int(*p)[5] , int row, int col)
{int i row;for (i 0; i row; i){int j col;for (j 0; j col; j){printf(%d , p[i][j]);}printf(\n);}
}
这里来解释一下p[i][j]
p[i]相当于*(pi)pi是每行的地址
*(pi)就是每行的数组名而数组名又是数组首元素的地址
因此p[i]就相当于每行首元素的地址通过j就可以依次访问每行的元素。 四、数组传参和指针传参
写代码时我们难免要将一个数组或指针传参那么形参部分该如果设计
判断下面的传参是否正确
4.1一维数组传参
void test(int arr[])//ok?
{}void test(int arr[10])//ok?
{}void test(int* arr)//ok?
{}void test2(int* arr[20])//ok?
{}void test2(int** arr)//ok?
{}int main()
{int arr[10] { 0 }; int* arr2[20] { 0 };test(arr);test2(arr2);
} 4.2二维数组传参
void test(int arr[3][5])//ok
{}
void test(int arr[][])//ok
{}
void test(int arr[][5])//ok
{}
void test(int* arr)//ok
{}
void test(int* arr[5])//ok
{}
void test(int(*arr)[5])//ok
{}
void test(int** arr)//ok
{}
int main()
{int arr[3][5] { 0 };test(arr);
} 4.3一级指针传参
void Print(int* p, int sz)
{int i 0;for (i 0; i sz; i){printf(%d , *(p i));}
}int main()
{int arr[] { 1,2,3,4,5,6 };int sz sizeof(arr) / sizeof(arr[0]);int* p arr;Print(p, sz);return 0;
} 思考当函数的形参是一级指针的时候可以接受什么参数 void test(int* p)
{}int main()
{int a 1;int* p a;int arr[] { 1,2,3 };test(p);//传整型指针test(a);//传整型变量的地址test(arr);//传整型一维数组的数组名return 0;
} 4.4二级指针传参
void test(int** pp)
{printf(%d\n, **pp);
}int main()
{int a 1;int* p a;int** pp p;test(pp);test(p);return 0;
} 思考当函数的参数是二级指针的时候可以传什么参数 void test(int** pp)
{}int main()
{int a 1;int b 2;int c 3;int* p a;int** pp p;int* arr[] { a,b,c };test(pp);//传二级指针变量test(p);//传一级指针变量的地址test(arr);//传整型指针数组的数组名return 0;
} 五、函数指针
5.1函数指针的定义
函数指针就是存放一个函数地址的指针同理解数组指针一样我们得弄明白
1.怎么得到函数的地址
2.函数指针变量怎么写
这里就直接给出结论了函数名函数名都是取出函数的地址。
函数指针变量的写法 int test(int x ,int y)
{}int main()
{int(*p)(int, int) test;int(*p)(int, int) test;//两种写法都可以return 0;
} 5.2函数指针的使用
int Add(int x ,int y)
{return x y;
}int main()
{int a 1;int b 2;int c Add(1, 2);int d (*Add)(1, 2);printf(c %d d %d, c, d);return 0;
}
对于函数指针*我们可以加也可以不加两者是同等的*并没有实际的作用但是如果要加*必须跟p括号起来。
来看看两个有趣的代码
//代码1
(*(void (*)())0)();//代码2
void (*signal(int , void(*)(int)))(int);
代码1解读
该代码我们从0开始一个整数前面加上括号第一想到的应该是强制转换。
再看括号里面的部分void (*)()是一个函数指针类型该函数没有参数返回值是void类型。
加上*就是引用该函数。
于是代码的总体意思就是引用0地址处的函数该函数没有参数返回值为void类型 代码2解读
首先来看signal后面加上()容易想到是函数的定义或声明。
再看参数只有类型没有参数能确定是函数的声明。
将signal(int,void(*)(int))去掉余下的void (*)(int)就是函数的返回值类型了。
该代码的意思是声明一个函数名为signal的函数该函数的参数类型分别是int和void(*)(int)返回值类型是void(*)(int) 我们还可以对该代码进行一个简化
typedef void (*ptr)(int);将void(*)(int)类型重命名为ptr以后我们想用该类型创建变量时可以直接用ptr。
ptr signal(int, void(*)(int));六、函数指针数组
函数指针数组本质上是数组数组中每个元素都是函数指针。
6.1函数指针数组的定义
int (*arr[])(int, int);
arr首先与[]结合表明arr是个数组数组中每个元素的类型是int (*)(int, int)。 6.2函数指针数组的使用
首先我们来模拟一个简单的计算器可以实现加减乘除法
//计算器version1
void menu()
{printf(*************************\n);printf(*** 1.Add 2.Sub ****\n);printf(*** 3.Mul 4.Div ****\n);printf(*** 0.Exit ****\n);printf(*************************\n);
}int Add(int x, int y)
{return x y;
}int Sub(int x, int y)
{return x - y;
}int Mul(int x, int y)
{return x * y;
}int Div(int x, int y)
{return x / y;
}int main()
{int input 0;int x 0;int y 0;int ret 0;do{menu();printf(请输入操作:);scanf(%d, input);switch (input){case 1:printf(请输入两个操作数:);scanf(%d%d, x, y);ret Add(x, y);printf(%d\n, ret);break;case 2:printf(请输入两个操作数:);scanf(%d%d, x, y);ret Sub(x, y);printf(%d\n, ret);break;case 3:printf(请输入两个操作数:);scanf(%d%d, x, y);ret Mul(x, y);printf(%d\n, ret);break;case 4:printf(请输入两个操作数:);scanf(%d%d, x, y);ret Div(x, y);printf(%d\n, ret);break;case 0:printf(退出程序\n);break;default:printf(输入错误请重新输入\n);break;}}while (input);return 0;
}
该代码虽然能完成我们的要求但试想如果我们要更多的运算一方面我们得增加运算的定义另一方面我们还要增加case语句的长度代码就会变得非常长这时就可以使用函数指针数组来优化我们的代码。
优化后的代码如下
//计算器version2
int main()
{int input 0;int x 0;int y 0;int ret 0;int(*pf[5])(int, int) { NULL, Add, Sub, Mul, Div };//将运算函数的地址存到一个函数指针数组中//输入数字通过数组下标执行相应的函数//为了保证输入的数字和我们想要执行的函数对应//加上NULLdo{menu();printf(请输入操作:);scanf(%d, input);if (input 1 input 4){printf(请输入两个操作数:);scanf(%d%d, x, y);ret pf[input](x, y);printf(%d\n, ret);}else if (input 0){printf(退出程序\n);}else{printf(输入错误请重新输入\n);}} while (input);return 0;
}
这时我们想要增加运算时只要添加运算的定义在函数指针数组中增加新增函数的地址修改一下if条件而我们的代码长度不变大大增加了代码的可读性和维护性。
需要注意的是由于数组是存储一系列相同类型的元素因此所有函数的参数类型和返回值必须相同才能使用函数指针数组。 七、指向函数指针数组的指针
首先指向函数指针数组的指针是一个指针指向一个数组数组中每个元素的类型都是函数指针类型。
定义
int (*pf[5])(int, int) { NULL,Add,Sub,Mul,Div };int (*(*p)[5])(int, int) pf;
//*先跟p结合表明这是个指针
//往后看到[]表明指针指向一个数组数组中有5元素
//剩下的int (* )(int, int)就是元素的类型
当然我们日常写代码时很少用到指向函数指针数组的指针大家可以做个了解。 八、回调函数
8.1回调函数的定义和使用 回调函数的定义回调函数不是由函数的实现方直接调用而是处于某种特定的情境下由另一个函数通过函数指针的方式调用的。 这里用上面计算器 version1举例我们发现代码有很多冗余的部分。 这些部分能不能只写成一份于是就有了我们的计算器version3。
//计算器version3
void Calc(int (*p)(int, int))
{int x 0;int y 0;int ret 0;printf(请输入两个操作数:);scanf(%d%d, x, y);ret p(x, y);printf(%d\n, ret);
}int main()
{int input 0;do{menu();printf(请输入操作:);scanf(%d, input);switch (input){case 1:Calc(Add);break;case 2:Calc(Sub);break;case 3:Calc(Mul);break;case 4:Calc(Div);break;case 0:printf(退出程序\n);break;default:printf(输入错误请重新输入\n);break;}} while (input);return 0;
} 计算器version3中的AddSubMulDiv就是回调函数这些函数不是本身直接调用而是作为一个参数传到Calc函数中由Calc函数调用的。
这里再用库中的qsort函数来帮助大家更好的理解回调函数 8.2qsort的使用
在讲qsort函数之前简单回顾一下冒泡排序由于该排序比较简单就直接给出代码了。
void Bubble_Sort(int arr[], int sz)
{int i 0;for (i 0; i sz - 1; i){int j 0;for (j 0; j sz - 1 - i; j){if (arr[j] arr[j 1]){int tmp arr[j];arr[j] arr[j 1];arr[j 1] tmp;}}}
}void Print(int arr[], int sz)
{int i 0;for (i 0; i sz; i){printf(%d , arr[i]);}printf(\n);
}int main()
{int arr[] { 9,8,7,6,5,4,3,2,1 };int sz sizeof(arr) / sizeof(arr[0]);Print(arr, sz);Bubble_Sort(arr, sz);Print(arr,sz);return 0;
}
该代码的缺陷是只能排序整型数据当我们想要排序结构体类型字符类型等的数据它就不能完成要求但qsort函数是可以做到的。
qsort函数是C语言的库函数大家可以自行查找具体用法这里就给出它大致的用法。
void qsort(void* base, size_t num, size_t size,int (*compar)(const void* p1, const void* p2));
//base指向待排序的数组
//num是待排序数组元素的个数
//size是待排序数组一个元素的大小
//compar是一个函数指针p1和p2是两个待比较的元素
void*类型可以接受任意类型的数据但不能进行解引用和-1操作它没有具体的类型
为什么basep1和p2要写成void*类型呢
因为qsort要实现的是对任意类型的数据进行排序如果是int*char*等具体类型的指针就只能接收对应类型的数据想要排序其他类型的数据就得改变basep1和p2的类型而我们的库函数肯定是不能随便乱动的。
对于qsort我们只需要实现数据的比较方法函数再将该函数作为函数指针参数传到qsort函数中qsort就会自动为我们排序。
而对于compar函数我们要完成的功能是
当p1所指对象p2所指对象返回负数
当p1所指对象p2所指对象返回正数
当p1所指对象p2所指对象返回0 下面使用qsort来排序一个结构体
struct Stu
{char name[20];int age;
};void PirntStruct(const void* arr, int sz)
{int i 0;for (i 0; i sz; i){printf(%s %d\n, (((struct Stu*)arr)i)-name, ((struct Stu*)arri)-age);}printf(\n);
}//以年龄排序
int compar_by_age(const void* p1, const void* p2)
{return (((struct Stu*)p1)-age - ((struct Stu*)p2)-age);
}//以名字排序
int compar_by_name(const void* p1, const void* p2)
{return strcmp(((struct Stu*)p1)-name, ((struct Stu*)p2)-name);//字符串的比较用strcmp函数strcmp函数的返回值正好与我们要求的返回值一致
}int main()
{struct Stu stu[] { {baiyahua,20},{zhangsan,18},{lisi,13} };int sz sizeof(stu) / sizeof(stu[0]);printf(排序前:\n);PirntStruct(stu, sz);printf(以名字排序后:\n);qsort(stu, sz, sizeof(stu[0]), compar_by_name);PirntStruct(stu, sz);printf(以年龄排序后:\n);qsort(stu, sz, sizeof(stu[0]), compar_by_age);PirntStruct(stu, sz);return 0;
} 8.3qsort的模拟实现
知道了qsort的使用方法我们能不能自己实现一个qsort函数这里底层用冒泡排序来模拟一个qsort函数。
需要解决的问题
函数的参数是怎么设计的这里可以参考库中的qsort函数
怎么比较两个数据由于需要排序不同类型的数据就需要不同类型数据的比较方法我们将方法独立写成一个函数将该函数的指针传为我们的qsort函数再我们的qsort函数中调用
怎么交换两个数据我们将两个数据的内存全部交换相当于交换的两个数据
int compar(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}void Swap(char* e1, char* e2, int size)
{int i 0;for (i 0; i size; i){char tmp e1[i];e1[i] e2[i];e2[i] tmp;}
}void my_qsort(void* base, size_t num, size_t size, int compar(const void*,const void*))
{int i 0;for (i 0; i num - 1; i){int j 0;for (j 0; j num - 1 - i; j){if (compar((char*)base j * size, (char*)base (j 1) * size) 0){Swap((char*)base j * size, (char*)base (j 1) * size, size);}}}
}
这里解释一下两个地方 想要排序结构体数据时只要给出结构体数据的比较方法即可 九、指针和数组笔试题解析
int main()
{//一维数组int a[] { 1,2,3,4 };printf(%d\n, sizeof(a));// 16sizeof(数组名)计算整个数组的大小printf(%d\n, sizeof(a 0));// 4/832位机器下4字节64位机器下8字节printf(%d\n, sizeof(*a));// 4,sizeof(1),整形数据的大小printf(%d\n, sizeof(a 1));// 4/8地址的大小printf(%d\n, sizeof(a[1]));// 4sizeof(2)printf(%d\n, sizeof(a));// 4/8地址的大小printf(%d\n, sizeof(*a));// 16*和相抵消相当于sizeof(a)printf(%d\n, sizeof(a 1));// 4/8地址的大小printf(%d\n, sizeof(a[0]));// 4/8地址的大小printf(%d\n, sizeof(a[0] 1));// 4/8地址的大小return 0;
}
//字符数组
int main()
{char arr[] { a,b,c,d,e,f };printf(%d\n, sizeof(arr));//6计算数组所占空间printf(%d\n, sizeof(arr 0));//4/8地址的大小printf(%d\n, sizeof(*arr));//1字符a的大小printf(%d\n, sizeof(arr[1]));//1字符b的大小printf(%d\n, sizeof(arr));//4/8地址的大小printf(%d\n, sizeof(arr 1));//4/8地址的大小printf(%d\n, sizeof(arr[0] 1));//4/8地址的大小printf(%d\n, strlen(arr));//随机值printf(%d\n, strlen(arr 0));//随机值printf(%d\n, strlen(*arr));//程序报错a的ASCII码值是97strlen认为97是个地址而97对于的内存地址不属于我们printf(%d\n, strlen(arr[1]));//程序报错printf(%d\n, strlen(arr));//随机值printf(%d\n, strlen(arr 1));//随机值printf(%d\n, strlen(arr[0] 1));//随机值return 0;
}
int main()
{char arr[] abcdef;printf(%d\n, sizeof(arr));// 7printf(%d\n, sizeof(arr 0));// 4/8printf(%d\n, sizeof(*arr));//1printf(%d\n, sizeof(arr[1]));// 1printf(%d\n, sizeof(arr));// 4/8printf(%d\n, sizeof(arr 1));// 4/8printf(%d\n, sizeof(arr[0] 1));// 4/8printf(%d\n, strlen(arr));// 6printf(%d\n, strlen(arr 0));//6printf(%d\n, strlen(*arr));//程序报错printf(%d\n, strlen(arr[1]));//程序报错printf(%d\n, strlen(arr));//6printf(%d\n, strlen(arr 1));//随机值printf(%d\n, strlen(arr[0] 1));//5return 0;
}
int main()
{char* p abcdef;printf(%d\n, sizeof(p));// 4/8printf(%d\n, sizeof(p 1));// 4/8printf(%d\n, sizeof(*p));// 1printf(%d\n, sizeof(p[0]));// 1printf(%d\n, sizeof(p));// 4/8printf(%d\n, sizeof(p 1));// 4/8printf(%d\n, sizeof(p[0] 1));// 4/8printf(%d\n, strlen(p));//6printf(%d\n, strlen(p 1));//5//printf(%d\n, strlen(*p));//程序报错//printf(%d\n, strlen(p[0]));//程序报错printf(%d\n, strlen(p));//随机值printf(%d\n, strlen(p 1));//随机值printf(%d\n, strlen(p[0] 1));//5return 0;
} 10.指针笔试题
笔试题1
int main()
{int a[5] { 1, 2, 3, 4, 5 };int *ptr (int *)(a 1);printf( %d,%d, *(a 1), *(ptr - 1));return 0;
} 代码解析 a是数组名既没有sizeof(数组名)也没有数组名所以就表示数组首元素地址 *(a1)就表示数组第二个元素也就是2a取出整个数组的地址(a1)跳过一个数组再强转成一个int*类型因此ptr-1就指向数组倒数第一个元素*(ptr-1)就是5 笔试题2
//由于还没学习结构体这里告知结构体的大小是20个字节
struct Test
{int Num;char* pcName;short sDate;char cha[2];short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少
//已知结构体Test类型的变量大小是20个字节
int main()
{p 0x100000;printf(%p\n, p 0x1);printf(%p\n, (unsigned long)p 0x1);printf(%p\n, (unsigned int*)p 0x1);return 0;
} 题目解析 p是一个结构体指针1跳过一个结构体的大小因此(p1)跳过20个字节转换成16进制就是0x00000014(p0x1)就是00100014p被强转成无符号长整型1就是整型1因此((unsigned long)p0x1)就是00100001p被强转成无符号整型指针1跳过一个整型指针类型也就是4字节((unsigned int*)p0x1)就是00100004 笔试题3
int main()
{int a[4] { 1, 2, 3, 4 };int* ptr1 (int*)(a 1);int* ptr2 (int*)((int)a 1);printf(%x,%x, ptr1[-1], *ptr2);return 0;
} 题目解析 (a1)跳过数组再强转成整型ptr[-1]相当于*(ptr-1)答案是4a被强转成整型1就是数值1再被强转整型指针这里我们需要画出a数组的详细内存图 *ptr2就是图中的红色部分但内存中是以小端字节序存储的拿出来要还原因此答案就是02000000 笔试题4
int main()
{int a[3][2] { (0, 1), (2, 3), (4, 5) };int* p;p a[0];printf(%d, p[0]);return 0;
} 题目解析 需要注意数组的初始化中有()不要误以为这是在初始化数组()中是一个表达式其结果是最后一个表达式的结果因此(0,1)是1(2,3)是3(4,5)是5实际的数组中的数据 a[0]是数组首行的地址也是第一行的数组名数组名表示首元素的地址a[0]就是第一行第一个元素的地址p[0]相当于*(p0)答案是1 笔试题5
int main()
{int a[5][5];int(*p)[4];p a;printf( %p,%d\n, p[4][2] - a[4][2], p[4][2] - a[4][2]);return 0;
} 题目解析 这题需要我们画出数组内存图 (p[4][2]-a[4][2])是一个高地址-低地址得出的结果是-4 -4的补码是11111111 11111111 11111111 11111100表示成16进制就是FFFFFFFC 以%d打印就是-4 笔试题6
int main()
{int aa[2][5] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int *ptr1 (int *)(aa 1);int *ptr2 (int *)(*(aa 1));printf( %d,%d, *(ptr1 - 1), *(ptr2 - 1));return 0;
}代码解析 (ptr1-1)是数组倒数第一个元素的地址*(ptr1-1)就是10*(aa1)可以看成a[1]是第二行的数组名也就是第二行首元素的地址被强转成了int*因此(ptr2-1)是第一行倒数第一个元素的地址答案是5 笔试题7
int main()
{char* a[] { work,at,alibaba };char** pa a;pa;printf(%s\n, *pa);return 0;
} 题目解析 内存分布图 答案就是at 面试题8
int main()
{char* c[] { ENTER,NEW,POINT,FIRST };char** cp[] { c 3,c 2,c 1,c };char*** cpp cp;printf(%s\n, **cpp);printf(%s\n, *-- * cpp 3);printf(%s\n, *cpp[-2] 3);printf(%s\n, cpp[-1][-1] 1);return 0;
} 题目解析 内存分布图 需要注意会改变cpp的值 因此答案就是POINTERSTEW 关于指针的内容就讲到这