【问题标题】:Passing a multidimensional array as a pointer to a function in C gives an unexpected result将多维数组作为指向 C 中函数的指针传递会产生意想不到的结果
【发布时间】:2015-01-14 16:28:57
【问题描述】:

我是 C 新手,我正在尝试编写一个函数来计算由 1 和 0 组成的矩阵中每一列的 1 的数量。这是我的代码:

#include <stdio.h>

void *countCols(int *output, int rows, int cols, int **matrix[5][5])
{
  /*(int *output) is the pointer which we want the output stored at.
   *(int rows) is the number of rows in our matrix. This is found to be 5 at runtime
   *(int cols) is the number of cols in our matrix. This is also found to be 5 at runtime.
   *(int **matrix[5][5]) is a matrix containing the 1's and 0's.
   */
  int colnum;
  int rownum;
  int counts[cols];
  for (colnum = 0; colnum < cols; colnum ++)
  {
    for (rownum = 0; rownum < rows; rownum ++)
    {
      counts[colnum] += matrix[rownum][colnum];
    }
  }
  /*
   *We store the result in output.
   */
  output = counts;
}

int main(int argc, char **argv)
{
  /*
   *First, we create our matrix.
   */
  int matrix[5][5] = {{0, 1, 1, 0, 1},
                      {1, 0, 1, 1, 0},
                      {1, 0, 0, 0, 1},
                      {0, 0, 1, 1, 1},
                      {1, 0, 1, 1, 0}};
  int *Cs;
  countCols(Cs, 5, 5, matrix); 
  /*Here, we tally up our 1's column by column.*/
  int i;
  printf("The column counts are:\n");
  for (i = 0; i < 5; i ++)
  {
    printf("%d\n", Cs[i]);
    /*Next, we print the counts on separate lines.*/
  }
  /*Finally, we return 0*/
  return 0;
}

所以,我期待:

The column counts are:
3
1
4
3
3

然而,令我惊讶的是,我得到了:

The column counts are:
1768709983
1935631202
1953653108
1767992671
1600061550

这里发生了什么?还值得注意的是,当我编译时,我收到了这些警告:

C.c In function 'countCols':
C.c:12.22: warning: assignment makes integer from pointer without a cast
        counts[colnum] += matrix[rownum][colnum];

C.c In function 'main':
C.c:27.23: warning: passing argument 4 of 'countCols' from incompatible pointer type
     countCols(Cs, 5, 5, matrix);

C.c:3:7: note: expected 'int ** (*)[5]' but argument is of type 'int (*)[5]'
 void *countCols(int *output, int rows, int cols, int **matrix[5][5])

任何建议将不胜感激。

编辑: 为了清楚起见,我将指向矩阵的指针而不是矩阵本身传递给 countCols。

【问题讨论】:

  • 注意警告。数组不是指针,指针不是数组,多维数组也不是指针指向的指针。 Link to relevant C-FAQ section(顺便说一句,是什么让您相信int **[5][5] 可以可能int ** 相同?)

标签: c function pointers gcc multidimensional-array


【解决方案1】:

我认为您的意思是以下函数声明:)

void countCols(int *output, int rows, int cols, int ( *matrix )[5] );

而不是

void *countCols(int *output, int rows, int cols, int **matrix[5][5]);

因为你这样称呼它

countCols(Cs, 5, 5, matrix); 

考虑到你没有分配指针Cs指向的内存

int *Cs;

但是在函数内部,你为它分配了一个本地数组的第一个元素的地址。

所以程序有未定义的行为。

你可以简单地写

int Cs[5];

并且在函数内部使用它而不是本地数组。

所以去掉本地数组的定义

  int counts[cols];

从函数中直接使用参数输出

【讨论】:

  • 这也可以解决问题,我喜欢这里有我的替代解决方案。 :) 但是,我认为您建议的原型仍然需要调整。检查我的答案。
  • 它依赖于matrix[5][5]等价于*(matrix + row)[col]*(*(matrix + row) + col)这一事实。从原型的角度来看,row 只是 0,而必须指定 col 索引,将语法减少到 *matrix[5](*matrix)[5] 以提高可读性。
  • @G。 Samaras 我不明白你在说什么“调音”。
  • @DavidC.Rankin 你的评论是针对我的吗?如果是这样,我不是那个意思,但我在谈论(Vlad)原型的返回类型。我觉得我们在这个问题上花费的时间比 OP 更多。 :P
  • 是的,弗拉德的原型是正确的。你所说的“调整”是什么意思?
【解决方案2】:

你的函数没有返回任何东西,所以返回类型应该是void,而不是void*

首先你的函数原型应该是这样的:

void countCols(int *output, int rows, int cols, int matrix[5][5])

虽然可以改进。

然后,在你做的函数体内:

output = counts;

您将指针设置为具有本地范围的数组,因此当函数终止时它将被取消分配。但是,您的指针 Cs 不会保留更改,因为它是按值传递给函数的。

改用动态分配,完成后不要忘记释放它。

使用动态分配,您的函数应该是这样的(注意原型与我上面建议的不同):

// Pass a pointer to the integer pointer for 'output'
void countCols(int **output, int rows, int cols, int matrix[5][5])
{
  int colnum;
  int rownum;
  // PERFORM DYNAMIC ALLOCATIONS and USE 'output', instead of 'count'
  *output = malloc(sizeof(int) * cols);
  for (colnum = 0; colnum < cols; colnum ++)
  {
    for (rownum = 0; rownum < rows; rownum ++)
    {
      (*output)[colnum] += matrix[rownum][colnum];
    }
  }

  // NO NEED FOR THIS
  // output = counts;
}

还有main,内存的调用和释放非常显着:

int main(int argc, char **argv)
{
  /*
   *First, we create our matrix.
   */
  int matrix[5][5] = {{0, 1, 1, 0, 1},
                      {1, 0, 1, 1, 0},
                      {1, 0, 0, 0, 1},
                      {0, 0, 1, 1, 1},
                      {1, 0, 1, 1, 0}};
  int *Cs = NULL;
  countCols(&Cs, 5, 5, matrix);
  /*Here, we tally up our 1's column by column.*/
  int i;
  printf("The column counts are:\n");
  for (i = 0; i < 5; i ++)
  {
    printf("%d\n", Cs[i]);
    /*Next, we print the counts on separate lines.*/
  }

  free(Cs);
  /*Finally, we return 0*/
  return 0;
}

附录

正如顺磁羊角面包所说:

“注意警告。数组不是指针,指针不是数组,多维数组不是指针。”

请务必仔细阅读 here 中的“数组和指针”部分。

【讨论】:

  • output = counts; 实际上不会产生悬空指针。 output 值的变化不会反映在调用者之外,因为它是被调用者本地的。如果 outputint ** 并且 OP 写了 *output = counts;,则会出现问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-18
  • 2013-11-18
  • 1970-01-01
相关资源
最近更新 更多