我的编程空间,编程开发者的网络收藏夹
学习永远不晚

掌握指针和数组:经典笔试题攻略(万字详解)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

掌握指针和数组:经典笔试题攻略(万字详解)

在这里插入图片描述

文章目录

前言

  • 当涉及到计算机编程的核心概念时,指针和数组无疑是最重要和基础的话题之一。无论你是初学者还是有经验的开发者,深入理解和掌握这两个概念都能让你的编程技能得到质的提升。
  • 在本篇博客中,我们将带你进入指针和数组的精彩世界,探索其在编程中的作用和应用。无论你是为了笔试准备,还是为了提升自己的技能,这里都将为你提供一个深入学习的机会。

在本篇文章中如有遇到不懂的知识点,可以参考以下文章《掌握指针进阶:探索字符指针、数组指针和指针数组的妙用》《掌握指针进阶:一篇带你玩转函数指针、函数指针数组及指向函数指针数组的指针!!》希望对你有所帮助

注意: 本次讲解是在vs2022 x86的环境下进行的,即电脑的32位环境,所以默认为指针大小占4个字节


📍指针和数组笔试题

🚀一维数组

//一维数组int a[] = { 1,2,3,4 };printf("%d\n", sizeof(a));printf("%d\n", sizeof(a + 0));printf("%d\n", sizeof(*a));printf("%d\n", sizeof(a + 1));printf("%d\n", sizeof(a[1]));printf("%d\n", sizeof(&a));printf("%d\n", sizeof(*&a));printf("%d\n", sizeof(&a + 1));printf("%d\n", sizeof(&a[0]));printf("%d\n", sizeof(&a[0] + 1));

以上语句输出的结果是什么?结果如下:

在这里插入图片描述

【解析】:

int main(){//一维数组int a[] = { 1,2,3,4 };//数组中有4个元素,每个元素的类型为int类型,所以数组所占字节大小为4*4=16printf("%d\n", sizeof(a));//sizeof里面的a表示的是整个数组,所以这里求的是整个数组的大小,即4*4=16printf("%d\n", sizeof(a + 0));//a+0 其实是下标为0的元素的地址(即数组第一个元素的地址),是地址就是4/8字节,这里是32位环境,所以大小是4个字节printf("%d\n", sizeof(*a));//*a是数组首元素,计算的是数组首元素的大小,单位是字节,a为int类型,所以大小为4个字节printf("%d\n", sizeof(a + 1));//a为首元素地址,+1表示下表为1的元素地址(即第二个元素的地址),地址大小为4个字节printf("%d\n", sizeof(a[1]));//a[1]表示第二个元素,计算的是第二个元素的大小,大小为4个字节printf("%d\n", sizeof(&a));//&a是整个数组的地址,整个数组的地址也是地址,地址的大小为4个字节//&a---> 类型:int(*)[4] (数组指针类型)printf("%d\n", sizeof(*&a));//&a是数组的地址,*&a就是拿到了数组,*&a --> a,a就是数组名,sizeof(*&a)-->sizeof(a)//计算的是整个数组的大小,单位是字节,即大小是4*4 = 16个字节printf("%d\n", sizeof(&a + 1));//&a是整个数组的地址,&a+1,跳过整个数组,指向数组后边的空间,是一个地址,大小是4个字节printf("%d\n", sizeof(&a[0]));//&a[0]是首元素的地址,计算的是首元素地址的大小,为4个字节printf("%d\n", sizeof(&a[0] + 1));//&a[0]表示第一个元素的地址,+1就是第二个元素的地址,地址的大小为4个字节return 0;}//sizeof 类型:----> size_t ----> unsigned int

这里我们需要知道:

1. sizeof(数组名),数组名表示整个数组。计算的是整个数组的大小,单位是字节。
2. &数组名,数组名表示整个数组。取出的是整个数组的地址,+1跳过的是整个数组。

  • 除此之外,所有的数组名都是数组首元素的地址

🚀字符指针

🍁sizeof()的计算

//字符数组 ---> sizeof()char arr[] = {'a','b','c','d','e','f'};printf("%d\n", sizeof(arr));printf("%d\n", sizeof(arr+0));printf("%d\n", sizeof(*arr));printf("%d\n", sizeof(arr[1]));printf("%d\n", sizeof(&arr));printf("%d\n", sizeof(&arr+1));printf("%d\n", sizeof(&arr[0]+1));

以上语句输出的结果是什么?结果如下:

在这里插入图片描述
【解析】:

int main(){char arr[] = { 'a','b','c','d','e','f' };printf("%d\n", sizeof(arr));//arr单独放在sizeof内部,计算的是整个数组的大小,单位是字节,所以大小为 6*1 = 6个字节printf("%d\n", sizeof(arr + 0));//arr表示首元素地址,+0表示下标为0的元素地址(即数组首元素的地址),大小为4个字节printf("%d\n", sizeof(*arr));//arr是数组的首元素的地址,*arr表示对arr解引用,得到字符'a',大小为1字节printf("%d\n", sizeof(arr[1]));//arr[1]是第二个元素,因为数组元素为char类型,所以大小为1字节printf("%d\n", sizeof(&arr));//&arr表示取出整个数组的地址,数组的地址也是地址,大小为4个字节printf("%d\n", sizeof(&arr + 1));//&arr表示取出整个数组的地址,+1表示跳过整个数组,指向数组后边空间(即'f'后面)的地址,大小为4个字节printf("%d\n", sizeof(&arr[0] + 1));//&arr[0] + 1表示数组第二个元素的地址,大小为4个字节return 0;}

注意: 如果 char arr[] = "abcdef"; 这里的arr数组有7个元素(加上一个’\0’),编译器会默认为arr数组末尾添加结束标志‘\0’,所以计算数组大小时结果不再是6而是7。

在这里插入图片描述


当使用指针存放字符串又会怎样?

char *p = "abcdef";printf("%d\n", sizeof(p));printf("%d\n", sizeof(p+1));printf("%d\n", sizeof(*p));printf("%d\n", sizeof(p[0]));printf("%d\n", sizeof(&p));printf("%d\n", sizeof(&p+1));printf("%d\n", sizeof(&p[0]+1));

以上语句输出的结果是什么?结果如下:

在这里插入图片描述
【解析】:

int main(){char* p = "abcdef";printf("%d\n", sizeof(p));//p是存放字符串"abcdef"的指针变量,是指针,所以大小为4个字节printf("%d\n", sizeof(p + 1));//p表示首元素的地址,+1表示下表为1的元素的地址(即b的地址),大小为4个字节printf("%d\n", sizeof(*p));//p表示首元素的地址,对p解引用,*p就是字符'a',sizeof(*p)计算的是字符的大小,是1个字节printf("%d\n", sizeof(p[0]));//p[0]-->*(p+0) --> *p  表示第一个元素'a',大小是1个字节printf("%d\n", sizeof(&p));//&p是二级指针,是指针大小为4个字节printf("%d\n", sizeof(&p + 1)); //&p是二级指针,+1跳过的是p变量后(即指针大小为4个字节)的地址,因为还是指针,所以大小为4个字节printf("%d\n", sizeof(&p[0] + 1));//p[0]就是‘a’,&p[0]就是a的地址,+1,就是b的地址,是地址大小为4个字节return 0;}

🍁strlen的计算

//size_t strlen(const char* str)//strlen返回类型为size_t ----> unsigned intchar arr[] = { 'a','b','c','d','e','f' };printf("%d\n", strlen(arr));printf("%d\n", strlen(arr + 0));//printf("%d\n", strlen(*arr));//printf("%d\n", strlen(arr[1]));printf("%d\n", strlen(&arr));printf("%d\n", strlen(&arr + 1));printf("%d\n", strlen(&arr[0] + 1));

输出结果如下:

【解析】:

int main(){//size_t strlen(const char* str)//strlen返回类型为size_t ----> unsigned intchar arr[] = { 'a','b','c','d','e','f' };printf("%d\n", strlen(arr));//strlen统计字符串长度时直到遇到 '\0'才停止,但是在初始化arr时我们没有加上'\0',//即在arr数组中我们不知道'\0'的位置,所以这里计算的结果是随机值printf("%d\n", strlen(arr + 0));//这里计算的是从下标为0的元素位置开始计算字符串长度,由于无法得知结束标志'\0'的位置,所以结果同上,为随机值//printf("%d\n", strlen(*arr)); ---> //strlen需要接收的是一个地址,strlen('a') -> strlen(97),非法访问 - error//printf("%d\n", strlen(arr[1])); ---> //'b'->98,和上面的代码类似,是非法访问 - errorprintf("%d\n", strlen(&arr));//&arr虽然是整个数组的地址,但是也是从数组起始位置开始的,计算的结果同第一个一样还是随机值//&arr类型 ---> char(*)[6](数组指针类型)printf("%d\n", strlen(&arr + 1));//&arr是整个数组的地址,&arr+1是跳过整个数组的地址即'f'后面的地址,计算的是'f'后面的字符串长度,//结果也是随即值,但是这个随机值比第一个少6,少的是字符串"abcdef"printf("%d\n", strlen(&arr[0] + 1));//&arr[0]表示的是第一个元素的地址, + 1表示第二个元素的地址,是'b'的地址,计算的是从'b'开始的字符串的长度,//结果也是随机值,但是这个随机值比第一个少1,少的是字符'a'return 0;}

char arr[] = "abcdef";printf("%d\n", strlen(arr));printf("%d\n", strlen(arr + 0));//printf("%d\n", strlen(*arr));//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";//数组是7个元素//[a b c d e f \0]printf("%d\n", strlen(arr));//arr是数组首元素的地址,strlen从首元素的地址开始统计'\0'之前出现的字符个数,结果是6printf("%d\n", strlen(arr + 0));//arr + 0是数组首元素的地址,同第一个,结果是6//printf("%d\n", strlen(*arr));//*arr是'a',ASC II码值是97,传给strlen是一个非法的地址,造成非法访问//printf("%d\n", strlen(arr[1]));//'b' --> 98 ,同上printf("%d\n", strlen(&arr));//&arr虽然是整个数组的地址,但是也是从数组起始位置开始的,计算结果同第一个是6printf("%d\n", strlen(&arr + 1));//&arr + 1是跳过整个数组后的地址,统计字符串的长度是随机值printf("%d\n", strlen(&arr[0] + 1));//&arr[0]+1是b的地址,从第二个字符往后统计字符串的长度,大小是5return 0;}

char* p = "abcdef";printf("%d\n", strlen(p));printf("%d\n", strlen(p + 1));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));

输出结果如下:

在这里插入图片描述

【解析】:

int main(){char* p = "abcdef";printf("%d\n", strlen(p));//6- 求字符串长度printf("%d\n", strlen(p + 1));//p + 1是b的地址,求字符串长度就是5//printf("%d\n", strlen(*p));//error,*p是'a'//printf("%d\n", strlen(p[0]));//error --> 同上一个printf("%d\n", strlen(&p));//&p拿到的是p这个指针变量的起始地址,从这里开始求字符串长度完全是随机值printf("%d\n", strlen(&p + 1));//&p+1是跳过p变量的地址,从这里开始求字符串长度也是随机值printf("%d\n", strlen(&p[0] + 1));//&p[0]表示'a'的地址, + 1是b的地址,从b的地址向后数字符串的长度是5return 0;}

🍁总结

  • sizeof 只关注占用内存空间的大小,单位是字节,不关心内存中存放的是什么
    sizeof 操作符
  • strlen是求字符串长度的,统计的是\0之前出现的字符个数,一定要找到 ‘\0’ 才算结束,所以可能存在越界访问的
    strlen库函数

🚀二维数组

//二维数组int a[3][4] = {0};printf("%d\n",sizeof(a));printf("%d\n",sizeof(a[0][0]));printf("%d\n",sizeof(a[0]));printf("%d\n",sizeof(a[0]+1));printf("%d\n",sizeof(*(a[0]+1)));printf("%d\n",sizeof(a+1));printf("%d\n",sizeof(*(a+1)));printf("%d\n",sizeof(&a[0]+1));printf("%d\n",sizeof(*(&a[0]+1)));printf("%d\n",sizeof(*a));printf("%d\n",sizeof(a[3]));

以上语句输出的结果是什么?结果如下:

在这里插入图片描述

【解析】:

int main(){//二维数组int a[3][4] = { 0 };printf("%d\n", sizeof(a));//数组名单独放在sizeof内部,a表示整个数组的地址,计算的是整个数组的大小,整个数组有3*4=12个元素,//每个元素为int类型,所以计算的大小为 3*4*4 = 12*4 = 48个字节printf("%d\n", sizeof(a[0][0]));//a[0][0]表示第一行第一列的元素(即数组首元素),大小为4个字节printf("%d\n", sizeof(a[0]));//a[0]是二维数组第一行的数组名,数组名单独放在sizeof内部,计算的就是数组(第一行)的大小,为4*4 = 16个字节printf("%d\n", sizeof(a[0] + 1));//a[0]作为第一行的数组名,没有单独放在sizeof内部,没有取地址,表示的就是数组首元素的地址//那就是a[0][0]的地址,a[0]+1就是第一行第二个元素的地址,是地址,计算的大小就是4个字节printf("%d\n", sizeof(*(a[0] + 1)));//a[0] + 1表示的是第一行第二个元素的地址,对其解引用,*(a[0] + 1)就是是第一行第二个元素,计算的是元素的大小,为 4个字节printf("%d\n", sizeof(a + 1));//a是二维数组的数组名,数组名表示首元素的地址,就是第一行的地址,a+1就是第二行的地址//第二行的地址也是地址,是地址,计算的大小就是4个字节   //a 类型: --> int (*)[4](数组指针类型)//a+1 类型: --> int(*)[4](数组指针类型)printf("%d\n", sizeof(*(a + 1)));//a+1是第二行的地址,对其解引用,*(a+1)表示的就是第二行,*(a+1) --> a[1]//因为第二行有4个元素,每个元素为int类型,所以计算大小为 4*4 =16个字节printf("%d\n", sizeof(&a[0] + 1));//&a[0]是第一行的地址,&a[0]+1就是第二行的地址,是地址,大小就是4个字节printf("%d\n", sizeof(*(&a[0] + 1)));//*(&a[0] + 1) 是对第二行的地址解引用,得到的就是第二行,计算的就是第二行的大小,为4*4 = 16个字节 printf("%d\n", sizeof(*a));//a表示首元素的地址,就是第一行的地址,*a就是第一行,计算的就是第一行的大小,为 4*4 = 16个字节//*a --> *(a+0) --> a[0]printf("%d\n", sizeof(a[3]));//结果是16个字节 <-- int[4]//如果数组存在第四行,a[3]就是第四行的数组名,数组名单独放在sizeof内部,计算的是第四行的大小,为 4*4 =16个字节return 0;}

📍指针笔试题

🚀笔试题1:

int main(){    int a[5] = { 1, 2, 3, 4, 5 };    int *ptr = (int *)(&a + 1);    printf( "%d,%d\n", *(a + 1), *(ptr - 1));    return 0;}//程序的结果是什么?

输出结果如下:

在这里插入图片描述

【解析】:

  1. int a[5] = { 1, 2, 3, 4, 5 };: 这行代码定义了一个包含5个整数的整型数组,初始化为从1到5的连续整数。
  2. int* ptr = (int*)(&a + 1);:&a表示的是整个数组的地址,+1跳过整个数组,指向数组末尾后的地址(此时是int()a[5]类型),(int)表示的是将此地址强制转换成 int* 类型,所以这行代码将一个指向整型的指针ptr指向数组a之后的内存位置,也就是数组的末尾之后的位置。
  3. *(a + 1)a表示数组首元素的地址,+1表示下标为1的元素的地址(即第二个元素的地址),对其解引用,*(a+1)表示第二个元素,即2。
  4. *(ptr - 1)ptr表示的是5后面的地址,-1就表示在该地址的条件下向前移动一个位置,即指向5的地址,对其解引用就得到元素5。

🚀笔试题2:

//由于还没学习结构体,这里告知结构体的大小是20个字节struct Test{ int Num; char *pcName; short sDate; char cha[2]; short sBa[4];}*p;//假设p 的值为0x100000。 如下表表达式的值分别为多少?//已知,结构体Test类型的变量大小是20个字节int main(){ printf("%p\n", p + 0x1); printf("%p\n", (unsigned long)p + 0x1); printf("%p\n", (unsigned int*)p + 0x1); return 0;}

输出结果如下:

在这里插入图片描述

【解析】:

在给定的代码中,有一个名为struct Test的结构体类型,大小为20个字节。变量p是一个指向这种结构体类型的指针,并被赋值为0x100000。

根据C语言中的指针算术规则,指针在增加时会根据所指向类型的大小进行适当的偏移。

  1. printf("%p\n", p + 0x1); 因为p是结构体指针类型,所以这里的表达式p + 0x1会将指针p增加一个结构体的大小,即20个字节(20的16进制为0x14)。故结果将是:0x100014

  2. printf("%p\n", (unsigned long)p + 0x1); 在这个表达式中,将指针p先转换为unsigned long类型,这时原来的结构体指针p就变成了unsigned long类型的数组,加上0x1,就是单纯的将0x100000加上0x1。所以结果将是:0x100001

  3. printf("%p\n", (unsigned int*)p + 0x1); 这个表达式中,将指针p转换为unsigned int*类型,然后增加0x1。因为unsigned int*大小是4个字节,所以增加1个字节相当于增加0x4。故结果将是:0x100004

需要注意的是,指针的算术运算会根据指针指向的类型来调整偏移量,这取决于所使用的编译器和系统架构。此外,将指针转换为不同类型可能会引起对齐和字节顺序等问题,因此需要谨慎使用。


🚀笔试题3:

int main(){    int a[4] = { 1, 2, 3, 4 };    int *ptr1 = (int *)(&a + 1);    int *ptr2 = (int *)((int)a + 1);    printf( "%x,%x\n", ptr1[-1], *ptr2);    return 0;}

输出结果如下:

在这里插入图片描述

【解析】:

  1. int a[4] = { 1, 2, 3, 4 }; 这行代码定义了一个包含4个整数的数组,初始化为 1, 2, 3, 和 4。

  2. int* ptr1 = (int*)(&a + 1); 这里取数组a的地址,表示整个数组的地址,加1,跳过了4个整型的大小,然后将结果转换为int*类型的指针。这使得ptr1指向数组a之后的内存位置(即4后面的地址)。

  3. int* ptr2 = (int*)((int)a + 1); 这里将数组a的值(即数组的第一个元素的地址)转换为int类型,然后加1(注意如果没有转换为int类型,就是指针+1,实际上加了4个字节),最后将结果转换为int*类型的指针。这使得ptr2指向数组a的第一个元素之后的内存位置。

  4. printf("%x,%x\n", ptr1[-1], *ptr2); 这里使用指针ptr1访问了其前一个位置的值(即数组a的最后一个元素),并将它以十六进制格式打印出来。然后,使用指针ptr2访问了其所指向位置的值(即数组a的第二个元素),并同样以十六进制格式打印出来。

由于ptr1指向数组a之后的位置,而ptr2指向数组a的第一个元素之后的位置,它们访问的内存位置是不同的。然而,数组的元素在内存中是连续存储的,因此最终输出的结果将受到内存布局的影响。

在这里插入图片描述


🚀笔试题4:

#include int main(){    int a[3][2] = { (0, 1), (2, 3), (4, 5) };    int *p;    p = a[0];    printf( "%d\n", p[0]); return 0;}

输出结果如下:

在这里插入图片描述

【解析】:

在这段代码中,数组a是一个3x2的二维数组,每个元素都是一个包含两个整数的小数组。

  1. int a[3][2] = { (0, 1), (2, 3), (4, 5) }; 这里使用逗号运算符初始化二维数组a的元素。逗号运算符的结果是它的最后一个表达式的值,因此实际上是初始化了数组a的元素为 {1,3, 5},而0, 2, 4被忽略了。所以,a的内容实际上是 {1, 3}, {5, 0}, {2, 4}

  2. int* p; 这里声明了一个指向整数的指针p

  3. p = a[0]; 这里将指针p指向数组a的第一个元素,即{1, 3}的首地址。

  4. printf("%d\n", p[0]); 这里通过指针p访问了其第一个元素,即数组a的第一个元素的第一个整数元素,即1。然后将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;}

输出结果如下:

在这里插入图片描述

【解析】:

  1. int a[5][5]; 这行代码定义了一个5x5的二维整数数组。

  2. int(*p)[4]; 这里定义了一个指向包含4个整数的数组的指针。

  3. p = a; 这里将指针p指向数组a的第一个子数组,即a[0](二维数组的第一行地址)。

  4. printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]); 这行代码计算了两个地址之间的偏移量,并打印出结果。

现在我们来计算偏移量:

  • &p[4][2] 表示指针p指向的数组的第5个子数组(即第五行的元素),然后取其中的第3个整数元素的地址。

  • &a[4][2] 表示数组a的最后一行的第3个元素的地址。

因此,表达式 &p[4][2] - &a[4][2] 会计算两个指针之间的偏移量,这是一个指针运算,计算的结果将是两个指针相差的数组元素个数。在这个特定的情况下,由于p指向的数组每行有4个元素,所以&p[4][2]会在&a[4][2]前面,如图,&p[4][2]&a[4][2]之间有四个元素,因此这个计算结果将是-4。 而%p是以16进制的形式打印其补码(因为数据在内存中存储是以补码的形式存储的,所以打印的时候也是打印补码),-4的原、反、补码如下;:
10000000 00000000 00000000 00000100
111111111 111111111 111111111 111111011
111111111 111111111 111111111 111111100
故其补码的16进制形式为 FFFFFFFC

在这里插入图片描述


🚀笔试题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\n", *(ptr1 - 1), *(ptr2 - 1));    return 0;}

输出结果如下:

在这里插入图片描述

【解析】:

  1. int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 这行代码定义了一个2x5的二维整数数组,并用初始化值填充它。

  2. int* ptr1 = (int*)(&aa + 1); 这里取数组aa的地址,去出的是整个二维数组的地址,加1,跳过整个二维数组,指向二维数组末尾后面的地址,然后将结果转换为int*类型的指针。这将使得ptr1指向数组aa之后的内存位置(即10后面的地址)。

  3. int* ptr2 = (int*)(*(aa + 1)); 这里aa表示的是二维数组首元素的地址(即第一行的地址),+1跳过一行元素,指向第二行的地址,然后对其解引用得到第二行第一个元素的地址,最后将结果转换为int*类型的指针。这将使得ptr2指向第二行的起始位置。

  4. printf("%d,%d\n", *(ptr1 - 1), *(ptr2 - 1)); 这里使用指针算术访问了指针ptr1的前一个位置的值(即数组aa的最后一个元素),并将它打印出来。然后,使用指针算术访问了指针ptr2的前一个位置的值(即第二行的最后一个元素),并将它打印出来。

注意:ptr1 指向整个二维数组 aa 之后的位置,而 ptr2 指向第二行的起始位置,它们访问的内存位置是不同的。

在这里插入图片描述


🚀笔试题7:

#include int main(){ char *a[] = {"work","at","alibaba"}; char**pa = a; pa++; printf("%s\n", *pa); return 0;}

输出结果如下:

在这里插入图片描述

【解析】:

  1. char *a[] = {"work","at","alibaba"};
    这行代码定义了一个字符指针数组 a,其中每个元素是一个指向字符串常量的指针。数组中有三个元素,分别指向字符串 “work”、“at” 和 “alibaba”。

  2. char**pa = a;
    这里定义了一个指向字符指针的指针 pa,将其指向数组 a 的第一个元素,即指向字符串 “work” 的指针。

  3. pa++;
    这里将指针 pa 增加了一次,使其指向数组 a 的下一个元素,即指向字符串 “at” 的指针。

  4. printf("%s\n", *pa);
    这里通过指针 pa 访问了其所指向的字符串(这里*pa表示的是字符串"at"的地址),然后使用 %s 格式化输出该字符串。


🚀笔试题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;}

输出结果如下:

在这里插入图片描述

【解析】:

这段代码涉及指针和指针数组的操作,有点复杂,让我们逐行解释:

  1. char* c[] = { "ENTER","NEW","POINT","FIRST" };
    这行代码定义了一个字符指针数组 c,其中每个元素是一个指向字符串常量的指针。数组中有四个元素,分别指向字符串 “ENTER”、“NEW”、“POINT” 和 “FIRST”。

  2. char** cp[] = { c + 3,c + 2,c + 1,c };
    这里定义了一个指向字符指针的指针数组 cp,其中每个元素是一个指向数组 c 中的某个元素的指针。c + 3 表示指向 “FIRST” 的指针,c + 2 表示指向 “POINT” 的指针,以此类推。

  3. char*** cpp = cp;
    这里定义了一个指向指针数组 cp 的指针 cpp
    在这里插入图片描述

  4. printf("%s\n", **++cpp);
    这里首先将指针 cpp 增加了一次,然后通过 ** 解引用两次得到 “POINT” 的字符串,然后输出。
    在这里插入图片描述

  5. printf("%s\n", *-- * ++cpp + 3);
    这里先将指针 cpp 增加一次,然后将其解引用得到指向 “NEW” 的指针。接着,*-- * ++cpp 操作会将 *++cpp 减少一次,然后将其解引用,得到字符串"ENTER" 的地址。最终, + 3 操作将 “ENTER” 的字符串地址向后偏移3,得到字符串 “ER”,然后输出。
    在这里插入图片描述

  6. printf("%s\n", *cpp[-2] + 3);
    这里使用指针数组的索引操作,首先cpp[-2] 得到指向字符串 “FIRST” 的指针,然后对其解引用,得到字符串"FIRST"的地址,最终+ 3 将 “FIRST” 的字符串地址向后偏移3,得到字符串 “ST”,然后输出。
    在这里插入图片描述

  7. printf("%s\n", cpp[-1][-1] + 1);
    这里 cpp[-1] 得到指向 “POINT” 的指针,然后 cpp[-1][-1] 得到 “NEW” 的字符串指针(地址),然后 + 1 将字符串地址向后偏移1,得到字符串 “EW”,然后输出。
    在这里插入图片描述

💥小结:

理解和掌握指针和数组的概念是编程中的关键。通过练习和实践,你将能够更好地处理与指针和数组相关的问题。遇到困难并不是失败,而是在通向成功的道路上的一部分。每次犯错,你都在学习如何做得更好。我们一起加油!!✨☄

🔥今天的分享就到这里了, 如果觉得博主的文章还不错的话, 请👍三连支持一下博主哦🤞

在这里插入图片描述

来源地址:https://blog.csdn.net/2201_75743654/article/details/132384114

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

掌握指针和数组:经典笔试题攻略(万字详解)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录