如何在C语言中通过指针传递二维数组?

44

我正在学习C语言,但在将一个二维数组的指针传递给另一个函数并打印出该二维数组时遇到了麻烦。希望能得到帮助。

int main( void ){
    char array[50][50];
    int SIZE;

    ...call function to fill array... this part works.

    printarray( array, SIZE );
}

void printarray( char **array, int SIZE ){
    int i;
    int j;

    for( j = 0; j < SIZE; j++ ){
        for( i = 0; i < SIZE; i ++){
            printf( "%c ", array[j][i] );
        }
        printf( "\n" );
    }
}

1
void printarray( char array[][50], int SIZE ) - Lucas
1
虽然这是可能的,但最好将其转换为一维数组,并使用 j*SIZE+i 进行索引。 - Dave
@Dave 为什么?................................(只是填充语) - kotlomoy
1
@kotlomoy 因为 C 语言的 n-D 数组语法最多是模糊不清的,手动索引它会强制你考虑内存顺序(通常有助于缓存性能)。此外,这意味着您可以无缝地切换到使用动态大小的数组(通过 malloc)来实现。 - Dave
5个回答

38

char **并不代表一个二维数组 - 它将是一个指向指针的指针数组。如果你想传递一个二维数组,你需要改变printarray的定义:

void printarray( char (*array)[50], int SIZE )

或等价地:

void printarray( char array[][50], int SIZE )

1
你能用通俗易懂的语言解释一下 "char *array[50]" 这个语法的含义吗? - user1362058
3
运行 cdecl explain 'char (*arr)[50]' 将得到结果 declare arr as pointer to array 50 of char,意思是“声明 arr 为指向包含50个 char 元素的数组的指针”。 - Carl Norum
1
@user1362058:不,没有发生任何复制(除了指针)。你不能将数组传递给函数;它们会降级为指向它们第一个元素的指针。你的问题在于你的类型声明是错误的。一个二维数组会降级为指向另一个数组的指针。 - Ed S.
2
很棒的回答。char (*array)[50]声明了一个指针,名为array,指向一个包含50个字符的一维数组。我认为注释中的解释有点模糊,所以想做出改进。 - KeyC0de
2
@Jarkid,前者是指向一个50元素数组的指针,而后者是一个包含50个指针的数组。 - Carl Norum
显示剩余6条评论

11

main()函数中,变量"array"被声明为

char array[50][50];

这是一段2500字节的数据。当main()中的“array”被传递时,它是指向该数据开头的指针。它是一个指向char的指针,预期按照50行组织。

然而在函数printarray()中,你声明

 char **array

这里的“array”是指向char *pointer的指针。

@Lucus 建议的 void printarray(char array[][50], int SIZE) 是可行的,但它不够通用,因为您的 SIZE 参数必须为 50。

想法:在 printarray() 中克服(yeech)参数数组的类型。

void printarray(void *array, int SIZE ){
    int i;
    int j;
    char *charArray = (char *) array;

    for( j = 0; j < SIZE; j++ ){
        for( i = 0; i < SIZE; i ++){
            printf( "%c ", charArray[j*SIZE + i] );
        }
        printf( "\n" );
    }
}

一种更优雅的解决方案是将main()中的"数组"变成指针数组。

// Your original printarray()
void printarray(char **array, int SIZE ){
    int i;
    int j;
    for( j = 0; j < SIZE; j++ ){
        for( i = 0; i < SIZE; i ++){
            printf( "%c ", array[j][i] );
        }
        printf( "\n" );
    }
}

// main()
char **array;
int SIZE;
// Initialization of SIZE is not shown, but let's assume SIZE = 50;
// Allocate table
array = (char **) malloc(SIZE * sizeof(char*));
  // Note: cleaner alternative syntax
  // array = malloc(sizeof *array * SIZE);
// Allocate rows
for (int row = 0; row<SIZE; row++) {
  // Note: sizeof(char) is 1. (@Carl Norum)
  // Shown here to help show difference between this malloc() and the above one.
  array[row] = (char *) malloc(SIZE * sizeof(char));
    // Note: cleaner alternative syntax
    // array[row] = malloc(sizeof(**array) * SIZE);
  }
// Initialize each element.
for (int row = 0; row<SIZE; row++) {
  for (int col = 0; col<SIZE; col++) {
    array[row][col] = 'a';  // or whatever value you want
  }
}
// Print it
printarray(array, SIZE);
...

3
只是因为这个语句是可以这样做,不意味着你必须无情地用1替换它(或者完全删除它)。使用 sizeof 语句可以在很大程度上使您的代码自我说明。 - Thomas
@Thomas,如果你想让你的代码自我记录,你可以做到不冗余。例如使用sizeof **array。这样,即使以后更改数据类型,你也可以免费获得大小调整。 - Carl Norum
3
数组维度在传递给函数时不需要固定;例如,可以声明一个函数 void printarray(size_t Rows, size_t cols, char array[][cols])。(我不知道为什么这个已经在标准中存在了14年后还不是很有名。) - Eric Postpischil
@Eric Postpischil:使用“void printarray(size_t Rows, size_t cols, char array[][cols]);”声明函数会导致我的编译器失败。这是对您建议的正确测试吗? - chux - Reinstate Monica
@chux: 在其他人提供帮助之前,您需要指定“我的编译器”是什么。是GCC?Clang?某个微软的东西?出现了什么错误消息?有些编译器可能默认使用旧的语言版本(例如GCC的c89)或非标准的版本(例如gnu89)。对于GCC或clang,请尝试使用“-std=c99”或“-std=c1x”。对于Microsoft编译器,请尝试使用GCC或clang。您是否包含了<stdlib.h>以定义size_t?(您可以在声明中使用其他整数类型来表示维度;它可以是int而不是size_t。) - Eric Postpischil
显示剩余2条评论

5

由于C99支持动态大小数组,以下样式更方便传递2维数组:

void printarray( void *array0, int SIZE ){
    char (*array)[SIZE] = array0;
    int i;
    int j;
    for( j = 0; j < SIZE; j++ ){
        for( i = 0; i < SIZE; i ++){
            printf( "%c ", array[j][i] );
        }
        printf( "\n" );
    }
}

1
这是我喜欢的答案,因为它适用于在编译时不知道大小的情况。但是,我想做两个注释:(1)如果你传递了两个维度大小(比如行和列),那么 array 应该声明为 char (*array)[columns] = array0;(2)如果你使用了 const correctness(在这种情况下,你没有更改数组中的任何值,所以它是合适的),那么你需要将 array0 参数声明为 const void *array0,并在函数体中将 array 声明为 char const (*array)[columns] = array0; - Tynach
1
一个不需要 char (*array)[SIZE] = array0; 的干净的替代方法是 printarray(int SIZE, char array[SIZE][SIZE]) - chux - Reinstate Monica

2

这里没有我所寻找的答案,因此我将发布我解决问题的简单方法。

#include <iostream>

using namespace std;

void example(int* mat, int dim0, int dim1){
    
    for(int i = 0; i < dim0; ++i) {
         for(int j = 0; j < dim1; ++j) {
             auto cur_index = i * dim1 + j;
            cout<< *(mat + cur_index) << endl;
        }
    }
}

int main()
{
    const int dim0 = 3;
    const int dim1 = 2;

    int mat[dim0][dim1];
    
    for(int i = 0; i < dim0; ++i) {
         for(int j = 0; j < dim1; ++j) {
            mat[i][j] = i * dim1 + j;
        }
    }
    
    example(&(mat[0][0]), dim0, dim1);
    return 0;
}

-2

您可以使用双指针轻松传递二维数组。

  void printarray( char **array, int n)
  {
     int i, j;
     for(i=0; i<n; i++ )
     {
         for(j=0; j<n; j++)
         {
            printf("%c ", array[i][j] );
         }
        printf( "\n" );
     }
  }

  int main()
  {
      int n = 2;
      int i, j;

      char **array = (char **) malloc(n * sizeof(char*));

      for (i=0; i<n; i++) 
      {
        array[i] = (char *) malloc(n* sizeof(char));
      }

     for (i=0; i<n; i++)
     {
       for (j=0; j<n; j++)
       {
           scanf("%c ", &array[i][j]);
       }
     }

     printarray(array, n);

     return 0;
  }

完整代码:Ideone

1
你的答案中没有数组。 - Fredrik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接