【C语言进阶】C指针详解之练习(附解析)

目录

一、数组sizeof/strlen的练习

        (1)整形数组-sizeof函数        

        (2)字符数组-sizeof函数

        (3)字符数组-strlen函数

        (4)字符串数组-strlen函数

        (5)字符串数组-strlen函数

         (6)指针变量-sizeof函数

        (7)指针变量-strlen函数

        (8) 二维数组-sizeof函数

二、指针笔试题

        (1)笔试题1

        (2)笔试题2

        (3)笔试题3

        (4)笔试题4

        (5)笔试题5

        (6)笔试题6

        (7)笔试题7

        (8)笔试题8


首先我们再来重新认识一下数组名的概念

数组名是首元素的地址

1.sizeof(数组名) - 数组名表示整个数组

2.&数组名 - 数组名表示整个数组

注意:

上面这两种情况都需要 sizeof() / &后面直接+数组名,如果不是直接 + 数组名,则不是表示整数数组。除了上述两种情况外,其余所有情况数组名均表示的是首元素地址。

其次地址的大小根据操作平台32位/64位的不同会开辟不同大小的空间。

32位开辟的是4个字节的空间大小,而64位开辟的是8个字节的空间大小。

 那么接下去我们就来看题目叭!

一、数组sizeof/strlen的练习

写出下面程序执行的结果:

//一维数组
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));

//字符数组
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));

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));

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));

//二维数组
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]));

看到这么多的代码是不是一下子有点头疼?没事,我们一点一点来进行分析:

(1)整形数组-sizeof函数        

#include 
int main()
{
    //1.数组名是首元素的地址
    //2.sizeof(数组名) - 数组名表示整个数组
    //3.&数组名 - 数组名表示整个数组
    //一维数组
    int a[] = {1,2,3,4};// 4*4 = 16字节
    printf("%d\n",sizeof(a));
    // 16 sizeof(数组名) 计算的是数组总大小单位是字节 4*4=16字节
    printf("%d\n",sizeof(a+0));
    // 4/8 数组名这里表示首元素的值,a+0还是首元素地址,地址的大小就是4/8个字节
    printf("%d\n",sizeof(*a));
    // 4 数组名表示首元素地址,*a就是首元素,是int型,sizeof(*a)为4个字节
    printf("%d\n",sizeof(a+1));
    // 4/8 - 数组名这里表示首元素地址,a+1为第二个元素的地址,地址的大小就是4/8个字节
    printf("%d\n",sizeof(a[1]));
    // 4 - 下标为1,即第2个元素的大小。为4个字节
    printf("%d\n",sizeof(&a));
    // 8 &a取出的是数组的地址,但是数组的地址也是地址,地址大小为4/8个字节
    printf("%d\n",sizeof(*&a));
    // 16 &a数组的地址,数组的地址解引用访问的数组,sizeof计算的就是数组的大小,单位是字节
    printf("%d\n",sizeof(&a+1));
    // 4/8 &a是数组的地址,&a+1,跳过整个数组,仍为一个地址,大小为4/8个字节
    printf("%d\n",sizeof(&a[0]));
    // 4/8 &a[0]是第一个元素的地址,地址大小为4/8个字节
    printf("%d\n",sizeof(&a[0]+1));
    // 4/8 &a[0]+1是第二个元素的地址,地址大小为4/8个字节

    return 0;
}

结果:

【C语言进阶】C指针详解之练习(附解析)_第1张图片


(2)字符数组-sizeof函数

#include 
int main()
{
    //字符数组
    char arr1[] = {'a','b','c','d','e','f'};
    printf("%d\n", sizeof(arr1));
    // 6 sizeof计算的是数组大小,由于arr1是一个指针,他里面有6个char类型的元素,6*1=6字节
    printf("%d\n", sizeof(arr1+0));
    // 4/8 数组名arr1不是单独放在数组内部,并且它没有取地址,+0后依然是首元素地址,地址为4/8个字节
    printf("%d\n", sizeof(*arr1));
    // 1 arr1是首元素地址,*arr1是首元素,首元素是字符大小为1个字节
    printf("%d\n", sizeof(arr1[1]));
    // 1 arr1[1]代表下标为1,即第2个元素的大小,为1个字节  
    printf("%d\n", sizeof(&arr1));
    // 4/8 &arr1虽然是数组的地址,但他仍然是一个地址,所以地址大小是4/8个字节
    printf("%d\n", sizeof(&arr1+1));
    // 4/8 &arr1是数组的地址,&arr1+1跳过了整个数组,仍为一个地址,地址大小为4/8个字节
    printf("%d\n", sizeof(&arr1[0]+1));
    // 4/8 &arr1[0]是第一个元素的的地址,即首元素地址,而&arr1[0]+1是第二个元素的地址,地址大小就是4/8个字节

    return 0;
}

 结果:

 【C语言进阶】C指针详解之练习(附解析)_第2张图片


(3)字符数组-strlen函数

#include 
int main()
{
    char arr[] = { 'a ', 'b', 'c', 'd', 'e', 'f' };
    printf("%d\n", strlen(arr1));
    // 随机值 arr表示首元素地址,数组中没有\0,所以用strlen计算长度的时候不知道会在哪里停止,所以是随机值
    printf("%d\n", strlen(arr1+0));
    // 随机值 随机值,arr+0表示首元素地址,数组中没有\0,所以用strlen计算长度的时候不知道会在哪里停止,所以是随机值
    //printf("%d\n", strlen(*arr1));
    // error strlen后面需要传递一个地址,*arr表示首元素,首元素是字符'a',其ASCII码是97,strlen会将97当作地址来处理,此时会造成越界访问,运行时会报错
    //printf("%d\n", strlen(arr1[1]));
    // error strlen后面需要传递一个地址,arr[1]表示第二个元素,首元素是字符'b',其ASCII码是98,strlen会将98当作地址来处理此时会造成越界访问,运行时会报错
    printf("%d\n", strlen(&arr1));
    // 随机值 &arr表示数组的地址,数组中没有\0,所以用strlen计算长度的时候不知道会在哪里停止,所以是随机值
    printf("%d\n", strlen(&arr1+1));
    // 随机值-6 &arr+1表示跳过数组后的地址,后面不知道什么时候遇到'\0',所以是随机值,但是要减去这个数组的大小,即随机值-6
    printf("%d\n", strlen(&arr1[0]+1));
    // 随机值-1 &arr[0] + 1表示第二个元素的地址,后面不知道什么时候遇到'\0',所以是随机值,但是这里由于少了一个a,所以随机值要减去1,即随机值-1
    
    return 0;
}

 结果:

【C语言进阶】C指针详解之练习(附解析)_第3张图片


(4)字符串数组-strlen函数

#include 
int main()
{
    char arr2[] = "abcdef";
    printf("%d\n", sizeof(arr2));
    // 7 由于这是一个字符串,字符串后面有'\0',sizeof(arr2)计算的整个数组的大小,单位是字节,所以7*1=7
    printf("%d\n", sizeof(arr2+0));
    // 4/8 数组名arr2不是单独放在数组内部,并且没有取地址,+0后依然是首元素地址,地址为4/8个字节
    printf("%d\n", sizeof(*arr2));
    // 1 arr2是首元素地址,*arr2是首元素,首元素是a,字符大小为1个字节
    printf("%d\n", sizeof(arr2[1]));
    // 1 arr2[1]计算下标为1,即第二个元素,sizeof(arr2[1])计算的是第二个元素b的大小,因为类型是char,所以为1个字节
    printf("%d\n", sizeof(&arr2));
    // 4/8 &arr2是数组的地址,但也是地址,地址大小是4/8个字节
    printf("%d\n", sizeof(&arr2+1));
    // 4/8 &arr2是数组的地址,&arr2+1跳过了整个数组,但仍是一个地址,大小是4/8个字节
    printf("%d\n", sizeof(&arr2[0]+1));
    // 4/8 &arr2[0]是第一个元素的地址,即首元素地址,而&arr[0]+1是第二个元素的地址,大小为4/8个字节

    return 0;
}

结果: 

【C语言进阶】C指针详解之练习(附解析)_第4张图片


(5)字符串数组-strlen函数

#include 
int main()
{
    char arr2[] = "abcdef";
    printf("%d\n", strlen(arr2)); 
    // 6 strlen是求'\0'前的元素个数,abcdef是6个元素,所以是6个字节
    printf("%d\n", strlen(arr2+0));
    // 6 arr2是首元素地址,数组名,+0仍一样,所以是6个字节
    //printf("%d\n", strlen(*arr2));
    // error arr2是首元素地址,*arr2传过去的值是a,a的ASCII码值是97,此时的空间不属于你所要访问的空间,属于非法访问,所以这里产生报错
    //printf("%d\n", strlen(arr2[1]));
    // error 同上,传的是b的值,b的ASCII码值是98,开辟空间仍然不属于应访问的空间,所以产生报错
    printf("%d\n", strlen(&arr2));
    // 6 &arr2是数组的地址,数组指针,而他仍是一个地址,strlen是求'\0'前的所有元素,所以是6个字节
    printf("%d\n", strlen(&arr2+1));
    // 随机值 &arr2跳过了整个数组,此时'\0'也被移动过去了,所以找不到'\0'的位置,产生的是随机值
    printf("%d\n", strlen(&arr2[0]+1));
    // 5 &arr2[0]是取首元素地址,+1看出向右移,取第二个元素b的地址,strlen求'\0'前的所有元素,所以此时是5个字节

    return 0;
}

结果:

【C语言进阶】C指针详解之练习(附解析)_第5张图片


 (6)指针变量-sizeof函数

#include 
int main()
{
    char *p = "abcdef";
    printf("%d\n", sizeof(p));
    // 4/8 此时p是char *的指针变量,它里面存放的是首元素a的地址,指针变量p的大小为4/8个字节
    printf("%d\n", sizeof(p+1));
    // 4/8 此时p仍然是char *的指针变量,+1的得到的是第二个元素字符b的地址,地址的大小为4/8个字节
    printf("%d\n", sizeof(*p));
    // 1 *p就是字符串的首元素a,字符a的大小为1个字节
    printf("%d\n", sizeof(p[0]));
    // 1 p[0] == *p(p+0),就是字符串的首元素a,字符a的大小为1个字节
    printf("%d\n", sizeof(&p));
    // 4/8 &p就是变量p的地址,那么地址的大小为4/8个字节
    printf("%d\n", sizeof(&p+1));
    // 4/8 &p+1是跳过了一个p的地址,此时仍为地址,所以大小是4/8个字节
    printf("%d\n", sizeof(&p[0]+1));
    // 4/8 &p[0]是首元素的地址,+1后是元素b的地址,地址的大小是4/8个字节
    return 0;
}

结果:

【C语言进阶】C指针详解之练习(附解析)_第6张图片


 (7)指针变量-strlen函数

#include 
int main()
{
    char *p = "abcdef";
    printf("\n%d\n", strlen(p));
    // 6 strlen是求'\0'前的所有元素大小,这里p是数组名,首元素地址,所以从a开始,一共是6个元素,大小是6个字节
    printf("%d\n", strlen(p+1));
    // 5 p是首元素,即a的地址,+1后是b的地址,从b一直到'\0'前一共是5个元素,所以大小是5个字节
    //printf("%d\n", strlen(*p));
    // error *p为字符‘a’,ASCII码是97,strlen会将97当作地址来处理,此时会造成越界访问,运行时会报错
    //printf("%d\n", strlen(p[0]));
    // error p[0]为字符‘a’,ASCII码是97,strlen会将97当作地址来处理,此时会造成越界访问,运行时会报错
    printf("%d\n", strlen(&p));
    // 随机值 取出p的地址,传给strlen,strlen在往后寻找'\0',不知道什么时候遇到'\0'
    printf("%d\n", strlen(&p+1));
    // 随机值 取出p后面的地址,传给strlen,strlen在往后寻找'\0',不知道什么时候遇到'\0'
    printf("%d\n", strlen(&p[0]+1));
    // 5 p[0]表示首元素,&p[0]表示首元素地址,&p[0] + 1表示第二个元素'b'的地址,而strlen从'b'开始计算字符串长度

    return 0;
}

结果:

【C语言进阶】C指针详解之练习(附解析)_第7张图片


(8) 二维数组-sizeof函数

在进行这段代码的剖析前,我们先来了解一些知识:

二维数组的数组名表示首元素地址时,首元素指的是第一行数组,也就是说首元素是数组,数组名表示的是第一行数组的地址。

【C语言进阶】C指针详解之练习(附解析)_第8张图片

 代码:

#include 
int main()
{
    int a[3][4] = {0};
    printf("%d\n",sizeof(a));
    //48 3*4*4=48
    printf("%d\n",sizeof(a[0][0]));
    //4 指向的是下标0,第一行的第一个元素,因为是int型,大小为4字节
    printf("%d\n",sizeof(a[0]));
    //16 a[0]相当于第一行作为一维数组的数组名,第一行一共是4个元素,大小为4*4=16字节
    printf("%d\n",sizeof(a[0]+1));
    //4/8 此时a[0]没有单独放到sizeof()表达式中,表示的是首元素地址,此时a[0]+1是第一行第二个元素的地址,所以是4/8个字节
    printf("%d\n",sizeof(*(a[0]+1)));
    //4 a[0]+1指向的是第一行第二个元素的地址,解引用后得到的是他的值,由于是int型,所以大小是4个字节。
    printf("%d\n",sizeof(a+1));
    //4/8 a是二维数组的数组名,没有sizeof(数组名),也没有&数组名,所以a是首元素地址,二维数组的首元素是第一行,此时a+1就是第二行地址,大小是4/8字节
    printf("%d\n",sizeof(*(a+1)));
    //16 由于a+1是第二行的地址,而数组的地址解引用就是找到这个数组,大小是4*4=16字节
    printf("%d\n",sizeof(&a[0]+1));
    //4/8 &a[0]是第一行的地址,+1后代表第二行的地址,地址大小是4/8字节
    printf("%d\n",sizeof(*(&a[0]+1)));
    //16 因为a[0]+1是第二行的地址,*解引用后就是第二行的值,大小是4*4=16字节
    printf("%d\n",sizeof(*a));
    //16 因为此时a不是单独放在sizeof()表达式中,所以此时数组名a是首元素的地址即第一行的地址,*解引用后就是第一行的值,所以是4*4=16字节
    printf("%d\n",sizeof(a[3]));
    //16 a[3]是第四行,虽然它不存在,但是a[3]其实等于a[0],即第一行的值,所以是16字节
    return 0;
}

结果:

【C语言进阶】C指针详解之练习(附解析)_第9张图片

二、指针笔试题

写代码的三种境界
1.看代码是代码
2.看代码是内存
3.看代码还是代码

(1)笔试题1

程序的结果是什么?

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

解题思路:

#include 
int main()
{
	int a[5] = { 1,2,3,4,5 };
	int* ptr = (int*)(&a + 1);
    //&a表示取出数组a的地址,&a+1表示跳过该数组,指向数组后面的地址
	printf("%d,%d", *(a + 1), *(ptr - 1));
    //此时a表示首元素地址,a+1表示第二个元素地址,(a + 1)表示第二个元素---2
    //ptr表示数组后面的地址,ptr - 1表示数组末尾的地址,(ptr - 1)表示数组最后一个元素---5

	return 0;
}

【C语言进阶】C指针详解之练习(附解析)_第10张图片

 结果:

2 , 5

【C语言进阶】C指针详解之练习(附解析)_第11张图片


(2)笔试题2

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

解题思路:

这个题目考察的就是指针类型的意义,指针 + -的步长,指针 + 1到底是加几个字节。 

#include 
struct Test
{
    int Num;
    char* pcName;
    short sDate;
    char cha[2];
    short sBa[4];
}*p;
int main()
{
    p = (struct Test*)0x100000;
    printf("%p\n", p + 0x1);
    //0x1 指的是十六进制的1,转换成十进制也是1
    //0x100014 此时p是结构体指针,结构体大小是20个字节,p+1其地址+20,而20转换成地址是0x00100014(这里后面的1为16,4就是4)
    printf("%p\n", (unsigned long)p + 0x1);
    //0x100001 此时p被强制类型转换成 unsigned long 类型,也就是整型,整型+1就是实实在在的+1,所以p+1就是地址+1(即整数+1)
    printf("%p\n", (unsigned int*)p + 0x1);
    //0x100004 p被强制类型转换成unsigned int*类型,p+1就是跳过一个int类型,地址+4
    return 0;
}

结果:

00100014

00100001

00100004

【C语言进阶】C指针详解之练习(附解析)_第12张图片


(3)笔试题3

程序的结果是什么?

#include 
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 main()
{
    int a[4] = { 1, 2, 3, 4 };
    int* ptr1 = (int*)(&a + 1);
    //&a表示取出数组的地址,&a+1表示跳过数组,到数组后面的地址
    //(int*)(&a+1)将这个地址强制类型转换成int*,放到ptr1里面
    int* ptr2 = (int*)((int)a + 1);
    //a表示数组首元素地址,(int)a将这个地址强制类型转换成int类型
    //(int)a + 1,就是地址+1,(int*)((int)a + 1)将这个地址强制类型转换成int*,放到ptr2里面
    printf("%x,%x", ptr1[-1], *ptr2);
    //4  ptr[-1]==>*(ptr-1)得到数组最后一个元素,即4,%x十六进制打印结果也是4
	//02 00 00 00 *ptr2得到的就是被强制类型转换为int类型的地址的值+1,地址的单位是字节
    //由于ptr2解引用是通过小端(字节序存储)访问 00 00 00 02 ,打印的时候就是 02 00 00 00
    return 0;
}

【C语言进阶】C指针详解之练习(附解析)_第13张图片

结果:

 4,2000000

【C语言进阶】C指针详解之练习(附解析)_第14张图片


(4)笔试题4

程序的结果是什么?

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

解题思路:

#include 
int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };
    //初始化{}内部的( )是逗号表示式,结果是最后一个表达式的结果,即{1,3,5}
    int* p;
    p = a[0];
    //将二维数组第一行第一个元素的地址赋值给p
    printf("%d", p[0]);
    //0 p[0]指向的是首元素地址,%d打印就是1
    return 0;
}

【C语言进阶】C指针详解之练习(附解析)_第15张图片

答案:

1

【C语言进阶】C指针详解之练习(附解析)_第16张图片


(5)笔试题5

程序的结果是什么?

#include 
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;
}

解题思路:

#include 
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]);
	//指针:指针得到两者之间元素的个数
	//&p[4][2] - &a[4][2]之间相差4个元素,且p

【C语言进阶】C指针详解之练习(附解析)_第17张图片

答案:

FFFFFFFC , -4

【C语言进阶】C指针详解之练习(附解析)_第18张图片


(6)笔试题6

程序的结果是什么?

#include 
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;
}

解题思路:

#include 
int main()
{
    int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int* ptr1 = (int*)(&aa + 1);
    //&aa + 1 表示的跳过整个数组,指向数组aa后面的地址
    int* ptr2 = (int*)(*(aa + 1));
    //*(aa + 1) 等价于aa[1],是指第二行的首元素6的地址
    printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
    //10 *(ptr1-1)所以此时指向10的地址,%d打印就是10
    //5  *(ptr2-1)所以此时指向5的地址,%d打印就是5
    return 0;
}

【C语言进阶】C指针详解之练习(附解析)_第19张图片

答案:

10 , 5

【C语言进阶】C指针详解之练习(附解析)_第20张图片


(7)笔试题7

程序的结果是什么?

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

解题思路:

#include 
int main()
{
	char *a[] = { "work","at","alibaba" };
	//此时数组a中存的都是字符指针,而字符指针存的都是首元素地址,所以存的是'w','a','a'
	char **pa = a;
	//pa此时指向了a的首元素地址,又由于a原来就有*,所以pa要用**
	pa++;
	//pa++,指向了第二个元素的地址,也就是a[1]的地址,a[1]内部存放"at"常量字符串的首地址
	printf("%s\n", *pa);
	//at *pa解引用a[1]的地址,%s打印字符串at
	return 0;
}

【C语言进阶】C指针详解之练习(附解析)_第21张图片

答案:

at

【C语言进阶】C指针详解之练习(附解析)_第22张图片


(8)笔试题8

程序的结果是什么?

#include 
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;
}

解题思路:

#include 
int main()
{
	char* c[] = { "ENTER" , "NEW" , "POINT", "FIRST" };
	char** cp[] = { c + 3, c + 2, c + 1, c };
	char*** cpp = cp;
	printf("%s\n", **++cpp);
	//POINT 此时cpp因为++后,*++cpp后从指向cp中的'c+3'变为了'c+2',而'c+2'对应的是数组c中的POINT,所以%s打印POINT
	printf("%s \n", *-- * ++cpp + 3);
	//ER 首先++的优先级最高,所以*++cpp后从c+2指向了cp中的c+1,而--后,c+1中的1被减去了,所以就是c
	//又因为*所以c指向的是'c'对应的数组c中的"ENTER",又+3,指向了ENTER中的第二个E,所以%s打印出的结果是ER
	printf("%s \n", *cpp[-2] + 3);
	//ST *cpp[-2]+3即**(cpp+(-2))+3又等价**(cpp-2)+3,而*(cpp-2)指向的是cp中的c+3的地址
	//又因为*所以指向了'c+3'对应的c中存的"FISRT",又+3,指向了FIRST当中的S,所以%s打印出的结果是ST
	printf("%s \n", cpp[-1][-1] + 1);
	//EW cpp[-1][-1]+1等价于*(*(cpp-1)-1)+1,首先*(cpp-1),此时指向了cp中的c+2地址,而c+2-1后得到c+1
	//又因为*所以此时指向了'c+1'对应的数组c中存的"NEW",又+1,指向了NEW中的E,所以%s打印出的结果是EW
	return 0;
}

【C语言进阶】C指针详解之练习(附解析)_第23张图片

答案:

POINT
ER
ST
EW

你可能感兴趣的:(C,学习笔记,c语言)