在perl中,我可以创建一维数组,然后从它们创建二维数组,方法如下:
@a1=(a,b,c)
@a2=(d,e,f)
@a3=(g,h,i)
@m23_v1=(\@a1,\@a2,\@a3)
这是另一种方式(假设@a1
,@a2
和@a3
与前一个示例相同):
@m23_v2=([@a1],[@a2],[@a3])
这两种方式之间的区别在于,当使用反斜杠时,更改$a[0][0]
也会更改$a1[0]
。另一方面,当使用括号时,会复制该值,因此更改$a[0][0]
不会更改$a1[0]
。 Bellow是变量的内存地址,应该澄清我的意思:
print \$a1[0]
SCALAR(0x2006c0a0)
print \$m23_v1[0][0]
SCALAR(0x2006c0a0)
print \$m23_v2[0][0]
SCALAR(0x2030a7e8)
如何在C中实现相同的目标?我试过以下代码:
# include <stdio.h>
int main(){
int a1[3] = {1,2,3};
int a2[3] = {4,5,6};
int m23[2][3] = {a1, a2};
printf("%d\n", a1[0]);
printf("%d\n", m23[0][0]);
}
但它给了我以下编译警告:
2d.c: In function ‘main’:
2d.c:4:3: warning: initialization makes integer from pointer without a cast [enabled by default]
2d.c:4:3: warning: (near initialization for ‘m23[0][0]’) [enabled by default]
2d.c:4:3: warning: initialization makes integer from pointer without a cast [enabled by default]
2d.c:4:3: warning: (near initialization for ‘m23[0][1]’) [enabled by default]
2d.c:5:3: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
执行后,C代码返回以下内容:
1
-1077371888
问题:
答案 0 :(得分:3)
您收到警告,因为初始化m23
数组时,数组a1
和a2
会衰减到指针,这样您就不会拥有数组数组但指针。通过将m23
声明为指针数组,这也是你解决问题的方法:
int *m23[2] = { a1, a2 };
答案 1 :(得分:2)
您可以使用指针数组来获得等效的反向版本(即@m23_v1
):
#include <stdio.h>
int main(void)
{
int a1[3] = {1,2,3};
int a2[3] = {4,5,6};
int *m23[2] = {a1, a2};
printf("%d\n", a1[0]);
printf("%d\n", m23[0][0]);
return 0;
}
在您的代码中:
int m23[2][3] = {a1, a2};
初始化程序期望填充整数。基本上你用两个整数创建二维数组:a1
,a2
。其余元素用零初始化。为了说明这一点,它看起来像:
int m23[2][3] = {0xaaee33, 0xaaee55, 0, 0, 0, 0};
实际上与:
相同int m23[2][3] = {{0xaaee33, 0xaaee55, 0}, {0, 0, 0}}; // two rows, three columns
但是,a1
不是整数。它是数组的名称,被隐式转换为int
(在转换为指针后,指向数组的第一个元素)。换句话说,您将a1
和a2
的地址隐含地转换为两个整数。实际上,这样的操作在C中是非法的,并且这样的代码甚至不应该使用-pedantic-errors
标志(或等效的)进行编译。
括号版本的等价物是什么(反之亦然)?
相当于支撑版本是定义一个特定大小的多维数组,然后将a1
和a2
数组的每个元素复制到其中:
#include <stdio.h>
#include <string.h>
int main(void)
{
int a1[3] = {1,2,3};
int a2[3] = {4,5,6};
int m23[2][3];
memcpy(m23 + 0, a1, sizeof(a1));
memcpy(m23 + 1, a2, sizeof(a2));
printf("%d\n", a1[0]);
printf("%d\n", m23[0][0]);
return 0;
}
答案 2 :(得分:1)
嗯,你不能使用其他数组初始化数组。你可以这样做:
int m[2][3] = {{1,2,3},{4,5,6}};
这是因为a1和a2被视为指向int的指针。 你可以使用指针数组:
int* m[2] = {a1,a2);
答案 3 :(得分:1)
为什么我会收到编译警告以及如何修改代码以摆脱它们?
这是因为你指定了一个指针(a1),它需要一个整数(m23,如果是int类型)没有适当的转换。
这是写它的一种方式:
#include <stdio.h>
#define N 2
#define M 3
int main(){
int a1[M] = {1,2,3};
int a2[M] = {4,5,6};
int* m23[N] = {a1, a2};
printf("%d\n", a1[0]);
printf("%d\n", m23[0][0]);
}
如果给定C等效于backslashed perl版本,那么括号版本的等价物是什么(反之亦然)?
我不是Perl的专家,但我认为没有像某些类型那样简单的方法。正如您在Perl的输出中所看到的那样,您正在打印行和向量驻留在内存中的位置。 $ a1与$ m23_v1相同,因为它获得行的$ a1,但是在$ m23_v2中你实际上是从$ a2创建了另一个向量,因此内存位置发生了变化。
为什么我得到-1077371888而不是1?
那是因为你为m23分配了指针a1的值,它是内存中的一个地址,当像一个整数一样打印时(printf(“%d \ n”),它的计算结果是int,这就是结果
答案 4 :(得分:1)
正如其他答案已经说明的那样,你可以创建一个指针数组来收集两个子数组。然而,它们确实没有复制,只是被引用(即像带有反斜杠的Perl片段)。
int *m23[] = {a1, a2};
在C中,您无法分配数组,也无法直接从另一个数组初始化数组。您必须手动复制它:
int a1[3] = {1,2,3};
int a2[3] = {4,5,6};
// Uninitialized array of sufficient size
int m23[2][3];
// Manual copy of both subarrays
memcpy(&m23[0], &a1, sizeof a1);
memcpy(&m23[1], &a2, sizeof a2);
与您的一条评论相关的旁注:数组不是指针,常量或其他。但是在大多数情况下,数组的名称可以衰减指向其第一个元素的指针。
数组到指针衰减的例外情况包括上面使用的sizeof
运算符:此处的结果为3 * sizeof(int)
,即数组的实际大小,而不是sizeof(int*)
。
答案 5 :(得分:1)
您必须考虑C语言用于在内存中存储多维数组的方式。
C是一种简单的语言,它认为在具有n维的数组中,只有最后一个定义了存在多少个真实对象,其他是重复它。即一个int int arr[10][5];
数组意味着我们有一个由5个整数组成的字符串,它在内存中重复10次。
如果我们添加更多维度,我们在内存中会有更多重复。即int arr[4][10][5];
表示我们有一个由5个整数组成的字符串,它们重复10次,连续累加50个整数,再次重复4次。最后,我们在内存中有一个200个整数的序列,代表一个3维整数数组。
现在C的一个黑暗面是缺少边界控制,这个数组可以用我们喜欢的任何索引来读取,哪个产品介于0到199之间。因此,当你声明一个多维数组时,允许编译器正确地解决元素,你应该给出所有尺寸,但最后一个。
现在有了你的问题,你可以使用一个联合来伪造数组混合:
union
{
struct
{
int a1[3];
int a2[3];
};
int m23[2][3];
} stTst = {1,2,3,4,5,6};
printf("%d\n", stTst.a1[0]);
printf("%d\n", stTst.m23[0][0]);
printf("%d\n", stTst.a2[2]);
printf("%d\n", stTst.m23[1][2]);
在这种情况下,我们使用C数组内存布局来创建两个modimensional数组和多维数组。
另一种解决方案是将每个单个数组复制到多维数组的维度中。