先说一下字符串字面量(字符串常量):双引号中的字符和编译器自动加入末尾的\0字符,都作为字符串储存在内存中。字符串常量属于静态存储类别,说明如果在函数中使用字符串常量,该字符串只会储存一次,在整个程序的生命周期内存在,即使函数被调用多次。用双引号扣起来的内容被视为指向该字符串储存位置的指针。
字符串的赋值可以用指针与数组,请看下面的例子
char str1[] = "I am a student";
const char *str2 = "I am a student too";
以上两种表示方法还是有一些不同的
先说数组表示法,数组形式str1[]在计算机的内存中分配一个内含15个元素的数组(末尾还要加上空字符'\0'),当程序载入内存时,也载入了程序中的字符串,字符串存储在静态存储区中,但是当程序在开始时才会为该数组分配内存,此时才将字符串拷贝到数组中,注意此时字符串有两个副本,一个是静态存储区中的常量,另一个是存储在数组中的字符串。str1为首元素的地址(&str1[0]),是常量地址,不能更改,可以进行str1+1(&str1[1]),但是不允许str++这样的操作,因为递增运算符只能对变量名进行运算。
指针形式(*str2)也使得编译器为字符串在静态存储区预留19个元素空间,一旦开始执行程序,它会为指针变量str2流出一个储存位置,并把字符串的地址储存在指针变量中,该变量最初指向该字符串的首地址,但它的值可以改变。因此可以使用自增运算符,如++str2将指向第二个字符。
总结一下,初始化数组把静态存储区的字符串拷贝到数组中,而初始化指针只把字符串的地址拷贝给指针。
看一下例子
#include <stdio.h>
#define MSG "I'm special"
int main(void) {
char str1[] = MSG;
const char * str2 = MSG;
printf("address of \"I'm special\":%p\n","I'm special");
printf(" address str1:%p\n",str1);
printf(" address str2:%p\n",str2);
printf(" address MSG:%p\n",MSG);
printf("address of \"I'm special\":%p\n","I'm special");
return 0;
}
运行结果为:
address of "I'm special":0x4006e8
address str1:0x7fff05a39f40
address str2:0x4006e8
address MSG:0x4006e8
address of "I'm special":0x4006e8
str2与MSG的地址相同,而与str1的地址不同。虽然字符串常量"I'm special"在两个printf()函数中出现了两次,但是编译器只使用了一个存储位置,而且与MSG的地址相同。