c语⾔数组初始化只能常量,C语⾔全局变量的初始化和字符串
常量
在C++中对于以下语句:
// 全局域
int i = 3;
int j = i;
编译时将i放⼊.data段,设置其值为3。⽽对于j,编译器遇到这种语句,只知道j = i,由于i是变量,不是常量,编译器⽆法在编译时直接得到它的值,编译器只会到i的地址, 然后读取这个地址的内容,再把这个内容写⼊j的地址。编译器不能够直接⽤3来初始化j,因为计算机不是⼈,不懂简单的⼈类逻辑,我们想“因为i = 3,⽽j = i,所以j = 3",⽽计算机⽆法在逻辑上由i = 3和j = i来推出j = 3,就好像图灵机不可能证明某个论题的真伪⼀样。
计算机只会“取i的地址,把3放到i的地址中,取i的地址,读取这个地址中的内容,取j的地址,把这个内容 写⼊j的地址。它不会思考,不懂因果,只是机械地执⾏指令。编译器⽆法在编译时求得⼀个⾮常量的
值,它只能在运⾏时通过读取变量地址来间接得到变量的值,⽽全局变量在编译时就必须确定其值,故C有静态存储区数据必须⽤常量初始化的规定。
在编译时只能⽤常量去初始化⼀个静态存储区的数据,⽽不能⽤“读取某个变量的内容”来初始化,所以编译器会将j放⼊.bss段,默认值为0,然后添加⼀条语句在运⾏时读取i的值,再赋给j。这条语句在调⽤main()之前完成。
⼀个对⽐:
对于语句:
int i = 3
int main()
{
int j = i;
...
}
在编译时不需要确定局部变量 j的值,⽽是在运⾏时读取i的值来赋给j.编译连接后的可执⾏⽂件中不会存放j的值,只有相应的赋值语句的代码。与此相对的,由于i是全局变量,存储在静态存储区,因此在编译时其值就需要确定其值,在⽬标⽂件中会分配空间来存放i的值,运⾏时不会有赋值语句来给i赋值, 没有对应的代码。
⽽对于语句:
数组定义时初始化int i = 3;
int j = i;
由于j是全局变量,存储在静态存储区,因此也需要在编译时确定其值。⽽i是变量,不是常量,i的值⽆法在编译时确定,这就造成j的值也⽆法在编译时确定,所以C对此就会报错,在gcc中报错为:initializer element is not constant,⽽C++采取了另外⼀种做法,在编译时简单的把j作为未初始化的全局变量放⼊.bss区,其默认值为0,然后添加⼀条语句在运⾏时给j赋值,并保证这条语句在main函数开始之前执⾏。因此j的初始化实际上实在运⾏时完成的。
在C99标准中有如下的描述:
All the expressions in an initializer for an object that has static storage duration shall be
constant expressions or string literals,既,所有⽤来初始化⼀个具有静态存储⽣命周期的对象的表达式应该是常量表达式或字符串字⾯值。
数组和指针的差别:
char heart[] = "I love Tillie!";
char *head = "I love Millie!";
差别在于:前者初始化⼀个字符数组的元素,既,将前者为定义⼀个数组,然后将数组的元素初始化为后⾯的字符串,⽽后者则是⼀个真正的字符串常量,这个指针被初始化为指向这个字符串常量的存储位置,⽽且数组名heart是个常量,⽽指针head是个变量。
在使⽤中都可以使⽤数组名或指针加法的形式将字符串输出。
但是 head = heart是可以的,
heart = head 是不可以的,因为heart为常量,就像3 = x是不可以的。
我们可以任意修改heart数组中的任何⼀个元素,但是不能修改head所指向的字符串,原因在于编译器可能选择内存中同⼀个内存单元的拷贝,来表⽰所有相同的字符串⽂字,既后者的实现⽅式不⼀定会分配⼀块内存存储字符串,head可能指向内存总已经有了相同字符串的内存的地址。例如,下⾯的语句都指向字符串“Klingon”的同⼀个单独的内存位置。
char *p1 = "Klingon";
p1[0] = 'F' //可以修改吗
printf("Klingon");
printf("be ware the %ss!\n","Klingon");
这既是说,编译器可以⽤相同的地址来代替每⼀个"Klingon"的实例。如果编译器使⽤这种单个拷贝表⽰⽅法并且允许把p1[0]修改为'F'的话,那么将影响到所有的对这个字符串的使⽤。于是,打印字符串"Klingon"的语句实际就会显⽰为"Flingon"。
实际上,有些个编译器确实是按照这种容易混淆的⽅式⼯作的,⽽其他⼀些这回产⽣异常的中断。因此建议的做法是初始化⼀个指向字符串⽂字的指针时使⽤const修饰符:
const char *p1 = "Klingon" //推荐⽤法,
⽤⼀个字符串⽂字来初始化⼀个⾮const的数组,这不会导致此类问题,以为数组会从最初的字符串得到⼀个拷贝。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论