第四章 令人震惊的事实:数组和指针并不相同
(1)声明和定义
C语言的对象(与C++中的对象无关)必须有且只有一个定义,但它可以有多个extern声明。
定义是一种特殊的声明,它创建了一个对象;声明简单地说明了在其他地方创建的对象的名字,它允许你使用这个名字。
区分:
声明相当于普通的声明:它所说明的并非自身,而是描述其他地方创建的对象;
定义相当于特殊的声明:它为对象分配内存。
extern对象声明告诉编译器对象的类型和名字,对象的内存分配则在别处进行。
(2)左值在编译时可知,左值表示存储结果的地方;右值直到运行时才知,如无特别说明,右值表示“XX的内容”。(数组名是个左值但不是可修改的左值)。
编译器为每个变量分配一个地址(左值),这个地址在编译时可知,而且该变量在运行时一直保存于这个地址。相反,存储于变量中的值(它的右值)只有运行时才可知。如果需要用到变量中存储的值,编译器就发出指令从指定地址读入变量值并将它存于寄存器中。
(3)数组和指针的区别
(4)数组和指针都可以在它们的定义中用字符串常量进行初始化。表面一样,底层机制却不同。
a. 定义指针时,编译器并不为指针所指向的对象分配空间,它只是分配指针本身的空间,除非在定义时同时赋给指针 一个字符串常量进行初始化。如,下面的定义创建了一个字符串常量(为其分配了内存):
char *p = "breadfruit";
注意只有对字符串常量才是如此。不能指望为浮点数之类的常量分配空间,如:
float *pip = 3.141; /*错误,无法通过编译*/
在ANSI C中,初始化指针时所创建的字符串常量被定义为只读。如果试图通过指针修改这个字符串的值,程序就 会出现未定义的行为。在有些编译器中,字符串常量被存放在只允许读取的文本段中,以防止它被修改。
b. 数组也可以用字符串常量进行初始:
char a[] = "gooseberry";
与指针相反,由字符串常量初始化的数组是可以修改的。其中的每个字符在以后可以改变,如:
strncpy(a, "black", 5);
就将数组的值修改为“blackberry”。