我需要对指针数组进行一些解释,更准确,如何声明它们。
看看这段代码:
main()
{
int array[] = {5, 4, 2};
int array2[] = {6, 8};
int* int_arrays[2] = {array, array2}; // It works!
// int* int_arrays2[2] =
// {
// {5, 4, 2},
// {6, 8}
// };
//
int i, j;
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++) // This loop print a garbage value at the end, no big deal.
printf("%d\n", int_arrays[i][j]);
}
}
对我来说,评论的声明与上面的声明相同。但它不起作用。
Visual Studio C编译器给我这些指示:
错误:初始化程序太多。
警告:int *与int的间接级别不同。
我想这意味着int array[] = {5, 4, 2}
是有效分配给int*
的东西
虽然{5, 4, 2}
不是。{
你能告诉我一种方法来正确识别我的指针数组吗?
答案 0 :(得分:5)
数组初始值设定项不是对象,因此您无法指向此类对象的开头。如果你有至少C99,你可以做
int* int_arrays2[2] =
{
(int[]){5, 4, 2},
(int[]){6, 8}
};
这些是所谓的&#34;复合文字&#34;它们是对象,因此在这种情况下会转换为您需要的指针类型。
答案 1 :(得分:3)
声明
int* int_arrays[2]
将变量int_arrays
声明为两个指向int
的指针的数组。并且您初始化数组以在&#34中包含两个指向int
的指针;它可以正常工作&#34;码。请记住,数组会自然地衰减到指向第一个元素的指针,例如,int
数组可以在预期int *
的位置使用。
但是,您不能使用数组初始值设定项列表(如{ 5, 4, 2}
)作为指针,因为它不是。这就是为什么您注释掉的代码无法构建的原因。您可以在声明时使用数组数组,因为这是您初始化它的方式:
char int_array_of_arrays[2][3] = { ... };
重要的不是数组数组,而是数组到指针的衰减:An array of arrays is not the same as a pointer to pointer。
至于&#34;垃圾&#34;问题,这是因为你试图打印只包含两个元素的数组的第三个元素。 C没有任何边界检查,如果你试图将一个数组索引越界,你将有未定义的行为。
答案 2 :(得分:2)
考虑第一个声明
int* int_arrays[2] = {array, array2};
这是initilaizer列表包含两个表示数组名称的表达式。表达式中使用的数组被隐式转换为指向其第一个元素的指针。
事实上,这个声明等同于以下
int* int_arrays[2] = { &array[0], &array2[0] };
考虑到int_arrays
被声明为具有两个元素的数组,因此使用两个初始值设定项来初始化数组的元素。
您可以将初始化程序列表与多个初始化程序一起使用来初始化聚合:数组和结构。
如果使用标量值,则相应的初始化列表可能只有一个初始值设定项。考虑
int x = { 10 }; // Okey
int y = ( 10, 20 }; // compiler error
现在考虑一下这个宣言
int* int_arrays2[2] =
{
{5, 4, 2},
{6, 8}
};
在此声明中,数组int_arrays2
与以前一样只包含两个元素。数组的每个元素都是int *
类型的标量对象。初始化在语义上等同于以下
int *p1 = {5, 4, 2};
int *p2 = {6, 8};
其中p1
和p2
对应int_arrays2[0]
和int_arrays2[1]
。
它们是标量对象,正如上面所指出的那样,只能通过带有一个初始值设定项的初始化列表初始化。
因此编译器会发出错误。
另一方面,你可以写
而不是这个错误的声明int* int_arrays2[2] =
{
( int[] ){5, 4, 2},
( int [] ){6, 8}
};
这里使用了所谓的复合文字,它可以创建指定类型的未命名数组。因此在左侧有一个包含两个元素的数组,在右侧有一个初始化列表,其中包含两个初始化器,复合文字,转换为指向创建的未命名数组的第一个元素的指针。
这样的初始化是正确的。