Malloc'ing 数组然后释放它们?
Malloc'ing Arrays and then Free'ing them?
我目前正在处理 c 我在指针使用和语法方面遇到了一些问题。
下面,我(尝试)创建一个指向整数数组的指针数组,然后将每个指针指向通过 malloc() 创建的数组。
创建数组后,我会循环遍历每个单元格,并分配一个值。
现在,所有这些似乎都有效,但是当使用 free() 收回内存时,程序崩溃了。
我注意到,如果我 malloc() 数组内存,然后立即对它们调用 free(),程序将毫无问题地执行。但是,当我 malloc()、分配值然后调用 free() 时,将发生崩溃。 (分段错误)。
下面是有效的代码,malloc() 然后立即 free()ing
int (*ptrArr[5])[5];
for(int i=0; i<5; i++)
ptrArr[i] = malloc(sizeof(int) * 5);
for(int i=0; i<5; i++)
printf("ptrArr[%d][%x]->[%x]\n", i, &ptrArr[i], &*ptrArr[i]);
printf("\n");
for(int i=0; i<5; i++){
for(int j=0; j<5; j++){
printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]);
}
printf("\n");
}
for(int i=4; i>=0; i--)
free(ptrArr[i]);
上面的代码按我的预期执行,但是当我为单元格赋值然后尝试调用 free 时,生成了分段错误:
int (*ptrArr[5])[5];
for(int i=0; i<5; i++)
ptrArr[i] = malloc(sizeof(int) * 5);
for(int i=0; i<5; i++)
printf("ptrArr[%d][%x]->[%x]\n", i, &ptrArr[i], &*ptrArr[i]);
printf("\n");
for(int i=0; i<5; i++){
for(int j=0; j<5; j++){
printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]);
}
printf("\n");
}
int loop = 5;
for(int i=0; i<5; i++){
for(int j=0; j<5; j++){
*ptrArr[i][j] = (loop + (i*j));
++loop;
}
}
printf("\n");
for(int i=0; i<5; i++){
for(int j=0; j<5; j++){
printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]);
}
printf("\n");
}
for(int i=4; i>=0; i--)
{
printf("Freeing ptrArr[%x]\n", i);
free(ptrArr[i]);
}
我想我要么误解了
int (*ptrArr[5])[5];
声明,我想要的是一个包含 5 个指针的数组,每个指针都指向一个整数数组,或者我没有正确地为单元格赋值,而是破坏了导致 free() 失败的内存。
如有任何帮助,我将不胜感激,我希望问题简明扼要。
谢谢。
嗯,解码起来很头疼,但就像一个很好的神秘填字游戏一样,有一个解决方案。我已经整理了一下。根本问题是取消引用。
参见:
Order of operations for dereference and bracket-ref in C
我在下面的一些工作代码中标记了该行。我在 (*ptrArr[i]) 周围添加了括号以获得数组,然后可以将其正确索引为 (*ptrArr[i])[j]。
我还建议了另一种声明数组的方法。一个更容易验证的!
#include <stdlib.h>
#include <stdio.h>
#define SIZE 5
int main()
{
// This makes things clearer :-
typedef int ArrayType[SIZE];
typedef ArrayType * ArrayPtr;
ArrayPtr ptrArr[SIZE];
for (int i = 0; i < SIZE; i++)
ptrArr[i] = malloc (sizeof (int) * SIZE);
int loop = SIZE;
for (int i = 0; i < SIZE; i++)
{
for (int j = 0; j < SIZE; j++)
{
// THIS NEXT LINE HAD THE WRONG BRACKETS IN
// *(ptrArr[i])[j] = (loop + (i * j));
(*ptrArr[i])[j] = (loop + (i * j));
printf("array has base address: %lx\n", ptrArr[i]);
printf("writing to: %lx\n", &(*ptrArr[i])[j]);
++loop;
}
}
for (int i = SIZE-1; i >= 0; i--)
{
printf ("Freeing ptrArr[%x] with address %lx\n", i, ptrArr[i]);
free (ptrArr[i]);
}
}
for(int i=0; i<5; i++)
ptrArr[i] = malloc(sizeof(int) * 5);
这表示 ptrArr[i]
是指向某些整数的指针。
*ptrArr[i][j] = (loop + (i*j));
这表示 ptrArr[i][j]
是一个指向整数的指针。
这是哪个?这两段代码的区别在于间接层数。
您的第一个示例不正确,因为您打印的数组索引不正确。
嵌套的for循环调用这个:
printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]);
第三个参数与ptrArr[i][j][0]
相同。
但这是不正确的。它应该是 ptrArr[i][0][j]
因为你用 malloc 调用只分配了二维数组的一个内部维度:ptrArr[i] = malloc(sizeof(int) * 5);
.
你看int (*ptrArr[5])[5];
实际上是一个指向5个整数数组的指针数组。 ptrArr[i]
是指向 5 个整数的数组的指针。
这也意味着与 ptrArr[i][j]
相同的第二个参数 &*ptrArr[i][j]
实际上应该是 ptrArr[i][0]
,因为同样,我们只分配了一个维度。
...
我们快完成了。首先用 calloc 替换 malloc 调用,这样我们就不会打印垃圾值。然后将 %x printf 说明符替换为 %p 并将它们各自的参数转换为 (void*).
通过这些更正,第一个示例打印出正确的地址和正确的值,并且没有未定义的行为。(您还可以删除多余的 &*
对)
(这只是对第一个示例的修复!我什至没有解决第二个示例。但解决方案基本相同。)
我处理这类问题的方法是打印出 sizeof
各种嫌疑人,就像这样
int (*test[5])[5];
printf( "%zu ", sizeof(test) );
printf( "%zu ", sizeof(test[0]) );
printf( "%zu\n", sizeof(test[0][0]) );
结果是40 8 20
。 (请注意,在我的机器上,int
是 4 个字节,指针是 8 个字节。)
所以这告诉我 test
是一个包含 5 个指针的数组。从逻辑上讲,test[0]
是一个指针。但有趣的是 test[0][0]
是一个包含 5 个整数的数组。
如果我添加下面这行代码
printf( "%zu\n", sizeof(test[0][0][0]) );
输出为4,即test[0][0][0]
是单个int
。由此我们得出结论,声明 int (*test[5])[5]
正在声明一个三维数组,这不是您想要的。
所以让我们尝试一个更简单的声明,像这样
int (*test)[5];
printf( "%zu ", sizeof(test) );
printf( "%zu ", sizeof(test[0]) );
printf( "%zu\n", sizeof(test[0][0]) );
输出的是8 20 4
,也就是说test
是一个单指针,test[0]
是一个5个int的数组,test[0][0]
是一个单指针int
。我们得出结论,int (*test)[5]
声明了一个二维数组。
接下来的问题是我们如何为数组分配内存。如果我们这样做
test = malloc( 5 * sizeof(int) );
然后我们就有了一个1行5列的数组,基本上是一个一维数组。
要得到一个有N
行的二维数组,我们需要
test = malloc( N * 5 * sizeof(int) );
然后我们可以像这样填充、打印和释放数组
int N = 5;
for ( int row = 0; row < N; row++ )
for ( int col = 0; col < 5; col++ )
test[row][col] = (row+5)*10 + col;
for ( int row = 0; row < N; row++ )
{
for ( int col = 0; col < 5; col++ )
printf( "%2d ", test[row][col] );
printf( "\n" );
}
free( test );
我目前正在处理 c 我在指针使用和语法方面遇到了一些问题。
下面,我(尝试)创建一个指向整数数组的指针数组,然后将每个指针指向通过 malloc() 创建的数组。
创建数组后,我会循环遍历每个单元格,并分配一个值。
现在,所有这些似乎都有效,但是当使用 free() 收回内存时,程序崩溃了。
我注意到,如果我 malloc() 数组内存,然后立即对它们调用 free(),程序将毫无问题地执行。但是,当我 malloc()、分配值然后调用 free() 时,将发生崩溃。 (分段错误)。
下面是有效的代码,malloc() 然后立即 free()ing
int (*ptrArr[5])[5];
for(int i=0; i<5; i++)
ptrArr[i] = malloc(sizeof(int) * 5);
for(int i=0; i<5; i++)
printf("ptrArr[%d][%x]->[%x]\n", i, &ptrArr[i], &*ptrArr[i]);
printf("\n");
for(int i=0; i<5; i++){
for(int j=0; j<5; j++){
printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]);
}
printf("\n");
}
for(int i=4; i>=0; i--)
free(ptrArr[i]);
上面的代码按我的预期执行,但是当我为单元格赋值然后尝试调用 free 时,生成了分段错误:
int (*ptrArr[5])[5];
for(int i=0; i<5; i++)
ptrArr[i] = malloc(sizeof(int) * 5);
for(int i=0; i<5; i++)
printf("ptrArr[%d][%x]->[%x]\n", i, &ptrArr[i], &*ptrArr[i]);
printf("\n");
for(int i=0; i<5; i++){
for(int j=0; j<5; j++){
printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]);
}
printf("\n");
}
int loop = 5;
for(int i=0; i<5; i++){
for(int j=0; j<5; j++){
*ptrArr[i][j] = (loop + (i*j));
++loop;
}
}
printf("\n");
for(int i=0; i<5; i++){
for(int j=0; j<5; j++){
printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]);
}
printf("\n");
}
for(int i=4; i>=0; i--)
{
printf("Freeing ptrArr[%x]\n", i);
free(ptrArr[i]);
}
我想我要么误解了
int (*ptrArr[5])[5];
声明,我想要的是一个包含 5 个指针的数组,每个指针都指向一个整数数组,或者我没有正确地为单元格赋值,而是破坏了导致 free() 失败的内存。
如有任何帮助,我将不胜感激,我希望问题简明扼要。
谢谢。
嗯,解码起来很头疼,但就像一个很好的神秘填字游戏一样,有一个解决方案。我已经整理了一下。根本问题是取消引用。
参见: Order of operations for dereference and bracket-ref in C
我在下面的一些工作代码中标记了该行。我在 (*ptrArr[i]) 周围添加了括号以获得数组,然后可以将其正确索引为 (*ptrArr[i])[j]。
我还建议了另一种声明数组的方法。一个更容易验证的!
#include <stdlib.h>
#include <stdio.h>
#define SIZE 5
int main()
{
// This makes things clearer :-
typedef int ArrayType[SIZE];
typedef ArrayType * ArrayPtr;
ArrayPtr ptrArr[SIZE];
for (int i = 0; i < SIZE; i++)
ptrArr[i] = malloc (sizeof (int) * SIZE);
int loop = SIZE;
for (int i = 0; i < SIZE; i++)
{
for (int j = 0; j < SIZE; j++)
{
// THIS NEXT LINE HAD THE WRONG BRACKETS IN
// *(ptrArr[i])[j] = (loop + (i * j));
(*ptrArr[i])[j] = (loop + (i * j));
printf("array has base address: %lx\n", ptrArr[i]);
printf("writing to: %lx\n", &(*ptrArr[i])[j]);
++loop;
}
}
for (int i = SIZE-1; i >= 0; i--)
{
printf ("Freeing ptrArr[%x] with address %lx\n", i, ptrArr[i]);
free (ptrArr[i]);
}
}
for(int i=0; i<5; i++)
ptrArr[i] = malloc(sizeof(int) * 5);
这表示 ptrArr[i]
是指向某些整数的指针。
*ptrArr[i][j] = (loop + (i*j));
这表示 ptrArr[i][j]
是一个指向整数的指针。
这是哪个?这两段代码的区别在于间接层数。
您的第一个示例不正确,因为您打印的数组索引不正确。
嵌套的for循环调用这个:
printf("[%x](%2d) | ", &*ptrArr[i][j], *ptrArr[i][j]);
第三个参数与ptrArr[i][j][0]
相同。
但这是不正确的。它应该是 ptrArr[i][0][j]
因为你用 malloc 调用只分配了二维数组的一个内部维度:ptrArr[i] = malloc(sizeof(int) * 5);
.
你看int (*ptrArr[5])[5];
实际上是一个指向5个整数数组的指针数组。 ptrArr[i]
是指向 5 个整数的数组的指针。
这也意味着与 ptrArr[i][j]
相同的第二个参数 &*ptrArr[i][j]
实际上应该是 ptrArr[i][0]
,因为同样,我们只分配了一个维度。
...
我们快完成了。首先用 calloc 替换 malloc 调用,这样我们就不会打印垃圾值。然后将 %x printf 说明符替换为 %p 并将它们各自的参数转换为 (void*).
通过这些更正,第一个示例打印出正确的地址和正确的值,并且没有未定义的行为。(您还可以删除多余的 &*
对)
(这只是对第一个示例的修复!我什至没有解决第二个示例。但解决方案基本相同。)
我处理这类问题的方法是打印出 sizeof
各种嫌疑人,就像这样
int (*test[5])[5];
printf( "%zu ", sizeof(test) );
printf( "%zu ", sizeof(test[0]) );
printf( "%zu\n", sizeof(test[0][0]) );
结果是40 8 20
。 (请注意,在我的机器上,int
是 4 个字节,指针是 8 个字节。)
所以这告诉我 test
是一个包含 5 个指针的数组。从逻辑上讲,test[0]
是一个指针。但有趣的是 test[0][0]
是一个包含 5 个整数的数组。
如果我添加下面这行代码
printf( "%zu\n", sizeof(test[0][0][0]) );
输出为4,即test[0][0][0]
是单个int
。由此我们得出结论,声明 int (*test[5])[5]
正在声明一个三维数组,这不是您想要的。
所以让我们尝试一个更简单的声明,像这样
int (*test)[5];
printf( "%zu ", sizeof(test) );
printf( "%zu ", sizeof(test[0]) );
printf( "%zu\n", sizeof(test[0][0]) );
输出的是8 20 4
,也就是说test
是一个单指针,test[0]
是一个5个int的数组,test[0][0]
是一个单指针int
。我们得出结论,int (*test)[5]
声明了一个二维数组。
接下来的问题是我们如何为数组分配内存。如果我们这样做
test = malloc( 5 * sizeof(int) );
然后我们就有了一个1行5列的数组,基本上是一个一维数组。
要得到一个有N
行的二维数组,我们需要
test = malloc( N * 5 * sizeof(int) );
然后我们可以像这样填充、打印和释放数组
int N = 5;
for ( int row = 0; row < N; row++ )
for ( int col = 0; col < 5; col++ )
test[row][col] = (row+5)*10 + col;
for ( int row = 0; row < N; row++ )
{
for ( int col = 0; col < 5; col++ )
printf( "%2d ", test[row][col] );
printf( "\n" );
}
free( test );