在C语言中,可以使用字符串指针,字符串数组来引用字符串,指针和数组存储字符串的时候,编译器对两者的处理方式是不同的:
1、字符串数组方式
char string[] = "Hello World!";
char string[] = {'H','e',...,'d','!','\0'};
字符串数组的存储方式和其他数组的存储方式一样,属于auto variable类型存储在堆栈中,如果属于全局或者静态变量则存储在数据段中。
2、字符串指针方式
指针方式有一下两种方式,一种是提前给定分配空间,另一种是动态分配方式。
2.1当做字符串常量(只读)处理,存放在共享的空间
char *str = "Hello world!";
这种方式,“Hello world”被当做字符串常量存储在共享的只读位置,指针本身存储在可读可写的内存中,你可以更改指针的指向指向其他的位置,但不能更改当前指针指向中的内容,可以理解为当前指针指向的内容是作为常量来处理的,不能随便更改。以这种方式存储的字符串,适合用于字符串固定,没有修改的场合。
2.2在堆中动态分配
char *str;
int size = 13; /*one extra for ‘\0’*/
str = (char *)malloc(sizeof(char)*size);
*(str+0) = 'H';
*(str+1) = 'e';
*(str+2) = 'l';
. .
. .
*(str+13) = '\0';
下面举几个例子说明:
例一:
int main(void)
{
char string[] = "Hello";
string[0] = 'A';
return 0;
}
例二:
int main(void)
{
char *str = "Hello";
str[0] = 'A';
return 0;
}
在上述例子中,例一中对第一个字符修改是合法的,例二中企图修改第一个字符时,程序编译通过,但运行的时候报错“Segmentation fault (core dumped)”,出错的原因是对只能空间进行修改操作的非法行为引起的。
例三:
int main(void)
{
int size = 4;
char *str = (char *)malloc(sizeof(size));
*(str+0) = 'H';
*(str+1) = 'i';
*(str+2) = '!';
*(str+3) = '\0';
printf("%s",str);
return 0;
}
例三通过malloc在堆中动态分配字符串的存储空间,可对字符串内容进行写操作。
例四:
char *getstring()
{
char *str = "Hello";
return str;
}
int main(void)
{
printf("%s",getstring());
return 0;
}
例四在子函数char *getstring()中定义了局部的字符串变量char *str = "Helllo";子函数char *getstring()返回的是字符串变量char *str = "Helllo"的指针str。改程序可以编译通过且能正常执行。
例五:
char *getstring()
{
char str[] = "Hello";
return str;
}
int main(void)
{
printf("%s",getstring());
return 0;
}
例五将例四中的字符串存储的方式改为char str[] = "Hello",改程序不能被编译通过,有警告 warning: function returns address of local variable。可见编译器对字符串指针和字符串数组的存储方式的处理是不同的。
例6:
char *getstring()
{
int size = 4;
char *string = malloc(sizeof(char)*size;
string[0] = 'H';
string[1] = 'i';
string[2] = '!';
string[3] = '\0';
return string;
}
int main()
{
printf("%s\n",getstring());
return 0;
}
再看例六中使用malloc在堆中分配存储空间,子函数推出的时候没有删除掉分配的存储空间,在main()函数中还是能够寻址该字符串的存储空间。关于编译器对指针和数组的处理细节还有待于深究,还有不同类型的变量存储空间,如堆、栈、数据段、代码段等。。。