在程序中使用字符串常量会生成一个“指向字符的常量指针”,当一个字符串常量出现于一个表达式中时,表达式所使用的值就是这些字符所存储的地址,而不是字符本身。因此,可以把字符串常量复制给一个“指向字符的指针”,后者指向这些字符所存储的地址。标准C函数库包含了一组函数用于操纵字符串,包括对字符串进行复制、连接、比较以及计算字符串长度和在字符串中查找特定字符的函数。
原文:http://blog.163.com/liyani_1980/blog/static/38604145201121124347692/
总结:
1.字符串常量是不可改变的,放在文字常量区,也就是在静态存储区上。
2.除了charbuffer[20]= "hello ";和strcpy(p, "hello");除了这两个情况外,程序中出现的字符串都应该被视为字符串常量.
如constchar *p= "hello ";
////////////////////////////////////////////////
简单地说,除了存在栈和堆上的字符串才不是字符串常量.其余的都是字符串常量.
举一个例子:char buffer[20]= "hello";这个字符串是用来初始化字符数组buffer的,存在栈上,不是一个字符串常量,可以用下标读写其值.又比如,char*p=malloc(...);
strcpy(p, "hello ");这个 "hello"也不是一个字符串常量,因为是在堆上,也可以用指针p进行读写.
至于在这两者的前面加上const修饰,虽然表明 "hello"是不允许更改的,但是对于字符串来说,不能说明是字符串常量.因为,const要修饰的不是明确说hello是不可写的,而是说p指向的这段内存区域是不可写的.修饰的对象是不同的,只是恰巧这段区域里存的是hello这个字符串(说得有点绕了吧,你再坚持一下).
除了这两个情况以外,程序中出现的字符串都应该被视为字符串常量了.
比如const char *p= "hello";这个字符串是存放在静态存储区上的,是不可以更改的.它的有效范围是整个程序的生命期.如果有另外的语————句p= "nb";那么,hello这个字符串将会永远不被引用,但是它会存在于整个程序的生命期.这才是真正的字符串常量.
如下代码:
chara[]="hello";
a[0]='X';//ok
printf("%s", a);
char*pl="world";
pl[0]='H';//运行时错误
*pl='X';//运行时错误
printf("%s", pl);
char*s=NULL;
s=(char*)malloc(sizeof(char)*6);//让俺的s到堆上去
strcpy(s,"hello ");
s[0]='x';//ok
printf("%s ",s);
"hello"是字符常量。但char *s定义的是字符指针的。
s[0]= 'X ';当然是错误的,因为s[0]其实说的就是 'h'啦,h是常量来的,当然不能修改,假如你需要修改的话请用。
char s[6]= "hello ";
s[0]= 'X '; 就没事了。 其实char *pl="world";最好写成const char*pl="world";;以免被误用
s不是常量
指向常量
因此在此应用中不能更改
char *s= "ddd ";
一般应该定义成 const char *s = "dddd ";
如果想修改字符串字符的值就用char a[]="hello";
voidmain()
{
const char *s= "hello ";//此处加了个const修饰.
s[0]= 'X ';
}
这与i386的运行模式有关,现在大部分程序是32位的,一般都是运行在保护模式下,这种模式可以设定某个数据段不能write。 但TC的程序是16位实模式的,数据段无所谓read/write限制,甚至连代码段都是可以write的。 |
char *a ="hello world";
char b[] = "hello world";
*a = 'c';
b[0] = 'c';
编译一下,编译通过,运行一下,崩溃了,这是为什么呢?
下面我们就来详细的分析一下:
当我们双击执行上述编译连接之后的.exe的时候,从逻辑上,操作系统是这样子做的,
char *a = "helloworld";首先,操作系统在编译器规划内存方案中的的文字常量区分配一段内存(是连续的吗?),存储"helloworld"字符串(以二进制的形式),然后在栈区分配一个内存,存储"helloworld"字符串所在内存的首地址。
char b[] = "helloworld";操作系统在编译器规划的内存方案中的栈区分配一段连续内存空间(12个字节),存储"helloworld"字符串(以二进制的形式)。
那么当我们*a ='c';的时候,就是试图修改文字常量区的内容,但是文字常量区存储的可都是常量,常量一经初始化,就不允许被修改,所以产生错误,于是杯具就发生了……
而b[0] = 'c';是修改的栈区数组的内容,当然是合法的啦。
怎么让编译器帮我们检查出错误呢?这就需要我们巧妙的使用const来显示的告诉编译器,哥定义的内容是不允许被修改的!
const char *a = "hello world";或者
char const *a = "hello world";
这样a就变成了一个常量指针,意思是说a是一个“指向常量的指针”,那么a所指向的内存区域的内容是不允许被修改的。
既然说到常量指针,我们不得不区分一下指针常量和常量指针这两个概念。
常量指针:指向常量的指针,是说该指针所指向的内存区域的内容是常量,不可以被修改,例如:
char array1 [] = "hello world";
const char a = array1;
*a = 'c';
这样子是不可以的,但是我们可以修改该指针所指向的内存区域,例如:
char array1 [] = "hello world";
const char a = array1;
char array2 [] = "hello china";
a = array2;
这样子是可以的,因为该指针不是一个指针常量。
指针常量:该指针是一个常量,就是说该指针所指向的内存是不可以被改变的,但是该指针所指向的内存所存储的内容是可以被改变的,例如:
char array1 [] = "hello world";
const char a = array1;
char array2 [] = "hello china";
a = array2;
这样子是不可以的,因为它试图为指针a重新赋值。
char array1 [] = "hello world";
const char a = array1;
*a = 'c';
这样子是可以的,因为该指针不是一个常量指针(指向常量的指针)
一个程序的运行起来后,其在内存中有5个区域
1. 程序代码区
这个很简单,代码要执行,肯定要加载进内存, 我们不必关心。
2.文字常量区
一般我们这样定义一个字符串时,其是在文字常量区的:
char* s1 = "hello, world";
char* s2 = "hello, world";
if(s1 == s2)
printf("s1和s2指向同一个在文字常量区的字符串");
这里, s1和s2指向的是同一个字符串
3. 静态存储区
全局变量,静态变量会放在这个区域,事实上,全局变量也是静态的。
以上1,2,3三个区域的内存在程序起来的时候就开辟好了的。
4. 栈
局部变量就是在栈里的。另外,函数调用时的参数也是在栈里的,这个现在不必关心
5. 堆
malloc或new出来的内存就是在堆里的,需要程序员自己管理清除。