int main()
{
int *a={1,2,3}; //which value is stored and where it is stored
printf("n%d",*a); //crashes here
}
请解释为什么上述内容崩溃。
发布的代码具有未定义的行为,因此它可以编译和执行,但结果是不可预测的。一种可能的结果是分段错误。
该行:
int *a={1,2,3};
尝试使用初始值设定项列表(包含太多元素;这应该生成警告)初始化指向int
的指针,但此初始值设定项列表不是数组。
一种解决方案是使用实际的数组:
int arr[] = { 1, 2, 3 };
int *a = arr;
这里arr[]
是不完整的数组类型。初始值设定项列表用于初始化数组arr[]
,当到达初始值设定项列表的末尾时,数组类型完成。现在a
是指向数组arr[]
的第一个元素的指针,其类型为int [3]
。
自 C99 以来可用的另一种选择是使用复合文字:
int *a = (int []) { 1, 2, 3 };
在这里,复合文本创建一个匿名数组,a
指向该数组的第一个元素。请注意,在发布代码的情况下,此匿名数组将具有自动存储持续时间,也就是说,它仅在程序执行在main()
块内时才存在。一般而言,根据C11标准草案§6.5.2.5 5
如果复合文本出现在函数主体之外,则对象具有静态存储持续时间;否则,它具有与封闭块关联的自动存储持续时间。
首先来自标准
initializer:
assignment-expression
{ initializer-list }
{ initializer-list , }
所以你正在使用初始值设定项列表。
从标准 6.7.9p11
标量的初始值设定项应为单个表达式,可以选择括在大括号中。对象的初始值是表达式的初始值(转换后);应用与简单赋值相同的类型约束和转换,将标量类型作为其声明类型的非限定版本。
就是这样。int *a={1,2,3}
不是法典。
但即使你尝试这样的事情
int *a = {1};
编译器将大约error: invalid conversion from 'int' to 'int*' [-fpermissive]
.
不过你可以这样做,(但你对此无能为力)
int *a = {(int*)1};
但是取消引用可能会导致未定义的行为。(即分段错误)。
int *a={1,2,3};
这里a
是一个指针,它期待一些有效的地址,程序员的工作是给它分配一些有效的地址,这样它就不能指向随机地址。
虽然它是未定义的行为,但这里a
是用第一个元素初始化的。 所以它看起来像
int *a = 1;
当您执行*a
时,它会崩溃,因为您正在尝试取消引用无效地址。
解决方案是首先动态分配内存,然后执行操作
int *a = malloc( 3 * sizeof(int));
a[0]= 1;
a[1]= 2;
a[2]= 3;
for(int i = 0 ;i< 3 ;i++) {
printf("n[%d]n",a[i]);
}
作业完成后释放内存以避免内存泄漏
free(a);
注意:初始值设定项列表{ }
不同于字符串文字" "
。
int *a = {1}; /* a didn't get any address */
int *a = "1"; /* a gets address*/