本章重点
9.指针和数组面试题的解析
10. 指针笔试题
九、指针和数组面试题的解析
1、一维数组的sizeof
#include<stdio.h>
int main()
{
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));
return 0;
}
数组名就是数组首元素的地址
两个特殊情况:
1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址
printf("%d\n", sizeof(a));
特殊情况1,计算整个数组的大小,4 * 4 = 16
printf("%d\n", sizeof(a + 0));
数组名不是单独出现,a/(a + 0)表示数组首元素的地址,地址就是指针,4/8
printf("%d\n", sizeof(*a));
数组名不是单独出现,*a表示数组首元素,首元素类型是整型,4
printf("%d\n", sizeof(a + 1));
数组名不是单独出现,a表示数组首元素地址,a + 1第二个元素的地址,4/8
printf("%d\n", sizeof(a[1]));
a[1]表示数组的第二个元素,该元素的数据类型是整型,4
printf("%d\n", sizeof(&a));
特殊情况2,数组名表示整个数组,取出的是整个数组的地址,地址是指针,4/8
printf("%d\n", sizeof(*&a));
解法一:sizeof(*&a) <==> sizeof(a),16
解法二:&a -> int(*p)[4]数组指针 - 解引用*访问的就是数组,16
printf("%d\n", sizeof(&a + 1));
&a取出的是整个数组的地址,&a+1是跳过这个数组的地址,地址是指针,4/8
printf("%d\n", sizeof(&a[0]));
&a[0])获取的是数组首元素的地址,地址是指针,4/8
printf("%d\n", sizeof(&a[0] + 1));
&a[0])获取的是数组首元素的地址,&a[0] + 1获取的是数组第二元素的地址,地址是指针,4/8
代码图解
运行结果
2、字符数组的sizeof和strlen
#include<stdio.h>
#include<string.h>
int main()
{
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));
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;
}
数组名就是数组首元素的地址
两个特殊情况:
1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址
printf("%d\n", sizeof(arr));
数组名单独放在sizeof内部,arr表示整个数组,计算整个数组的大小,6 * sizeof(char) = 6
printf("%d\n", sizeof(arr + 0));
数组名不是单独出现,arr/(arr + 0)表示数组首元素的地址,地址就是指针,4/8
printf("%d\n", sizeof(*arr));
数组名不是单独出现,*arr表示数组首元素,首元素类型是字符型,1
printf("%d\n", sizeof(arr[1]));
arr[1]表示第二个字符,数据类型是字符型,1
printf("%d\n", sizeof(&arr));
数组名表示整个数组,&arr取出的是整个数组的地址,地址是指针,4/8
printf("%d\n", sizeof(&arr + 1));
&arr取出的是整个数组的地址,&arr+1是跳过这个数组的地址,地址是指针,4/8
printf("%d\n", sizeof(&arr[0] + 1));
&arr[0]是取出第一个字符的地址,&arr[0]+1是取出第二个字符的地址,地址就是指针,4/8
strlen统计的是在字符串中\0之前的字符的个数,如果没有\0,就会一直往后找
printf("%d\n", strlen(arr));
字符数组arr中没有\0,所以求字符串长度就会一直往后找,随机值
printf("%d\n", strlen(arr + 0));
arr+0是首元素的地址,字符数组arr中没有\0,所以求字符串长度就会一直往后找,随机值
printf("%d\n", strlen(*arr));
strlen(参数是地址),*arr是首元素-'a'-对应的ASCII码值为97,把97当作地址,非法访问,error
printf("%d\n", strlen(arr[1]));
arr[1] - 'b' - 对应的ASCII码值为98,把98当作地址传参,非法访问,error
printf("%d\n", strlen(&arr));
&arr取出的是整个数组的地址,&arr的类型数组指针char(*)[6]
strlen(const char *str)类型是字符指针,此时会发生数组指针转为字符指针的一个过程
传过去的值不会发生改变,只是类型发生改变
数组的地址和首元素的地址是一样滴,传递给strlen函数后,依然是从数组的第一个元素的位置寻找\0,所以大小仍然是随机值
printf("%d\n", strlen(&arr + 1));
&arr+1是跳过这个数组的地址,从数组的第七个元素的位置寻找\0,随机值,比strlen(&arr)小6
printf("%d\n", strlen(&arr[0] + 1));
&arr[0]+1是取出第二个字符的地址,从数组的第二个元素的位置寻找\0,随机值,比strlen(&arr)小1
代码图解
运行结果:
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abcdef";
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));
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;
}
数组名就是数组首元素的地址
两个特殊情况:
1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址char arr[] = "abcdef";//这种写法数组的内容是[a b c d e f \0]
printf("%d\n", sizeof(arr));
数组名单独放在sizeof内部,arr表示整个数组,计算整个数组的大小,7 * sizeof(char) = 7
printf("%d\n", sizeof(arr + 0));
数组名不是单独出现,arr/(arr + 0)表示数组首元素的地址,地址就是指针,4/8
printf("%d\n", sizeof(*arr));
数组名不是单独出现,*arr表示数组首元素,首元素类型是字符型,1
printf("%d\n", sizeof(arr[1]));
arr[1]表示第二个字符,数据类型是字符型,1
printf("%d\n", sizeof(&arr));
数组名表示整个数组,&arr取出的是整个数组的地址,地址是指针,4/8
printf("%d\n", sizeof(&arr + 1));
&arr取出的是整个数组的地址,&arr+1是跳过这个数组的地址,地址是指针,4/8
printf("%d\n", sizeof(&arr[0] + 1));
&arr[0]是取出第一个字符的地址,&arr[0]+1是取出第二个字符的地址,地址就是指针,4/8
strlen统计的是在字符串中\0之前的字符的个数,如果没有\0,就会一直往后找
printf("%d\n", strlen(arr));
字符数组arr中有\0,字符串长度是\0之前的字符,不包括\0,6
printf("%d\n", strlen(arr + 0));
arr+0是首元素的地址,字符数组arr中有\0,字符串长度是\0之前的字符,不包括\0,6
printf("%d\n", strlen(*arr));
strlen(参数是地址),*arr是首元素-'a'-对应的ASCII码值为97,把97当作地址,非法访问,error
printf("%d\n", strlen(arr[1]));
arr[1] - 'b' - 对应的ASCII码值为98,把98当作地址传参,非法访问,error
printf("%d\n", strlen(&arr));
&arr取出的是整个数组的地址,&arr的类型数组指针char(*)[6]
strlen(const char *str)类型是字符指针,此时会发生数组指针转为字符指针的一个过程
传过去的值不会发生改变,只是类型发生改变
数组的地址和首元素的地址是一样滴,传递给strlen函数后,依然是从数组的第一个元素的位置寻找\0,字符数组arr中有\0,字符串长度是\0之前的字符,不包括\0,6
printf("%d\n", strlen(&arr + 1));
&arr+1是跳过这个数组的地址,从数组的第八个元素的位置寻找\0,随机值
printf("%d\n", strlen(&arr[0] + 1));
&arr[0]+1是取出第二个字符的地址,从数组的第二个元素的位置寻找\0,5
代码图解:
运行结果:
#include<stdio.h>
int main()
{
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));
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));
return 0;
}
数组名就是数组首元素的地址
两个特殊情况:
1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址"abcdef" - 常量字符串 - [a,b,c,d,e,f,\0]
char* p = "abcdef";//这里指针变量p存放的是'a'的地址
printf("%d\n", sizeof(p));
p是一个指针变量,4/8
printf("%d\n", sizeof(p + 1));
p+1是第二个字符'b'的地址,地址就是指针,4/8
printf("%d\n", sizeof(*p));
*p就是字符'a',字符'a'的数据类型是char,sizeof(char), 1
printf("%d\n", sizeof(p[0]));
p[0]就是字符'a',字符'a'的数据类型是charsizeof(char), 1
printf("%d\n", sizeof(&p));
p是指针变量,&p就是二级指针,同样是地址,4/8
printf("%d\n", sizeof(&p + 1));
p是指针变量,&p就是二级指针,&p+1就是跳过这个二级指针变量,同样是地址,4/8
printf("%d\n", sizeof(&p[0] + 1));
&p[0]就是取字符'a'的地址,&p[0]+1就是第二个字符'b'的地址,地址就是指针,4/8
printf("%d\n", strlen(p));
常量字符串中有\0,字符串长度是\0之前的字符,不包括\0,6
printf("%d\n", strlen(p + 1));
p+1就是字符'b'的地址, 从常量字符串的第二个元素的位置寻找\0,5
printf("%d\n", strlen(*p));
*p就是字符'a'-对应的ASCII码值为97,把97当作地址,非法访问,error
printf("%d\n", strlen(p[0]));
p[0]就是字符'a'-对应的ASCII码值为97,把97当作地址,非法访问,error
printf("%d\n", strlen(&p));
&p是二级指针,存放的是指针变量p的地址,不知道\0的位置,随机值
printf("%d\n", strlen(&p + 1));
&p+1是跳过这个二级指针变量,不知道\0的位置,随机值
printf("%d\n", strlen(&p[0] + 1))
&p[0]+1就是第二个字符'b'的地址,从常量字符串的第二个元素的位置寻找\0,5
代码图解:
运行结果:
3、二维数组的sizeof
#include<stdio.h>
int main()
{
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]));
return 0;
}
printf("%d\n", sizeof(a));
数组名单独放在sizeof内部,a表示整个数组,计算整个数组的大小,12*sizeof(int)=48
printf("%d\n", sizeof(a[0][0]));
a[0][0]表示第一行第一列的数据,数据类型是整型,4
printf("%d\n", sizeof(a[0]));
表示二维数组的第一行元素,该行有4个元素,可以当作一个一维数组存放四个数据,a[0]是第一行这个一维数组的数组名,数组名单独出现,计算的是整个数组的大小,16
printf("%d\n", sizeof(a[0] + 1));
a[0]是第一行这个一维数组的数组名,数组名不单独出现,a[0]表示第一行数组的首元素地址,也就是a[0][0]的地址,所以a[0]+1是第一行第二个元素的地址,4/8
printf("%d\n", sizeof(*(a[0] + 1)));
a[0]+1是第一行第二个元素的地址,解引用就是a[0][1],数据类型是整型,4
printf("%d\n", sizeof(a + 1));
a是这个二维数组的数组名,数组名不单独出现,a表示这个二维数组的首元素地址,a+1就表示第二行这个一维数组的地址,4/8
printf("%d\n", sizeof(*(a + 1)));
*(a + 1)) <==> a[1],表示二维数组的第二行元素,该行有4个元素,可以当作一个一维数组存放四个数据,a[1]是第二行这个一维数组的数组名,数组名单独出现,计算的是整个数组的大小,16
printf("%d\n", sizeof(&a[0] + 1));
&a[0]表示取出第一行一维数组的地址,&a[0]+1就表示第二行这个一维数组的地址,4/8
printf("%d\n", sizeof(*(&a[0] + 1)));
*(&a[0] + 1) <==> *(a+1) <==> a[1],16
printf("%d\n", sizeof(*a));
数组名不单独出现,a表示首元素地址,也就是第一行的地址,*a <==> *(a+0) <==> a[0],16
printf("%d\n", sizeof(a[3]));
越界,但是sizeof并不会访问内存,a[3] <==> a[2] <==> a[1] <==> a[0],1
代码图解:
运行结果:
上面的sizeof(a[3])越界了,但是程序依然没报错,依然可以运行,为什么呢?
一个程序需要经过编译+链接->可执行程序->运行,sizeof不访问内存,在编译期间就已经执行了,而b = a + 1是在运行期间执行的。
总结: 数组名的意义:
- sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
- &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
- 除此之外所有的数组名都表示首元素的地址。
10、指针笔试题
demo1:
#include<stdio.h>
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int* ptr = (int*)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
//程序的结果是什么?
int a[5] = { 1, 2, 3, 4, 5 };
定义了一个整数数组a
,并初始化其元素为 1、2、3、4 和 5。
int* ptr = (int*)(&a + 1);
定义了一个指针ptr
,它指向数组a
的后一个位置。在这里,&a
获取整个数组的地址,然后+1
使指针指向下一个内存位置,即数组末尾后面的位置。
printf("%d,%d", *(a + 1), *(ptr - 1));
a是数组名,数组名不单独出现,a表示数组首元素的地址,a+1表示第二个元素的地址,*(a + 1)表示第二个元素,prt是int* 类型,此时表示跳过整个数组的地址,ptr - 1就指向了数组的第五个元素的地址,*(ptr - 1)就是5程序的结果是什么?2,5
demo2:
#include<stdio.h>
//由于还没学习结构体,这里告知结构体的大小是20个字节
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}*p = (struct Test*)0x100000;
//假设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;
//程序的结果是什么?
}
printf("%p\n", p + 0x1);
这里对指针p
进行加法操作,p + 0x1
实际上是将指针p
往后移动了一个结构体Test
的大小(20个字节),所以结果为0x100000 + 0x14 = 0x100014
。
printf("%p\n", (unsigned long)p + 0x1);
这里强制将指针p
转换为无符号长整型后再进行加法操作,即对数值进行计算,0x100000 + 0x1 = 0x100001
。
printf("%p\n", (unsigned int*)p + 0x1);
这里强制将指针p
转换为整型指针后再进行加法操作,整型指针的大小是4个字节,所以在进行加法操作时会跳过4个字节,即0x100000 + 0x4 = 0x100004
。程序的结果是什么?0x10014,0x10001,0x10004
demo3:
#include<stdio.h>
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;
//程序的结果是什么?
}
代码图解:
int* ptr1 = (int*)(&a + 1);
定义了一个指针ptr1
,它指向数组a
后一个位置。在这里,&a
获取整个数组的地址,然后+1
使指针指向下一个整数数组,即在数组a
之后的位置。
int* ptr2 = (int*)((int)a + 1);
这一行定义了一个指针ptr2
,它指向数组a
的首地址后一个字节的位置。在这里,(int)a
将数组a
的首地址转换为整数类型,然后+1
使指针指向首地址后一个字节的位置。让我们来计算这两个值的具体结果:
ptr1[-1]
:ptr1
指向了数组a
后面的位置,而ptr1[-1]
<==> *(ptr1-1),也就是从数组的
后面的位置减1,由于ptr1的类型是指针类型,-1操作的步长是所指向数据类型,也就是sizeof(int)4个字节,指向元素3的位置。
*ptr2
:ptr2
指向数组a
的首地址后一个字节的位置,所以*ptr2
取出了元素1的00 00 00三个字节,取出来元素2的02字节,00 00 00 02,由于是小端存储,实际数据是0x02 00 00 00.程序的结果是什么?4,2000000
demo4:
#include<stdio.h>
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int* p;
p = a[0];
printf("%d", p[0]);
return 0;
//程序的结果是什么?
}
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
这一行定义了一个二维整数数组a
,其中有 3 行 2 列,每个元素被初始化为(0, 1)
、(2, 3)
和(4, 5)
。请注意,(0, 1)
、(2, 3)
和(4, 5)
都是逗号运算符的结果,实际上只有后面的值(1, 3, 5)
会被用于初始化。
int* p;
这一行定义了一个整型指针p
。
p = a[0];
这里将指针p
指向二维数组a
的第一行的首地址,即数组a[0]
的首地址。
printf("%d", p[0]);
这一行使用printf
函数打印p[0]
的值。由于p
指向了数组a[0]
的首地址,所以p[0]
相当于访问了数组a[0]
的第一个元素,即(1, 3, 5)
中的第一个元素,也就是 1程序的结果是什么?1
demo5:
#include<stdio.h>
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;
//程序的结果是什么?
}
代码图解
int a[5][5];
定义了一个二维整数数组a
,有 5 行 5 列。由于没有初始化,数组a
的元素值是未定义的。
int(*p)[4];
定义了一个指向包含 4 个整数的一维数组的指针p
。
p = a;
这里将指针p
指向二维数组a
的第一行的首地址,即数组a[0]
的首地址。
&p[4][2] - &a[4][2]
:这一表达式用来计算&p[4][2]
与&a[4][2]
之间的距离,也就是这两个地址之间相差的元素个数。
&p[4][2] - &a[4][2]
:&p[4][2]
为指针p
所指向的位置的第 4 行第 2 列的元素地址,而&a[4][2]
为数组a
的第 4 行第 2 列的元素地址。这两个地址之间相差 4 个int
类型的元素,因为p
指向的一维数组有 4 个元素。程序的结果是什么?FFFFFFFC,-4
demo6:
#include<stdio.h>
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;
//程序的结果是什么?
}
int* ptr1 = (int*)(&aa + 1);
定义了一个指针ptr1
,它指向数组aa
后一个位置。在这里,&aa
获取整个数组aa
的地址,然后+1
使指针指向下一个二维整数数组的位置,即在数组aa
之后的位置。
int* ptr2 = (int*)(*(aa + 1));
定义了一个指针ptr2
,它指向数组aa
的第二行的首地址。*(aa + 1)
实际上是取数组aa
的第二行的首元素的地址。
现在,让我们计算这两个值的具体结果:
*(ptr1 - 1)
:ptr1
指向了数组aa
后面的位置,而ptr1 - 1
则是指向数组aa
之前一个整数数组的首元素。这个整数数组是{6, 7, 8, 9, 10}
,所以*(ptr1 - 1)
取出了这个整数数组的最后一个元素,即10
。*(ptr2 - 1)
:ptr2
指向数组aa
的第二行的首地址,而ptr2 - 1
则是指向数组aa
第二行之前一个整数的位置。这个整数是5
,所以*(ptr2 - 1)
取出了5
。- 程序的结果是什么?10,5
demo7:
#include <stdio.h>
int main()
{
char* a[] = { "work","at","mihayou" };
char** pa = a;
pa++;
printf("%s\n", *pa);
return 0;
//程序的结果是什么?
}
char* a[] = { "work","at","mihayou" };
这一行定义了一个字符指针数组a
,其中包含三个元素,分别指向字符串常量 "work"、"at" 和 "mihayou"。
char** pa = a;
这一行定义了一个指向字符指针的指针pa
,并将其指向字符指针数组a
的第一个元素,即 "work" 的地址。
pa++;
这里将指针pa
向后移动一个位置,现在pa
指向字符指针数组a
的第二个元素,即 "at" 的地址。
printf("%s\n", *pa);
这一行使用printf
函数打印指针pa
指向的位置的值,也就是字符指针 "at" 所指向的字符串。
demo8:
#include<stdio.h>
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;
//程序的结果是什么?
}
参考图:
char* c[] = { "ENTER","NEW","POINT","FIRST" };
定义了一个字符指针数组c
,其中包含四个元素,分别指向字符串常量 "ENTER"、"NEW"、"POINT" 和 "FIRST"。
char** cp[] = { c + 3,c + 2,c + 1,c };
定义了一个字符指针指针数组cp
,其中包含四个元素,每个元素是一个字符指针,并分别指向c
数组的不同位置。具体地说,cp[0]
指向c
数组的第四个元素 "FIRST" 的地址,cp[1]
指向c
数组的第三个元素 "POINT" 的地址,cp[2]
指向c
数组的第二个元素 "NEW" 的地址,cp[3]
指向c
数组的第一个元素 "ENTER" 的地址。
char*** cpp = cp;
定义了一个字符指针指针指针cpp
,并将其指向字符指针指针数组cp
的第一个元素,即cp[0]
,也就是指向 "FIRST" 的地址。
printf("%s\n", **++cpp);
这一行先执行++cpp
,将cpp
指向cp
数组的第二个元素,即cp[1]
,然后再执行**++cpp
,取出指针cpp
指向的位置的值,也就是字符指针 "POINT" 所指向的字符串。所以这一行输出 "POINT"。
printf("%s\n", *-- * ++cpp + 3);
先执行++cpp
,将cpp
指向cp
数组的第三个元素,即cp[2]
,然后再执行*++cpp
,取出指针cpp
指向的位置的值,接着执行-- * ++cpp
,先对指针cpp
指向的位置进行解引用,得到 "c+1",然后再执行--
操作,指针cp
指向cp
数组的第一个元素,即c[0]
。接下来,执行* c[0] + 3
,取出 "ENTER" 的地址并加上 3,所以这一行输出 "ER".
printf("%s\n", *cpp[-2] + 3);
访问cpp[-2] <==> **(cpp-2)
,即cp
数组的第一个元素,指向 "c+3" 的地址。然后执行* cpp[-2] + 3
,取出 "FIRST" 的地址并加上 3,所以这一行输出 "ST".
printf("%s\n", cpp[-1][-1] + 1);
访问cpp[-1]
,即cp
数组的第一个元素,指向 "c+2" 的地址。然后再访问cpp[-1][-1] <==> *(*(cpp-1)-1)
,即指向 "c+2" 的指针减去 1,指向 "NEW" 的地址。最后执行cpp[-1][-1] + 1
,取出 "NEW" 的地址并加上 1,所以这一行输出 "EW".程序的结果是什么?POINT,ER,ST,EW
本章结束啦!!!