为什么我可以在用双引号声明时使用指针作为字符串,而不是在C中用花括号括起来?

如果我声明并使用这样的指针:

int counter; char *pCow = "pCow goes MOO"; for(counter = 0; counter < 14; counter++) printf("%c", pCow[counter]); 

它显示整个字符串并且工作,是的,并且有很多欢乐。

但是,如果我使用这样的初始化器:

 int counter; char *pCow = {'p','C','o','w',' ','g','o','e','s',' ','M','O','O','\0'}; for(counter = 0; counter < 14; counter++) printf("%c", pCow[counter]); 

程序崩溃了,pCow拒绝为我的享乐主义乐趣而呻吟!

 3 Warnings. 0 Errors line 11 (near initialization for 'pCow') [enabled by default] C/C++ Problem line 11 excess elements in scalar initializer [enabled by default] C/C++ Problem line 11 initialization makes pointer from integer without a cast [enabled by default] C/C++ Problem 

在Eclipse CDT中经过精心测试。

在这种情况下, pCow设置为静态内存中c字符串的地址:

 char *pCow = "pCow goes MOO"; 

在这种情况下, pCow设置为值'p' (即112 ):

 char *pCow = {'p','C','o','w',' ','g','o','e','s',' ','M','O','O','\0'}; 

由于地址112很可能指向受限/无效的内存,因此当您尝试访问pCow[counter]时,会导致程序爆炸。

警告“标量初始化程序中的多余元素”告诉您它忽略了'p'之后的所有内容,因为指针只需要一个值。

警告“初始化使得指针来自没有强制转换的整数”告诉你你正在使用'p'作为指针,这可能不是一个好主意……

如果要使用初始化程序语法,您要做的是将pCow声明为字符数组而不是字符指针

 char pCow[] = {'p','C','o','w',' ','g','o','e','s',' ','M','O','O','\0'}; 

"pCow goes MOO"是一个字符串文字,有两种不同的用途。 您可以将它用作数组的初始值设定项:

 char aCow[] = "pCow goes MOO"; 

在这种情况下,字符串文字的内容将复制到数组中。

或者,您可以在程序的任何位置使用字符串文字作为独立常量数组。 例如strcpy(cow, "pCow goes MOO"); 。 所以这两者之间有明显的区别:

 char aCow[] = "pCow goes MOO"; char* pCow = "pCow goes MOO"; 

在第一种情况下,文字被复制到数组中。 在第二种情况下,文字在只读存储器中仍然是一个独立的常量,我们用指针指向它。 前者可以修改,后者不可以。

至于的情况

 char *pCow = {'p','C','o','w',' ','g','o','e','s',' ','M','O','O','\0'}; 

您正在使用指针,但您没有字符串文字。 相反,您有一个用于数组的初始化列表。 一个好的编译器会警告你“过多的初始化程序”。 代码编译的原因是C中的一个非常奇怪的规则,它允许使用大括号初始化普通变量,例如int x = {1}; 。 因此,编译器使用此规则初始化指向指向地址'p'指针,这当然是无意义的,然后它会丢弃初始化列表的其余部分。