1.存储位置
首先,常量字符串存储在静态存储区,对于静态存储区,其中的变量常量在程序运行期间会一直存在,不会释放,且变量常量在其中只有一份拷贝,不会出现相同的变量和常量的不同拷贝。常量字符串系统将它们放在常量区,只读的,不可以更改,并且一个字符串只有一个拷贝。
2.与字符数组的区别
常量字符串:
char *p1="abcde;
系统自动在末尾添加字符串结束标志'\0'.
如果你这时候想改变第一个字符的值,用p[0] =’b’,系统会报一个错,常量字符不能更改。
字符数组:
如果你定义一个char a[10],那么系统会“只分配”10个char这么长的内存区域,一个char是一个字节,那么系统会分配十个字节的内存空间,并且将这一片连续的内存空间的首地址赋值给a。也就是说“数组名的值是数组所在内存区域的首地址”换句话说“数组名是一个指针,指向数组第一个值的地址”。
如果你定义一个char a[] = “abcdefg”;这句代码就复杂点了。定义一个数组,数组长度未知,那么系统会根据等号后面的值来“初始化”这个数组,等号后面是什么?前面说过,它是一个常量字符串。在内存中占8个字节,7个字符加上一个结束标志。这时候在内存中就有两个”abcdefg”的字符串了,一个是常量区域的,另一个是根据前者复制了一份的。这句代码的意思就是复制一个常量区域的字符串,将复制后的字符串的首字母的地址赋值给a。
也就是说,最后a所指向的内存区域,已经不是常量里的”abcdefg”了,这里为什么要复制一份呢?原因是因为常量是不允许更改的,而数组一般都意味着需要修改,所以就复制了一份数据,放在非常量区域,就可以更改了。测试程序如下:
char* p1 = "abcdef";
char* p2 = "abcdef" ;
char a[]= "abcdef" ;
unsigned long dwP1 = (unsignedlong)p1 ;
//32位系统里的指针就是4个字节的整数,这样可以具体查看指针的值。
unsigned long dwP2 = (unsignedlong)p2 ;
unsigned long dwA = (unsignedlong)a ;
printf("p1的值(32位地址)= 0x%X\n",dwP1);
//%X是打印十六进制,X是大写,x是小写
printf("p2的值(32位地址)= 0x%X\n",dwP2);
printf("a的值(32位地址) = 0x%X\n",dwA);
字符串常量在内存中只有一份。而赋值给数组的时候,系统会拷贝一份。
3.strlen和sizeof的区别
strlen求字符串的长度,遇到字符串结束符'\0’即终止。sizeof求字节数,包括终止符'\0'.
char a[]="abcdef";
char b[]={'a','b','c','d','e','f'};
char *p="abcdef";
strlen(a)=6;sizeof(a)=7;//包括字符串终止符'\0'
strlen(p)=6;sizeof(p)=4;//指针的大小;
strlen(b)=?;//未知值,首先strlen函数一直会扫描字符数组,直到遇到'\0',而数组中不存在'\0',所以会一直往后扫描,直到遇到某个'\0'为止