指针的两个遗忘点

文章详细分析了C语言中二维数组与指针的关系,解释了*a表示的不同含义,以及指针和数组在地址计算上的差异。同时,讨论了字符指针与字符数组的区别,包括修改字符串内容的权限和指针操作的合法性。文章通过示例代码解释了*C++运算符的优先级和结合性,并指出*p++和*(p++)的执行顺序。最后,提供了多个选择题例子来检验对这些概念的理解。
摘要由CSDN通过智能技术生成

1.下面程序段运行结果为()

int a[3][3] = {9,8,7,6,5,4,3,2,1},*p = a[1] + 1;
printf("%d\n",p-*a);

解析:
二维数组与指针的关系:
*a = *(a+0)+0,可以指二维数组a的首地址,也可以指第0行元素的首地址,也可以指第0行第0列这个元素的地址,也就是9这个元素在内存里的地址。

*(a+1) ,指第1行元素的首地址,等价于 *(a+1)+0,也就是第1行第0列元素的地址。

a[1],指第1行元素的首地址,等价于*(a+1)+0,也可以指第1行第0个元素的地址。

a[1]+1,也就等价于*(a+1)+1,指代的是第1行第1列元素的地址。

综上所述:p - *a为两个5和9两个元素的地址差,答案为4。

如果我们打印p的值发现为8191488,打印*a的值,发现为8191472。差为16,但如果输出p - *a的值,为4。这是因为这里是按字节编址的,在打印地址的时候,我们才看到了其对应的地址,相差为16个字节,一个int型变量占4个字节,正好对应4个。打印地址差的时候,输出的是4个sizeof(int)这么大的地址空间。所以这个答案输出的是4,而不是16。

2.下面说法正确的是()
A.

char *p = "ABCD"; printf("%c",*p+=1);的结果为B

B.

char p[]="ABCD"; printf("%c",*p++);的结果为A

C.

char p[]="ABCD"; printf("%c",*s++);的结果为B

D.

char *p="ABCD"; printf("%c",*p++);的结果为A

解析:
1.字符指针和字符数组的区别和联系
字符指针和字符数组变量均储存在栈里;其对应的字符串,作为常量储存在常量区。
区别:
字符指针定义的字符串不能直接进行字符串内容的修改,而字符数组可以直接对字符串的内容进行修改
字符指针不能将对应的字符串从常量区拷贝到栈里进行修改;而字符数组可以将字符串的内容从常量区拷贝到栈内进行修改。
例如:

char *p = "ABCD";
printf("%c",*p+=1);

这种写法是错误的,因为它企图更改字符指针所指向的字符串的内容。

char p[] = "ABCD";
printf("%c",*p+=1);

这种写法是正确的,因为我们可以修改字符数组对应的内容。他会输出A的ascii码+1对应的字符B。
字符指针可以直接使用这一指针来对指针进行指针的+,-等操作;不能直接使用以字符数组数组名为地址的指针进行指针的+,-操作。
例如:

char* p = "ABCD";
printf("%c",*(p+=1));

这将输出B,因为可以直接对字符指针p进行+,-等操作。
取出的是与A这个字符相邻的后一个字符,也就是B的地址,然后取其中的内容进行输出,为B。

char p[] = "ABCD";
printf("%c",*(p+=1));

这个会报错,因为不可以直接拿字符数组的名称p,将p这个指针进行+,-操作。这是不行的。
但是怎么做就可以了呢?

char p[] = "ABCD";
char *s = p;
printf("%c",*(s+1));

这样就可以了,取一个字符指针s指向字符数组p的首地址。然后修改s指针就可以了。
我们看一下如下的代码:

char p[] = "ABCD";
char *s = p;
printf("%d\n",s);
printf("%d",p);

输出均为8191507,证明s和p的值相同,这是因为它们都指向了‘A’这个元素的地址。

char p[] = "ABCD";
char *s = p;
printf("%d\n",&s);
printf("%d",&p);
return 0;

输出为:
8191504
8191515
我们可以看到,虽然s和p的值相同,但是它们并非为同一块存储空间,因为它们的类型不同,一个是字符指针,一个是字符数组,是不一样的,只是它们的值相同,仅此而已。(当然,s和p所对应的两块存储空间都位于栈内)。
这里值得注意的是,极容易被迷惑的一点是,*(p+1)这不算对p这个指针进行了+,-操作。

2.*和++的运算
*和++的运算优先级相同,但是遵循右结合。
也就是说:

*w++;   //右结合,相当于*(w++)
++*w;   //右结合,相当于++(*w)

*p++和 *(p++)的辨析:
这两个比较特殊,有一个压倒一切的原则,++运算符要整个表达式运算完了才运算。
所以说 *p++和 *(p++)都是一样的:先提取p指向的对象值,然后再对p做++运算,指向下一个存储单元的对象。

所以再回到这道题目:
A选项中,*的优先级高于+=,企图对字符指针所指向的字符串直接进行内容的修改,这是不对的,会报错。
B选项中,p++企图直接对字符数组名p的指针进行+,-操作,错误,会报错。
C选项中,s为一个字符指针,s++先输出s的值,为A,然后再对s指针加1,由于是字符指针,可以移动。不会报错,但输出的是A,选项说是B,所以C也错误。
D选项中,*p++,先输出p指向的字符的值,再对p指针后移一个存储单元,故输出A,不会报错,所以D选项正确。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值