Resizing a 2D array of structures

huangapple go评论61阅读模式
英文:

Resizing a 2D array of structures

问题

以下是您要翻译的代码部分:

我正在尝试编写一个名为`resizeArray`的函数,用于调整我的自定义类型`cell`的2D数组`array`的大小,如果无法分配足够的内存,则返回错误消息。但是,我的代码不起作用,但奇怪的是,我的编译器没有抛出警告。我怀疑`resizeArray`的返回指针类型不匹配。请告诉我我做错了什么?

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
  int variable_1;
  int variable_2;
  char character;
} cell;

unsigned long max(unsigned long a, unsigned long b)
{
  if (a >= b)
    return a;
  else
    return b;
}

void initialiseArray(unsigned long rows, unsigned long columns,
                     cell array[rows][columns])
{
  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].character = ' ';
    }
}

cell *resizeArray(unsigned long rows, unsigned long columns,
                  unsigned long *array_rows, unsigned long *array_columns,
                  cell array[*array_rows][*array_columns])
{
  if (rows > *array_rows || columns > *array_columns)
  {
    unsigned long new_array_rows = max(rows, *array_rows);
    unsigned long new_array_columns = max(columns, *array_columns);
    cell (*new_array)[new_array_rows][new_array_columns] = malloc(sizeof *new_array);
    if (new_array == NULL)
    {
      printf("Error in \"resize\": Memory could not be allocated.\n");
      return NULL;
    }
    else
      free(array);
    *array_rows = new_array_rows;
    *array_columns = new_array_columns;
    return new_array;
  }
}

int main(void)
{
  unsigned long array_rows = 10;
  unsigned long array_columns = 15;
  cell (*array)[array_rows][array_columns] = malloc(sizeof *array);
  if (array == NULL)
  {
    printf("Error in \"main\": Memory could not be allocated.\n");
    return 3;
  }
  cell *new_array = resizeArray(15, 15, &array_rows, &array_columns, *array);
  if (new_array == NULL)
    printf("Memory error. We stop the program.\n");
  return -1;
  array = new_array;
  initialiseArray(array_rows, array_columns, *array);
  return 0;
}

请注意,代码中存在一些问题,您可能需要进一步检查和修复以确保其正确运行。

英文:

I am trying to write a function resizeArray that resizes a 2D array array of my custom type cell and if not enough memory could be allocated returns an error message. However, my code does not work, but my compiler, strangely, does not throw a warning. It suspect that my returned pointer type of resizeArray is not fitting. Could you please tell me what I am doing wrong?

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
typedef struct
{
int variable_1;
int variable_2;
char character;
} cell;
unsigned long max(unsigned long a, unsigned long b)
{
if (a &gt;= b)
return a;
else
return b;
}
void initialiseArray(unsigned long rows, unsigned long columns,
cell array[rows][columns])
{
for (unsigned long i = 0; i &lt; rows; i = i + 1)
for (unsigned long j = 0; j &lt; columns; j = j + 1)
{
array[i][j].variable_1 = 0;
array[i][j].variable_2 = 0;
array[i][j].character = &#39; &#39;;
}
}
cell *resizeArray(unsigned long rows, unsigned long columns,
unsigned long *array_rows, unsigned long *array_columns,
cell array[*array_rows][*array_columns])
{
if (rows &gt; *array_rows || columns &gt; *array_columns)
{
unsigned long new_array_rows = max(rows, *array_rows);
unsigned long new_array_columns = max(columns, *array_columns);
cell (*new_array)[new_array_rows][new_array_columns] = malloc(sizeof *new_array);
if (new_array == NULL)
{
printf(&quot;Error in &quot;&quot;resize&quot;&quot;: Memory could not be allocated.\n&quot;);
return NULL;
}
else
free(array);
*array_rows = new_array_rows;
*array_columns = new_array_columns;
return new_array;
}
}
int main(void)
{
unsigned long array_rows = 10;
unsigned long array_columns = 15;
cell (*array)[array_rows][array_columns] = malloc(sizeof *array);
if (array == NULL)
{
printf(&quot;Error in &quot;&quot;main&quot;&quot;: Memory could not be allocated.\n&quot;);
return 3;
}
cell *new_array = resizeArray(15, 15, &amp;array_rows, &amp;array_columns, *array);
if (new_array == NULL)
printf(&quot;Memory error. We stop the program.\n&quot;);
return -1;
array = new_array;
initialiseArray(array_rows, array_columns, *array);
return 0;
}

答案1

得分: 3

以下是翻译好的部分:

在你的代码中存在多个问题:

  • main函数中,在分配失败后缺少大括号,导致后续代码被忽略。请将其更改为:
if (new_array == NULL) {
    printf("内存错误。我们停止程序。\n");
    return 1;
}
  • 函数resizeArray在数组不需要重新分配的情况下没有返回任何内容。你应该在函数末尾添加return &array[0][0];

  • 在相同的函数中,return new_array;存在类型不匹配。你可以使用return (void *)new_array;来消除警告,或者返回适当的类型return &(*new_array)[0][0];

  • main函数中,存储array = new_array;时存在相同的问题。你可以简单地写成array = (void *)new_array;,因为没有一种简单的方法来表示适当的强制转换。

但请注意,你的方法仍然令人困惑且容易出错:最后一个调用initialiseArray(array_rows, array_columns, *array)*array作为array_columns列和array_rows行的数组传递,这会导致它衰减为指向array_columns个整数数组的指针,但这在技术上是类型不匹配的,编译器不会捕捉到这个问题:array的类型仍然引用array_columnsarray_rows的原始值,而不是当前修改后的值,因此在main中使用*array来引用重新分配数组的单元格将会失败。

以下是修改后的版本,显示了该问题:

// 此处为示例代码

你可以考虑使用2D间接寻址来操作动态大小的矩阵。以下是使用单个矩阵的单个分配的修改版本:

// 此处为示例代码

输出:

// 此处为示例输出

希望这能帮助你理解代码中的问题。如果你需要进一步的帮助,请随时提问。

英文:

There are multiple problems in your code:

  • in function main there are missing braces after the test for allocation failure, causing the rest of the code to be ignored. Write this:

      if (new_array == NULL) {
    printf(&quot;Memory error. We stop the program.\n&quot;);
    return 1;
    }
    
  • function resizeArray does not return anything in case the array does not need to be reallocated. You should add return &amp;array[0][0]; at the end of the function.

  • in the same function, return new_array; is a type mismatch. You could silence the warning with return (void *)new_array; or return the appropriate type return &amp;(*new_array)[0][0];

  • in main, the same problem when storing array = new_array;. You can simply write array = (void *)new_array; as there is no easy way to express the appropriate cast.

Note however that your approach is confusing and error prone: the last call initialiseArray(array_rows, array_columns, *array) passes *array as an array of array_columns columns and array_rows rows, which decays to a pointer to arrays of array_columns ints, but this is technically a type mismatch that is not caught by the compiler: the type of array still refers to the original values of array_columns and array_rows, not the current modified ones, so using *array inside main to refer to the cells of the reallocated array will fail.

Here is a modified version displaying the problem:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
typedef struct
{
int variable_1;
int variable_2;
char character;
} cell;
unsigned long max(unsigned long a, unsigned long b)
{
if (a &gt;= b)
return a;
else
return b;
}
void initialiseArray(unsigned long rows, unsigned long columns,
cell array[rows][columns])
{
for (unsigned long i = 0; i &lt; rows; i = i + 1)
for (unsigned long j = 0; j &lt; columns; j = j + 1)
{
array[i][j].variable_1 = i;
array[i][j].variable_2 = j;
array[i][j].character = &#39; &#39;;
}
}
cell *resizeArray(unsigned long rows, unsigned long columns,
unsigned long *array_rows, unsigned long *array_columns,
cell array[*array_rows][*array_columns])
{
if (rows &gt; *array_rows || columns &gt; *array_columns)
{
unsigned long new_array_rows = max(rows, *array_rows);
unsigned long new_array_columns = max(columns, *array_columns);
cell (*new_array)[new_array_rows][new_array_columns] = malloc(sizeof *new_array);
if (new_array == NULL)
{
printf(&quot;Error in &quot;&quot;resize&quot;&quot;: Memory could not be allocated.\n&quot;);
return NULL;
}
else
{
free(array);
}
*array_rows = new_array_rows;
*array_columns = new_array_columns;
return &amp;(*new_array)[0][0];
}
return &amp;array[0][0];
}
void displayArray(unsigned long rows, unsigned long columns, cell array[rows][columns])
{
for (unsigned long row = 0; row &lt; rows; row++) {
for (unsigned long col = 0; col &lt; columns; col++) {
cell c = array[row][col];
printf(&quot; {%d,%d,&#39;%c&#39;},&quot;, c.variable_1, c.variable_2, c.character);
}
printf(&quot;\n&quot;);
}
}
int main(void)
{
unsigned long array_rows = 3;
unsigned long array_columns = 3;
cell (*array)[array_rows][array_columns] = malloc(sizeof *array);
if (array == NULL)
{
printf(&quot;Error in &quot;&quot;main&quot;&quot;: Memory could not be allocated.\n&quot;);
return 3;
}
cell *new_array = resizeArray(4, 5, &amp;array_rows, &amp;array_columns, *array);
if (new_array == NULL) {
printf(&quot;Memory error. We stop the program.\n&quot;);
return -1;
}
array = (void *)new_array;
initialiseArray(array_rows, array_columns, *array);
printf(&quot;Using displayArray:\n&quot;);
displayArray(array_rows, array_columns, *array);
printf(&quot;Same code from main:\n&quot;);
for (unsigned long row = 0; row &lt; array_rows; row++) {
for (unsigned long col = 0; col &lt; array_columns; col++) {
cell c = (*array)[row][col];
printf(&quot; {%d,%d,&#39;%c&#39;},&quot;, c.variable_1, c.variable_2, c.character);
}
printf(&quot;\n&quot;);
}
return 0;
}

Output:

Using displayArray:
{0,0,&#39; &#39;}, {0,1,&#39; &#39;}, {0,2,&#39; &#39;}, {0,3,&#39; &#39;}, {0,4,&#39; &#39;},
{1,0,&#39; &#39;}, {1,1,&#39; &#39;}, {1,2,&#39; &#39;}, {1,3,&#39; &#39;}, {1,4,&#39; &#39;},
{2,0,&#39; &#39;}, {2,1,&#39; &#39;}, {2,2,&#39; &#39;}, {2,3,&#39; &#39;}, {2,4,&#39; &#39;},
{3,0,&#39; &#39;}, {3,1,&#39; &#39;}, {3,2,&#39; &#39;}, {3,3,&#39; &#39;}, {3,4,&#39; &#39;},
Same code from main:
{0,0,&#39; &#39;}, {0,1,&#39; &#39;}, {0,2,&#39; &#39;}, {0,3,&#39; &#39;}, {0,4,&#39; &#39;},
{0,3,&#39; &#39;}, {0,4,&#39; &#39;}, {1,0,&#39; &#39;}, {1,1,&#39; &#39;}, {1,2,&#39; &#39;},
{1,1,&#39; &#39;}, {1,2,&#39; &#39;}, {1,3,&#39; &#39;}, {1,4,&#39; &#39;}, {2,0,&#39; &#39;},
{1,4,&#39; &#39;}, {2,0,&#39; &#39;}, {2,1,&#39; &#39;}, {2,2,&#39; &#39;}, {2,3,&#39; &#39;},

You might consider using 2D indirect addressing to manipulate dynamically sized matrixes. Here is a modified version using a single allocation per matrix:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
typedef struct {
int variable_1;
int variable_2;
char character;
} cell;
size_t max(size_t a, size_t b)
{
if (a &gt;= b)
return a;
else
return b;
}
cell **allocateArray(size_t rows, size_t cols)
{
/* allocate combined packed 2D matrix with an array of column pointers */
size_t head_size = (sizeof(cell **) * rows + sizeof(cell) - 1) / sizeof(cell);
cell **res = calloc(head_size + rows * cols, sizeof(cell));
if (res != NULL) {
for (size_t i = 0; i &lt; rows; i++)
res[i] = (cell *)res + head_size + i * cols;
}
return res;
}
void initialiseArray(size_t rows, size_t columns, cell **array)
{
for (size_t i = 0; i &lt; rows; i = i + 1) {
for (size_t j = 0; j &lt; columns; j = j + 1) {
array[i][j].variable_1 = i;
array[i][j].variable_2 = j;
array[i][j].character = &#39; &#39;;
}
}
}
cell **resizeArray(size_t rows, size_t columns,
size_t *array_rows, size_t *array_columns, cell ***arrayp)
{
cell **array = *arrayp;
if (rows &gt; *array_rows || columns &gt; *array_columns) {
size_t new_array_rows = max(rows, *array_rows);
size_t new_array_columns = max(columns, *array_columns);
cell **new_array = allocateArray(new_array_rows, new_array_columns);
if (new_array == NULL) {
printf(&quot;Error in &quot;&quot;resize&quot;&quot;: Memory could not be allocated.\n&quot;);
return NULL;
} else {
for (size_t i = 0; i &lt; *array_rows; i++) {
for (size_t j = 0; j &lt; *array_columns; j++) {
new_array[i][j] = array[i][j];
}
}
free(array);
}
*array_rows = new_array_rows;
*array_columns = new_array_columns;
return *arrayp = new_array;
}
return array;
}
void displayArray(size_t rows, size_t columns, cell **array)
{
for (size_t row = 0; row &lt; rows; row++) {
for (size_t col = 0; col &lt; columns; col++) {
cell c = array[row][col];
printf(&quot; {%d,%d,&#39;%c&#39;},&quot;, c.variable_1, c.variable_2, c.character);
}
printf(&quot;\n&quot;);
}
}
int main(void)
{
size_t array_rows = 3;
size_t array_columns = 3;
cell **array = allocateArray(array_rows, array_columns);
if (array == NULL) {
printf(&quot;Error in &quot;&quot;main&quot;&quot;: Memory could not be allocated.\n&quot;);
return 3;
}
initialiseArray(array_rows, array_columns, array);
printf(&quot;before resize:\n&quot;);
displayArray(array_rows, array_columns, array);
if (!resizeArray(4, 5, &amp;array_rows, &amp;array_columns, &amp;array)) {
printf(&quot;Memory error. We stop the program.\n&quot;);
return -1;
}
printf(&quot;after resize:\n&quot;);
displayArray(array_rows, array_columns, array);
free(array);
return 0;
}

Output:

before resize:
{0,0,&#39; &#39;}, {0,1,&#39; &#39;}, {0,2,&#39; &#39;},
{1,0,&#39; &#39;}, {1,1,&#39; &#39;}, {1,2,&#39; &#39;},
{2,0,&#39; &#39;}, {2,1,&#39; &#39;}, {2,2,&#39; &#39;},
after resize:
{0,0,&#39; &#39;}, {0,1,&#39; &#39;}, {0,2,&#39; &#39;}, {0,0,&#39;&#39;}, {0,0,&#39;&#39;},
{1,0,&#39; &#39;}, {1,1,&#39; &#39;}, {1,2,&#39; &#39;}, {0,0,&#39;&#39;}, {0,0,&#39;&#39;},
{2,0,&#39; &#39;}, {2,1,&#39; &#39;}, {2,2,&#39; &#39;}, {0,0,&#39;&#39;}, {0,0,&#39;&#39;},
{0,0,&#39;&#39;}, {0,0,&#39;&#39;}, {0,0,&#39;&#39;}, {0,0,&#39;&#39;}, {0,0,&#39;&#39;},

答案2

得分: 3

请参考 @chqrlie 的答案,详细评估您的代码。我只想回应这一点:

"> 我的代码不起作用,但是奇怪的是,我的编译器没有发出警告。"

编译器无法检测到您可能犯的每个错误,而且它没有义务诊断除语言形式约束的违规之外的任何事情。(对于其他任何情况,它应该能够生成代码。)

但是,我对您的说法表示怀疑。如果编译器没有诊断以下事实:

  • 您的 resizeArray() 函数可以在不返回值的情况下终止,
  • 您的 resizeArray() 函数可以返回其类型与函数声明的返回类型不匹配的值,
  • 您的 main() 包含不可访问的代码,以及
  • main 中的 array = new_array 包含类型不匹配

那么要么您的编译器不太好,要么您已禁用(某些)警告,要么以某种方式丢弃或错过了它实际上正在发出的诊断信息。

事实上,您的

在运行时也会包含类型不匹配,但鉴于这涉及到可变修改的类型,我不会真的期望编译器对其进行诊断。

英文:

Refer to @chqrlie's answer for a detailed critique of your code. I just want to address this:

> my code does not work, but my compiler, strangely, does not throw a warning.

The compiler cannot detect every possible thing you could do wrong, and it is not obligated to diagnose anything other than violations of the language's formal constraints. (And for anything else, it should be able to generate code.)

However, I'm skeptical of your claim. If the compiler does not diagnose the facts that

  • your resizeArray() function can terminate without returning a value,

  • your resizeArray() function can return a value whose type is mismatched with the function's declared return type,

  • your main() contains unreachable code, and

  • array = new_array in main contains a type mismatch

then either your compiler isn't very good, or you've disabled (some) warnings, or you're some other way discarding or missing diagnostics that it is, in fact, emitting.

As it turns out, your
>
&gt; initialiseArray(array_rows, array_columns, *array);
&gt;

will also contain a type mismatch at runtime, but inasmuch as this involves variably-modified types, I wouldn't really expect the compiler to diagnose it.

huangapple
  • 本文由 发表于 2023年5月21日 19:39:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76299726.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定