我的导师最近告诉C中的数组初始化有两种方式,即:
int a[5]={1,2,3,4,5};
scanf()
等int a[5], i; for(i=0;i<5;i++) scanf("%d", &a[i]);
在我看来,第二种方式&#34;是一种赋值而不是初始化的方式。所以我决定检查这里的人们对此有何看法。我偶然发现this帖子,其中一个答案声称:
如果您要询问的是术语(*不是很清楚 从你的问题),&#34;初始化&#34;变量的字面意思是 第一次为其分配值。这个词来自事实 你给变量它&#34;&#34; initial&#34;值。
这应该(显然)在第一次使用之前发生。
的便捷简写
int x=5;
是一个声明和初始化,实际上就是这样
int x; x=5;
如果我要遵循这个特定答案所声称的内容,那么第二种方式是&#34;初始化&#34;是正确的,因为在scanf()
语句之前没有赋值。但是,由于我对静态变量的了解,我脑子里出现了一个新的疑问。请考虑以下代码:
#include <stdio.h>
void first_way(){
static int x[2]={1,2};
printf("first_way called %d time(s)\n",++x[0]);
}
void second_way(){
int i;
static int x[2];
for(i=0;i<2;i++)scanf("%d",&x[i]);
printf("second_way called %d time(s)\n",++x[0]);
}
int main(void){
int i;
for(i=0;i<3;i++)
first_way();
printf("\n#######\n");
for(i=0;i<3;i++)
second_way();
return 0;
}
它的输出是这样的:
first_way called 2 time(s)
first_way called 3 time(s)
first_way called 4 time(s)
#######
1 2
second_way called 2 time(s)
1 2
second_way called 2 time(s)
1 2
second_way called 2 time(s)
此输出再次让我认为scanf()
版本更像是赋值版本而不是初始化,即使x[]
的元素没有值在scanf()
语句之前分配了。回到原点。
那么,第二个版本是否真的像我的导师声称的初始化或仅仅是一个任务(我相信)?
有人指出,我觉得我的static
数组示例很差,因为static
变量无论如何都隐式初始化为0。然后,有人向我指出const
变量。
考虑const int x = 2;
这里可以初始化x
,但在初始化后无法为其分配任何值。但这与声称的答案相矛盾(我再次引用它):
的便捷简写
int x = 5;
是一个声明和初始化,实际上就是这样int x; x=5;
所以,在这之后,scanf()
版本是否有资格作为初始化程序?
答案 0 :(得分:7)
在C标准中,只有选项(1)是初始化。
在编程术语中,两者都可以被认为是初始化。你的问题实际上是在询问单词的含义。
人们使用具有各种常见含义的单词是正常的,而不是为特定语言切换术语。另一个例子是“通过引用传递”。 C是否通过引用传递?有些人认为它只是通过价值传递,其他人则认为通过指针传递实现“通过引用传递”的概念。
然后我们可以讨论深拷贝与浅拷贝(C标准根本没有提到),或者术语“堆栈”和“堆”(C标准没有提到,但是常用)由C程序员),等等。
如果你说{ int b; b = 5; }
没有初始化(因为C标准说它不是),那么为了保持一致,你还应该说b
不是堆栈变量。
答案 1 :(得分:2)
这里有两个非常密切相关的概念。
初始值设定项是一种特定的句法结构。在声明中
int n = 42;
42
是初始值设定项。在声明中
n = 42;
42
不是initializer
; n = 42
在语法上是赋值表达式。
另一方面,标准也使用&#34;初始化&#34;引用初始值设定项以外的内容。例如,引用N1570第6.3.2.1节:
如果左值指定一个自动存储持续时间的对象 可以使用
register
存储类声明(从来没有 它的地址),并且该对象未初始化(未声明 使用初始化程序并且之前未执行任何赋值 使用),行为未定义。
因此,初始化程序始终是声明的一部分,而不是赋值 - 但如果使用初始化程序定义了一个对象,则称该对象是初始化,如果它是隐式初始化的,因为它是静态的,或者一个值已分配给它。
答案 2 :(得分:1)
1)声明
int a;
2)初始化
int a=10;
3)分配
a=10;
可以初始化阵列,但不能分配。
int arrA[3] = {1,3,2};
这将是非法的:
arrB = arrA;
答案 3 :(得分:1)
根据N1570 6.7.9.1:
initializer:
assignment-expression
{ initializer-list }
{ initializer-list , }
initializer-list:
designationopt initializer
initializer-list , designationopt initializer
designation:
designator-list =
designator-list:
designator
designator-list designator
designator:
[ constant-expression ]
. identifier
很明显,第二种方式并非实际&#34;初始化&#34;。但是,在大多数情况下,它在功能上与初始化相同。更重要的是,在指定存储在包含10000个元素的数组中的初始值时,您不想使用初始化列表。
答案 4 :(得分:-2)
你是对的,有点儿。使用“初始化”来引用这两种情况令人困惑,因为存在非常重要的区别。
您所称的“第一路”通常称为“静态初始化”。当您编写“static int x [2] = {1,2}”时,编译器将生成一个包含值“1,2”的数据块,然后初始化X以指向包含初始值的内存。因此,在代码中引用x [0]始终是安全的。
当您只编写“static int x [2]”时,编译器将为x保留内存,但您不知道该内存的初始化内容。一般来说,在使用x [0]之前,您的代码必须在该内存中写入内容。在复杂的应用程序或库中,特别是对于多个线程,确保x只被初始化一次并且只被初始化一次可能很棘手。
静态初始化始终是首选。