数组和指针练习解析(6)

37 篇文章 0 订阅
8 篇文章 0 订阅
文章详细解析了C语言中如何使用字符指针数组、二级和三级指针来访问字符串的首字符,展示了指针运算和数组索引的概念。
摘要由CSDN通过智能技术生成

题目:

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"};

  • 创建了一个字符指针数组,指针数组的内部存储的是各个字符串的首个字符的地址。

char**cp[] = {c+3,c+2,c+1,c};

  • cp是一个二级指针数组,数组的内部存储的是字符指针数组c的某些地址。
  • c+3——其中c是指针数组c的数组名,表示的是数组中首元素的地址,也便是c[0]的地址,而c+3表示的是往后加上三个元素的地址后抵达的位置,可以当作c[3]的地址。
  • c+2——同理,表示c[2]代表的元素地址
  • c+1——表示的是c[1]代表的元素地址
  • c——表示的是首元素地址

  char***cpp = cp;

cpp是三级指针,cpp内存储的是cp的首元素地址。


    printf("%s\n", **++cpp);

  1. ++使得cpp发生改变,原先的cpp内存储的是cp的首元素地址,在++后因为是指针数组,++表示的是向后加一个元素大小的地址,也就是第二个元素的地址。
  2. 因此在++后,这里的cpp存储的是cp1的第二个元素,c+2。
  3. 于是乎就变成了**(c+2),先解决第一个*,c+2在cp内,cp也是一个指针,所以c+2指向的是c中的第三个元素,POINT的首字符P的地址
  4. 于是乎就变成了*(P的首字符地址)
  5. 最后在解除最后一个*,且因为打印的格式是%s,所以打印除的结果是POINT

printf("%s\n", *--*++cpp+3);

  1. 按照优先级,先进行++cpp运算,因为++是有累计性的,所以cpp此刻存储的是cp中第二个元素的地址,如上图所示,因此在进行++后,cpp指向(存储)的地址变成了cp的第三个元素地址,也就是c+1的地址,所以变成了*--*(&cp[2])+3
  2. (&cp[2])表示的是cp中第三个元素的地址,最后通过*得到了内部存储的元素c+1,所以现在的结果是*--(c+1)+3
  3. *--(c+1)+3,在进行-- ,将c+1进行-- 得到的结果是c,于是变成了*(c)+3
  4. c指向的内容是字符串ENTER的首字符E的地址,所以在*后得到的是 'E'+3 
  5. 'E'+3 的E是字符类型,+3,相当于是加了三个字符类型的字节数大小,于是结果变成了ENTER中的第二个E
  6. 最后打印的格式是%s,所以打印的结果是ER

 

 printf("%s\n", *cpp[-2]+3);

  1. 由于++是有累积性的,所以cpp中存储的地址是cp的第三个元素的地址
  2. cpp[-2],表示的是一个元素,根据 *(数组名+ 0) =数组名[0] ,数组名[0]也表示一个元素 ,而数组名又表示首元素地址,我们得到结论,*(数组名+0)=数组名[0] =*( 首元素地址 +0)
  3. 而cpp是存储地址的指针,因此cpp[-2]我们可以得到,cpp现在所指向的地址-2之后得到的元素。
  4. cpp当前的地址是经过了上一次的++累加后,变成了如上图所示,指向的是cp的第三个元素,所以在-2后得到的结果是指向了cp的第一个元素,而第一个元素的内容是c+3
  5. 所以cpp[-2]= c+3
  6. *cpp[-2]+3 ————> *(c+3)+3
  7. c是一个数组名,表示的是数组首元素地址,而c+3根据数组名+n = &数组名[n]的原理,我们得到了c+3是表示首元素地址+3个元素的字节大小后后抵达的地址
  8. 在c中下标为3的元素是字符串FIRS的首字符地址,所以c+3表示的就是字符F的地址
  9. 随后得到 *(c+3)+3————>'F'+3
  10. 因为F是字符,且+3相当于是加上三个相同类型的字节数,又因为打印的各式是%s,所以得到的结果是ST

  printf("%s\n", cpp[-1][-1]+1);

  1. cpp内存储的依旧是cp中第三个元素的地址
  2. cpp[-1][-1]并不是二维数组所表达的意思,根据数组名[n] = *(数组名+n)的原理,进行计算,可以先将cpp[-1]当作数组名,那么我们可以转化为*(cpp[-1] +(-1))
  3. 而后,又将cpp当作数组名进行运算,那么我们可以转化为*(*(cpp+(-1))+(-1))——>*(*(cpp-1)-1)
  4. 而cpp中存储的是cp中第三个元素的地址,在进行-1后cpp中存储的地址发生了改变,变成了cp中第二个元素的地址,也就是c+2整个元素所在的地址,而通过第一个*后得到的结果就是c+2
  5. 所以式子变成了*(c+2-1)
  6. 内部运算,得到的结果是*(c+1)
  7. 最后整个式子是*(c+1)+1,而c是数组名,表示的是数组c的首元素地址,于是c+1表示的就是第二个元素的地址,在通过*得到的就是数组c的第二个元素
  8. 数组c的第二个元素是字符串NEW的首字符地址,所以最后的+1就是首字符地址加一,通过同类型原理,得到的就是第二个字符的地址
  9. 又因为打印的方式是%s所以最后的结果是EW

 结论:

  • *(数组名+ 0) =数组名[0],这里的数组名表示的是首元素地址
  • 数组名[n]表示的是在这个数组中,下标为n的元素的地址,也可以说为&数组名[n]
  • 数组名[n][n]这个数组并不是二维数组时,可以得到数组名[n][n]= *(*(数组名+n)+n)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值