变量指针指向的常量
关于 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 | int a=0; |
此时 a
是一个变量, p
则是一个指向变量 a
的指针,即为变量指针。
而同理,常量指针是一个指向常量的指针,如:
1 | const int a=0; |
此时 a
是一个常量, p
是一个指向常量 a
的指针,即为常量指针。
注意: 常量指针的声明格式为 数据类型 const * 指针变量
或者 const 数据类型 *指针变量。
变量还是常量?
那么问题来了,char *s="ABCDE"
一句中, s
指向的字符串是常量还是变量?
一个很简单的区分方式是,尝试改变字符串的字符。
1 | char t[]="ABCDE"; |
运行结果是:前两句可以正常执行,而执行第 4 句时则会弹出 Segmentation fault。
对程序进行分析可以知道,char *s="ABCDE";
一句会把字符串存储到只读的 rdata
段,所以无法改变其中的内容。
也就是说,char *s="ABCDE"
一句中,s 指向的字符串是常量。
总结
那么回到开始的问题,char *s="ABCDE";
为什么是错的
答案是,它用一个变量指针指向了一个常量!
正确的写法应为:const char *s="ABCDE";
也许当你编译时不会报错,甚至运行时不去改变里面的值时也不会发生中断,但这个语句的的确确是有问题的。