const char * p = "Hello World!";
const char Array[] = "Hello World!";
以上两种声明,p和Array都使用了字符串“Hello World!”的地址。在这种情况下,带双引号的字符串本身决定了预留给字符串的存储空间,但这两种形式并不是完全相同的。
数组形式和指针形式有何不同呢?
**数组形式(Array[])**在计算机的内存中分配一个内含13个字节的数组,该数组中每个元素被初始化为字符串字面量对应的值。通常,字符串“Hello World!”都作为可执行文件的的一部分存储在数据段中(静态存储区)。当程序运行时,才会为数组Array[]分配内存,此时才会把字符串从数据段拷贝到数组,即Array[]中的值为原始字符串的一个副本,而原始字符串依旧原封不动地保存在数据段。并且Array被编译器识别为备份字符串的首地址别名,为地址常量不可更改,即++Array之类的操作都是错误的。
**指针形式(p)**与数组形式不一样,从定义开始,指针p就保存着原始字符串“Hello World!”的首地址,并且指针p的值是可以改变的,即++p操作是合法的,表示指向下一个字符‘e’。
总之,初始化数组是把静态存储区的字符串拷贝到数组中,而初始化指针只是把字符串的地址拷贝给指针。
——————————————————————————————
#include <stdio.h>
#define MSG "I love China."
int main(int argc, char const *argv[])
{
const char *p = MSG;
char Array[] = MSG;
printf("adddress of \"I love China.\": %p\n", "I love China");
printf(" address of Array: %p\n", Array);
printf(" address of p: %p\n", p);
printf(" address of MSG: %p\n", MSG);
printf("adddress of \"I love China.\": %p\n", "I love China");
return 0;
}
输出结果:
adddress of "I love China.": 0x7f22cc200826
address of Array: 0x7fffcac294ca
address of p: 0x7f22cc200818
address of MSG: 0x7f22cc200818
adddress of "I love China.": 0x7f22cc200826
从程序输出的数据可以看出:
- p与MSG的地址是相同的,而Array的地址是不同的,所以是符合上面的结论的;
- 两次printf函数打印的“I love China.”的地址是一样的,说明两次在字符串都存储在同一个位置,但是却与MSG的位置不同,说明编译器编译的时候可以把多次使用的相同的字面量的字符串存储在一处或多处。
对于没有使用const限定符的指针初始化,能否使用该指针来修改这个字符串呢?
char * word = "big";
word[0] = 'p'; // 是否允许呢?
编译器可能是允许这样做,但是对于标准C此行为是未定义的。因为word指针的初始化是将字符串“big”的首地址赋值给word,而字符串“big”还是存储在数据段中,并没有备份到其他位置(与上述Array[]数组初始化方式区别),而根据上述历程,编译器有可能使用内存中的一个副本来表示完全相同的字符串字面量,所以直接使用指针修改了字符串有可能会直接影响到所有使用到该字符串的代码。因此,建议把指针初始化为字符串字面变量时使用const限定符。如下:
const char * word = "big";