变量指针指向的常量

关于 char *s="ABCDE" 为什么是有问题的


前言

之所以会注意到这个问题,是因为老师布置的课堂小测的一道题,原题如下:

下面能正确进行字符串赋值操作的是____。
A. char s[5]={“ABCDE”};
B. char s[5]={‘A’,’B’,’C’,’D’,’E’};
C. char *s;s=”ABCDE”;
D. char *s;scanf(“%s”,s);

当看到答案选 B 的时候,我人傻了,因为我上网查的答案是C,纳闷着调试,结果如下:

B 选项的做法不会在后面补零终止符'\0',此时执行printf("%s",s);会打印出ABCDE后面跟着一串乱码。
C 选项的做法会在后面补零终止符,且编译器编译不报错,运行同样不报错。

此时的我更加疑惑,B 选项这不是有问题了吗?询问老师,老师给出的解释是:

题干说进行字符串赋值操作,而 C 选项是给指针赋值

这个解释离大谱

后来在 GZTime 及 Hanmur 学长的无语点拨下,我注意到了 C 选项的一个问题。

常量指针与变量指针

首先先引入常量指针与变量指针的概念,顾名思义,变量指针就是指向变量的指针,如:

1
2
int a=0;
int *p=&a;

此时 a 是一个变量, p 则是一个指向变量 a 的指针,即为变量指针。
而同理,常量指针是一个指向常量的指针,如:

1
2
const int a=0;
const int *p=&a;

此时 a 是一个常量, p 是一个指向常量 a 的指针,即为常量指针。
注意: 常量指针的声明格式为 数据类型 const * 指针变量 或者 const 数据类型 *指针变量。

变量还是常量?

那么问题来了,char *s="ABCDE"一句中, s 指向的字符串是常量还是变量?
一个很简单的区分方式是,尝试改变字符串的字符。

1
2
3
4
char t[]="ABCDE";
t[0] = 'F';
char *s="ABCDE";
s[0]='F';

运行结果是:前两句可以正常执行,而执行第 4 句时则会弹出 Segmentation fault
对程序进行分析可以知道,char *s="ABCDE";一句会把字符串存储到只读rdata 段,所以无法改变其中的内容。
也就是说,char *s="ABCDE"一句中,s 指向的字符串是常量

总结

那么回到开始的问题,char *s="ABCDE"; 为什么是错的
答案是,它用一个变量指针指向了一个常量
正确的写法应为:
const char *s="ABCDE";
也许当你编译时不会报错,甚至运行时不去改变里面的值时也不会发生中断,但这个语句的的确确是有问题的。

作者

未央

发布于

2021-12-30

更新于

2024-03-26

许可协议

评论