从C中的现有1D数组创建2D数组?

时间:2015-07-27 12:47:12

标签: c arrays

在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

问题:

  1. 为什么我会收到编译警告以及如何修改代码以摆脱它们?
  2. 如果给定的C相当于backslashed perl版本,那么括号版本的等价物是什么(反之亦然)?
  3. 为什么我得到-1077371888而不是1?

6 个答案:

答案 0 :(得分:3)

您收到警告,因为初始化m23数组时,数组a1a2会衰减到指针,这样您就不会拥有数组数组但指针。通过将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};

初始化程序期望填充整数。基本上你用两个整数创建二维数组:a1a2。其余元素用零初始化。为了说明这一点,它看起来像:

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(在转换为指针后,指向数组的第一个元素)。换句话说,您将a1a2的地址隐含地转换为两个整数。实际上,这样的操作在C中是非法的,并且这样的代码甚至不应该使用-pedantic-errors标志(或等效的)进行编译。

  

括号版本的等价物是什么(反之亦然)?

相当于支撑版本是定义一个特定大小的多维数组,然后将a1a2数组的每个元素复制到其中:

#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)

  1.   

    为什么我会收到编译警告以及如何修改代码以摆脱它们?

  2. 这是因为你指定了一个指针(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]);
    }
    
    1.   

      如果给定C等效于backslashed perl版本,那么括号版本的等价物是什么(反之亦然)?

    2. 我不是Perl的专家,但我认为没有像某些类型那样简单的方法。正如您在Perl的输出中所看到的那样,您正在打印行和向量驻留在内存中的位置。 $ a1与$ m23_v1相同,因为它获得行的$ a1,但是在$ m23_v2中你实际上是从$ a2创建了另一个向量,因此内存位置发生了变化。

      1.   

        为什么我得到-1077371888而不是1?

      2. 那是因为你为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数组和多维数组。

另一种解决方案是将每个单个数组复制到多维数组的维度中。