英文:
Allocating a 2D array of structures
问题
我想分配一个二维数组,其元素是我的自定义类型 "cell" 的结构体。但是,我做错了什么,看看我的代码。你能告诉我我的错误在哪吗?
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
  int variable_1;
  int variable_2;
  int variable_3;
} cell;
void initialiseArray(unsigned long rows, unsigned long columns, cell array[rows][columns])
{
  for (int i = 0; i < rows; i = i + 1)
    for (int j = 0; j < columns; j = j + 1)
    {
      array[i][j].variable_1 = 0;
      array[i][j].variable_2 = 0;
      array[i][j].variable_3 = 0;
    }
}
int main()
{
  unsigned long rows = 200;
  unsigned long columns = 250;
  cell* array[rows];
  for (unsigned long i = 0; i < rows; i = i + 1)
    array[i] = malloc(columns * sizeof(cell));
  if (array == NULL)
  {
    printf("Error in \"main\": Memory could not be allocated.\n");
    return 3;
  }
  initialiseArray(rows, columns, array);
  return 0;
}
英文:
I want to allocate a 2D array of my custom type "cell", which is a structure. However, I am doing something wrong, see my code below. Could you please tell me where my mistake is?
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
  int variable_1;
  int variable_2;
  int variable_3;
} cell;
void initialiseArray(unsigned long rows, unsigned long columns, cell array[rows][columns])
{
  for (int i = 0; i < rows; i = i + 1)
    for (int j = 0; j < columns; j = j + 1)
    {
      array[i][j].variable_1 = 0;
      array[i][j].variable_2 = 0;
      array[i][j].variable_3 = 0;
    }
}
int main()
{
  unsigned long rows = 200;
  unsigned long columns = 250;
  cell* array[rows];
  for (unsigned long i = 0; i < rows; i = i + 1)
    array[i] = malloc(columns * sizeof(cell));
  if (array == NULL)
  {
    printf("Error in ""main"": Memory could not be allocated.\n");
    return 3;
  }
  initialiseArray(rows, columns, array);
  return 0;
}
答案1
得分: 6
cell* array[rows]; 是一个在栈上分配的可变长度数组(VLA);每一行都通过 array[i] = malloc(columns * sizeof(cell)); 在堆上分配。
我建议你要么在栈上,要么在堆上分配 array:
- 栈:
 
	cell array[rows][columns];
	初始化数组(rows, columns, array);
值得一提的是,你不能初始化 VLAs,所以你仍然需要 初始化数组()(或使用 memset())。在Linux上,默认的堆栈大小为8 MB,如果尝试使用超过这个大小,你的程序可能会导致段错误。
- 堆:
 
	cell (*array)[rows][columns] = malloc(sizeof *array);
	初始化数组(rows, columns, *array);
正如 @yano 提到的,你可以使用 calloc() 来对内存进行零初始化,因此不一定需要调用 初始化数组()。在Linux上,限制取决于可用的物理内存加上交换空间(例如,16 GB),如果尝试使用超过可用内存,malloc() / calloc() 将返回NULL,你可以轻松处理。
在这种情况下,两种方式都可以。如果 rows 和 columns 只在运行时知道,建议使用堆分配。
建议传递变量而不是 sizeof 的类型。
虽然 i 和 j 是完全有效的循环变量,但在这种情况下,考虑使用 r / row 或 c / col / column 更为合适。
英文:
cell* array[rows]; is a variable length array (VLA) that is allocated on the stack; each row is allocated on the heap with array[i] = malloc(columns * sizeof(cell));.
I suggest you either allocate the array on the stack or heap:
- Stack:
 
	cell array[rows][columns];
	initialiseArray(rows, columns, array);
You cannot initilaize VLAs, btw, so you still need initialiseArray() (or use memset()).  On Linux the default stack size is 8 MB, and if you try to use more than that your program will probably segfault.
- Heap:
 
	cell (*array)[rows][columns] = malloc(sizeof *array);
	initialiseArray(rows, columns, *array);
As @yano mentioned you can use calloc() to zero initialize your memory so you don't necessarily need to call initialiseArray().  On Linux the limit is whatever amount of free physical memory + swap (say, 16 GB), and if you try to use more than available malloc() / calloc() will return NULL which you can easily handle.
Either is in fine in this case.  If rows and columns are only known at run-time prefer heap allocation.
Prefer passing variable instead of a type of sizeof.
While i and j are perfectly valid loop variables consider using r / row or c / col / column in this case.
答案2
得分: 1
请看一下警告信息,您有许多问题,其中一些更为严重。最严重的问题是initialiseArray函数的array参数。当您将数组作为参数传递给函数时,它会“衰减”为指向第一个元素的指针。您有一个cell指针类型的数组,或者说cell*类型的数组。因此,这种类型的指针是cell**类型,所以您应该将参数更改为:
void initialiseArray(unsigned long rows, unsigned long columns, cell** array)
您应该修复的其他警告包括:
- 在
initialiseArray中将int与unsigned long进行比较。 - 检查
if (array == NULL)是没有意义的,因为它是自动存储中的数组,永远不会为NULL。相反,您应该检查if (array[i] == NULL),所以将该检查移到执行malloc的循环中。 
void initialiseArray(unsigned long rows, unsigned long columns, cell** array)
{
  for (unsigned long i = 0; i < rows; i = i + 1)
    for (unsigned long j = 0; j < columns; j = j + 1)
    {
      array[i][j].variable_1 = 0;
      array[i][j].variable_2 = 0;
      array[i][j].variable_3 = 0;
    }
}
int main(void)
{
  unsigned long rows = 200;
  unsigned long columns = 250;
  cell* array[rows];
  for (unsigned long i = 0; i < rows; i = i + 1)
  {
    array[i] = calloc(sizeof(cell), columns);
    if (array[i] == NULL)
    {
        printf("Error in \"main\": Memory could not be allocated.\n");
        return 3;
    }
  }
  initialiseArray(rows, columns, array);
  return 0;
}
但由于您将内存初始化为0,实际上根本不需要initialiseArray函数,只需使用calloc分配内存即可:
for (unsigned long i = 0; i < rows; i = i + 1)
{
  array[i] = calloc(sizeof(cell), columns);
  if (array[i] == NULL)
  {
    printf("Error in \"main\": Memory could not be allocated.\n");
    return 3;
  }
}
现在您的内存已被清零,无需自己编写函数。
最后,请不要忘记在程序结束时清理分配的内存,如果您选择这样做。
英文:
Take a look at the warnings, you have a number of issues, some more serious that others.  The most egregious violation is the array argument of initialiseArray.  When you pass an array to a function as an argument, it decays to a pointer to the first element.  You have an array of cell pointer types, or cell* types.  So a pointer to this type is a cell** type, so that's what you should change the argument to:
void initialiseArray(unsigned long rows, unsigned long columns, cell** array)
Additional warnings that you should fix:
- Comparing 
inttounsigned longininitialiseArray - Checking 
if (array == NULL)makes no sense, it's an array in automatic storage, it will never be NULL. Instead, you mean to checkif (array[i] == NULL), so move that check into the loop that's doing themallocing. 
void initialiseArray(unsigned long rows, unsigned long columns, cell** array)
{
  for (unsigned long i = 0; i < rows; i = i + 1)
    for (unsigned long j = 0; j < columns; j = j + 1)
    {
      array[i][j].variable_1 = 0;
      array[i][j].variable_2 = 0;
      array[i][j].variable_3 = 0;
    }
}
int main(void)
{
  unsigned long rows = 200;
  unsigned long columns = 250;
  cell* array[rows];
  for (unsigned long i = 0; i < rows; i = i + 1)
  {
    array[i] = calloc(sizeof(cell), columns);
    if (array[i] == NULL)
    {
        printf("Error in ""main"": Memory could not be allocated.\n");
        return 3;
    }
  }
  initialiseArray(rows, columns, array);
  return 0;
}
But since you're initializing your memory to 0, there's really no need for the initialiseArray function at all, simply allocate with calloc:
for (unsigned long i = 0; i < rows; i = i + 1)
{
  array[i] = calloc(sizeof(cell), columns);
  if (array[i] == NULL)
  {
    printf("Error in ""main"": Memory could not be allocated.\n");
    return 3;
  }
}
Now your memory is zeroized, no need to roll your own function.
Finally, don't forget to clean up your allocated memory if you so choose
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论