C中的多维数组数据类型

时间:2014-01-24 12:25:18

标签: c arrays

我试图在一个函数中创建一个二维数组,然后在其他地方使用它,但是我在任何地方都遇到了不兼容的指针类型。 (我知道,已经讨论了类似的主题,但仍然无法从现有的主板上清楚地看出来。)

所以这是故事:

我可以将数组传递给这样的函数(允许使用c99):

int func1(int N, int arr[][N]);
int main()
{
   int N=<something>,M=<something>;
   int array1[N][N];
   func1(N, array1);
}

我的理解是,array1实际上是一个指针(),虽然我不确定它的类型(与int *p相同还是其他?)

现在,问题是我试图通过使用一个函数来创建这个2-D数组(它将数组维度扫描到某个变量,为数组分配内存,用数据填充它,然后返回指针,将来使用),例如:

int *input_array(int *size_x,int *size_y)
{
    scanf("%d",size_x); //recieve array dimensions
    scanf("%d",size_y); //recieve array dimensions

    int *arr=malloc((*size_x)*(*size_y)*sizeof(int));
    if(!arr) return 0; //validate allocation success

    for(int i=0; i<(*size_x); i++) {
        for(int j=0; j<(*size_y); j++) {
            scanf("%d",arr[i][j]); //fill input data in to array  <- FAILS
        }
    }
    return arr; //return pointer to the start of arr[][]
}

scanf("%d",&arr[i][j]);行导致编译失败,原因是arr类型不兼容。

那么,我如何将int *p转换为与int arr[][]相同的类型(以及它的类型),以便我可以在程序的其他地方重用它?或者也许我为这件事创造了不同类型的分配?

提前致谢!

4 个答案:

答案 0 :(得分:2)

这可能会帮助您

if (( c = ( int** )malloc( N*sizeof( int* ))) == NULL )
{ /* error */ }

for ( i = 0; i < N; i++ )
{
  /* x_i here is the size of given row, need to
   *  multiply by sizeof( int )
   */
  if (( c[i] = ( int* )malloc( x_i )) == NULL )
  { /* error */ }

  /* probably init the row here */
}

答案 1 :(得分:1)

要使用可变长度数组(您已经使用它,并且它是C 1999的一部分但在C 2011中是可选的)执行此操作,请进行两项更改。在函数input_array内,更改malloc语句:

int *arr=malloc((*size_x)*(*size_y)*sizeof(int));

为:

int (*arr)[*size_y] = malloc(*size_x * sizeof *arr);

这将arr定义为指向*size_y int数组的指针,因此它就像一个数组数组,这是你想要的二维数组。

其次,由于arr是指向int数组的指针,因此不应将其作为int *返回,因此必须更改返回类型。不幸的是,由于您在编译时不知道数组的第二个维度,因此无法提前声明返回类型。因此,您必须以相同的格式将其退回malloc给您,void *

void *input_array(int *size_x, int *size_y)

然后input_array的调用者必须将它转换为适当类型的指针:

void *temporary = *input_array(&size_x, &size_y);
if (!temporary) HandleError;
int (*array)[size_y] = temporary;

还有另外两种方法可以处理二维数组。

一种是将空间分配为int(或其他元素)的一维数组,并使用您自己的算法将二维索引转换为一维(映射行i和列j到元素i*NumberOfColumns + j)。您可以编写小函数或预处理器宏来使索引看起来更好一些。这与使用可变长度数组时编译器完全相同,但它可用于不支持可变长度数组的编译器。

Stack Overflow上经常提出的另一种方法是创建一个指针数组并初始化它们以指向数组的行。因此,如果p是指向指针数组的指针,则p[i]是指针之一(因此它指向数组的一行),而p[i][j]是一个元素那一排。由于几个原因,这通常是一个糟糕的解决方案。一,它消耗更多空间。二,它需要额外的内存负载(以获得第二个指针)。三,它会干扰编译器的优化。

在后一点上,当你有一个可变长度数组或一个带有手动计算索引的一维数组时,编译器可以看到a[i][j]a[i+1][j]引用了不同的元素,所以它可以优化对这些元素的操作以并行执行。在指针方法中,a[i]a[i+1]是指向行的指针,并且编译器通常无法知道它们是指向同一行还是重叠行,这会阻止它优化使用{{1 }和a[i][j]

答案 2 :(得分:0)

首先是你得到的错误:你必须显式地将void *类型从malloc转换为int *:

int *arr= (int*) malloc((*size_x)*(*size_y)*sizeof(int));

其次,如果只分配一块RAM,则必须自己计算数组索引。例如:

arr[y*(*size_x)+x] = 123;

所以你必须为(* size_x)个int*个指针分配一个数组,然后你必须分配(* size_x)个数为{* 1}的数组,其大小为(* size_y)每个并将其指针存储到int数组中。然后,您可以使用int*表示法。

答案 3 :(得分:0)

我认为你需要一个指针数组,每个指针都分配一个整数数组。

int** makeTable(int size_x, int size_y){
    int z;
    int** table;
    /* get an array of pointers of length x */
    table = malloc(sizeof(int*) * size_x);
    for(z = 0; z < size_x; z++){
        /* call calloc to zero out an array */
        table[z] = calloc(sizeof(int), size_y);
    }
    return table;
}

然后您可以使用table[i][j]