一.数组形式
const char word[6] = "wdnmd";
2.不指定大小,有编译器计算大小,这种形式只能在初始化时使用,如果要创建一个稍后再填充的数组,则必须指定大小
const char word[] = "wdnmd";
二.指针形式
const char * p1 = "wdnmd"
当以数组形式初始化时,计算机为其分配一个六个元素的内存单元。通常字符串都作为可执行文件的一部分储存在数据段中,当把程序载入内存时,也载入了程序中的字符串,但是,程序要等到运行时才会为数组分配内存,此时才将字符串拷贝到数组中。此后,内存中的字符串有两个副本,一个存储在静态存储区,一个存储在数组中。
当以指针形式初始化时,与数组形式相同的是,编译器也为字符串在静态存储区预留六个元素的空间,不同的是,他还会为指针变量留出一个存储位置,将字符串的地址给他
总而言之,以数组形式初始化是将字符串拷贝给他,而指针形式是将字符串的地址给他
众所周知,C语言中字符串是静态存储类别,所以将字符串字面量视为const类型,所以指针应该声明为指向const数据的指针。而涉及const的类型,使用指针必定会不可避免的犯一些错误。
接下来我们看一下,用未使用const限定符的指针初始化:
#include
void main(void)
{
char* p = "wdnmd";
p[1] = 'f';
puts(p);
return;
}
运行结果如下:
很明显,我们的代码通过了编译器,但是执行时并没有任何结果,这是为什么呢?
要解释这个问题,我们先来看一下下面的代码
#include
#define STRING "I'm special"
void main(void)
{
char word[] = STRING;
const char * pt = STRING;
printf("address of \"I'm special\": %p \n", "I'm special");
printf(" address of word: %p\n", word);
printf(" address of STRING: %p\n", STRING);
printf("address of \"I'm special\": %p \n", "I',special");
return;
}
这个程序的输出中有个很奇怪的地方,I‘m special在连个printf函数中出现了两次,但是确实两个不同的地址,这说明了什么,编译器可以使用内存中的一个副本来表示完全相同的字符串字面量。
清楚了这个以后,我们继续讨论上面的问题。实际上,这种行为的结果C语言是未定义,很有可能会导致内存访问错误,例如,下面的语句引用字符串“I will fuck your wife”的一个内存位置:
char * p = "I will fuck your wife";
p[0]='c';
printf(“I will fuck your wife");
printf(":Be careful ,%ss!\n","I will fuck your wife");
输出结果可能为:c will fuck your wife:Be careful ,c will fuck your self(之所以说可能,是因为编译器不同,结果也会不一样)
也就是说,编译器可以用相同的地址替换没个I will fuck your wife实力,如果编译器使用这种单词副本表示法,而且允许p[0]修改I,那么僵影响所有使用该字符串的代码
所以建议在指针初始化时加上const限定符
总而言之,如果打算修改数据,那么最好就不要用指针形式
有以下代码
const char * word1[3]={
"ASDKFJ"
"AKDSJFLAKL"
"AKSDJFAL;KDSJF"
}
和
const word2[3][20] = {
"ASDKFJ"
"AKDSJFLAKL"
"AKSDJFAL;KDSJF"
}
word显然内存占用更少
原因之一是word1是一个内含三个指针的数组,分别指向三个字符串,它占的内存只不过是地址类型的大小;而word2储存字符串字面量的副本,所以每个字符串被存储了两次
第二个原因我觉得这样子理解比较形象,word2是一个规则的盒子,每行大小相同,为了每行都装的下,他必须能储存最长字符串的大小,一共3行,每行有15个char类型的值,总共占45个字节;而word1是一个不规则的盒子,每行有自己的空间,互不干扰,只要装的下这一行的字符串就ok了,它只占24个字节,共三个地址,每个地址占8个字节,显然word2所需的空间更大