容易混淆的不同字符串的定义形式 char p[ ]和char * q有什么区别。烧脑指针练习之c语言三级指针,指针的运算和使用。

字符串的定义形式

char a[ ] = "abcdef";  //这种定义下,a是一个字符数组,数组里有7个元素 abcdef \0。

只有在&a  和单独放置在sizeof中时,数组名a代表的是整个数组的地址 ,除此之外,数组名都代表数组首元素的地址。

char* p = "abcdef";//在这种定义下,系统会创建一个常量字符串(常量字符串,只能被访问,不能修改其中的数据。),而p中放置的是字符a的地址。这里要注意:这种定义方式下

p并不是一个数组。它只是一个装着常量字符串中首字符a的地址的一个指针。

下面我们通过一个例子来了解这两种定义方式的区别:

1:一种可以访问和改变数据,另一种只能访问而不能改变数据

 可以看到   char* p = "abcdef";这种定义形式下,不可以修改指向的数据,但是可以访问其中的数据 。

2:不同的保存形式

可以看到不同定义形式下 p和q的地址是相同的,因为他们所指向的是同一串字符常量。 

而a、和 b因为这是两个不同的数组,所以系统给他们分配不同的空间,只不过他们所指向的两块空间中存储的数据是相同的。并且也和p q的地址不同。

我们来看一个简单的习题

int main()
{
    char* a[3] = { "work","at","c++" };//
    char** pa = a;
    pa++;
    printf("%s", *pa);
    return 0;
}

   char* a[3] = { "work","at","c++" };这种定义方式解读如下

a是一个数组,数组有三个元素 ,每个元素的类型是char*(一个指向字符型的指针)

 所以这个结果打印的就是    at

有了上面这些铺垫 ,下面再来看一个比较烧脑的三级指针习题。

int main()
{
    char* c[] = { "neter","new","point","first" };
    char** cp[] = { c + 3,c + 2,c + 1,c + 0 };
    char*** cpp = cp;
    printf("%s", **++cpp);
    printf("%s",*--*++cpp);
    printf("%s", *cpp[-2]+3);
    printf("%s",cpp[-1][-2] + 1);
    return 0;
}

 首先我们简单分析一下上面的各种定义方式所得到的结果

 char* c[] = { "neter","new","point","first" }; c是一个数组,数组中的元素类型都是指针,指向的是初始化中各个字符串的首字符(c数组中每个指针元素内分别放置的是后面四个字符串的首字符的地址

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

cp依旧是一个数组,数组中的元素类型的指针,指针中存放的是一级指针的地址(cp中的元素都是二级指针,他是一个二级指针数组)

 char*** cpp = cp;//cp是一个数组名,数组名中除了两种例外(在开头有交代),其他情况下都代表数组首元素的地址。。cpp是一个三级指针,它里面存放的是二级指针的地址。

我们来画图来了解一个他们之间的关系,图解如下。

printf("%s", **++cpp); 打印的结果分析

**++cpp ,++是前置++,所以先对cpp进行++,再使用这个变量,那么此时cpp中的地址应该是c+2这个数据的地址,然后*(解引用)找到c+2,再*(解引用)找到char*3 然后以字符串形式打印 

打印出的结果是      point 。(图解如下)

下面是指针的指向路径

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

刚才经过第一次的++,现在的  *cpp指向的是c+2的位置,再一次前置++,拿到c+1位置的地址,*(解引用)访问c+1 .然后又前置--,这里要注意,原来存放c+1的地址的cp数组的第三个元素,自减,那么这个第三个元素中,现在存放的是指向 c 的地址。再* (解引用)访问到char*1,以%s的形式打印出的结果应该是     neter (图解如下)

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

经上面的变化 cpp现在指向cp[3],   经过第一步后( cpp[-2]    <=>    *(cpp-2)  )*(cpp-2)指向cp【0】再解引用可以访问到   char*4,又 +3,字符类型的指针,+3跳过三个字节,所以这里从s开始打印(这里要注意,cpp[-2]  是没有改变cpp的指向位置的。而前面的改变是因为它自身的++和--)。(图解如下)

         打印结果  st 

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

cpp【-1】《=》代表*(cpp-1)访问到 cp【1】拿到指向char*3的数据  c+2,然后再次-2,那么现在cp【1】中存放的数据是  c+0,解引用访问的是char* 1的数据,再+1,那么在printf函数拿到字符串”neter“的地址是第一个e的地址,最终也会从第一个e开始打印 

打印结果是  eter(图解如下)

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值