C中奇怪的malloc行为
Posted
技术标签:
【中文标题】C中奇怪的malloc行为【英文标题】:strange malloc behavior in C 【发布时间】:2009-10-12 12:18:58 【问题描述】:我正在尝试创建一个具有动态比例的矩阵并对其进行初始化 这是我用来分配内存和初始化的代码:
int **matrix;
//mem allocation
matrix=(int*)malloc(sizeof(int*)*mat_w);
for (i=0;i<mat_w;i++)
matrix[i]=(int)malloc(sizeof(int)*mat_h);
//init
for (i=0;i<mat_w;i++)
for (j=0;j<mat_h;j++)
matrix[i][j]=0;
这个,工作正常,问题是,如果我尝试创建一个 short 类型的矩阵 - 我在 init 第一次通过时遇到分段错误。
这是 C 语言问题还是我做错了什么?
short
类型矩阵的代码:
short **matrix;
//mem allocation
matrix=(short*)malloc(sizeof(short*)*mat_w);
for (i=0;i<mat_w;i++)
matrix[i]=(short)malloc(sizeof(short)*mat_h);
//init
for (i=0;i<mat_w;i++)
for (j=0;j<mat_h;j++)
matrix[i][j]=0;
P.S.:为了代码的清晰,我放弃了安全检查、索引变量和边界声明。
谢谢, 亚历克斯
【问题讨论】:
您是否真的在代码中将返回值从malloc
转换为整数类型(而不是指针)?此外,将代码缩进 4 个空格以将其格式化为代码。
您不想要 matrix=(int*) 或 =(short*) 吗?
啊,我明白了。格式化程序吃了多余的 * 字符。
循环中发生了什么?问题可能是初始化而不是分配。
请发布一个最小的可编译代码。它可以帮助我们帮助您。干杯!
【参考方案1】:
您对malloc()
返回值的强制转换无效。在第一种情况下它们应该是int**
和int*
,在第二种情况下应该是short**
和short*
。
当您将malloc()
的返回值强制转换为short
时,返回的指针将被截断以适合short
值,然后分配给short*
指针,从而产生指向无效的指针值内存位置。因此,您在尝试访问它时会遇到分段错误。
有了int
,你就走运了,因为在你的平台上很可能是sizeof(int)==sizeof(int*)
,所以malloc()
返回的指针转换为int
不会被截断,而且一切都在默默地工作。它很可能会在 64 位平台上以类似的方式崩溃。
应该是:
short **matrix;
matrix=(short**)malloc(sizeof(short*)*mat_w);
for (i=0;i<mat_w;i++)
matrix[i]=(short*)malloc(sizeof(short)*mat_h);
for (i=0;i<mat_w;i++)
for (j=0;j<mat_h;j++)
matrix[i][j]=0;
如果您的代码是纯 C(不是 C++),则可以省略强制转换,因为在 C 中从 void*
强制转换为任何其他指针类型都是有效的。
short **matrix;
matrix = malloc(sizeof(short*)*mat_w);
for (i=0;i<mat_w;i++)
matrix[i] = malloc(sizeof(short)*mat_h);
for (i=0;i<mat_w;i++)
for (j=0;j<mat_h;j++)
matrix[i][j]=0;
【讨论】:
在这种情况下,我更喜欢sizeof()
- sizeof(matrix)
和 sizeof(*matrix)
的替代使用在这里会更清楚。
另外,看在 Skeet 的份上,请检查 malloc()
没有返回 NULL
【参考方案2】:
您使用的是什么编译器,它不会对所有这些明显的错误大喊大叫?
gcc -Wall
使用此代码生成了 5 条警告消息。
#include <stdlib.h>
int main ()
int mat_w = 99;
int mat_h = 666;
int i;
int j;
int **imatrix;
short **smatrix;
//mem allocation
imatrix=(int*)malloc(sizeof(int*)*mat_w);
for (i=0;i<mat_w;i++)
imatrix[i]=(int)malloc(sizeof(int)*mat_h);
//init
for (i=0;i<mat_w;i++)
for (j=0;j<mat_h;j++)
imatrix[i][j]=0;
//mem allocation
smatrix=(short*)malloc(sizeof(short*)*mat_w);
for (i=0;i<mat_w;i++)
smatrix[i]=(short)malloc(sizeof(short)*mat_h);
//init
for (i=0;i<mat_w;i++)
for (j=0;j<mat_h;j++)
smatrix[i][j]=0;
return 0;
给我
malloc.c: In function 'main':
malloc.c:13: warning: assignment from incompatible pointer type
malloc.c:15: warning: assignment makes pointer from integer without a cast
malloc.c:22: warning: assignment from incompatible pointer type
malloc.c:24: warning: cast from pointer to integer of different size
malloc.c:24: warning: assignment makes pointer from integer without a cast
【讨论】:
【参考方案3】:你必须从这个错误中吸取教训。它说如下:永远不要转换“malloc”的结果。
此外,这是一个更大的良好实践准则的一部分,最好尽可能遵循:永远不要在代码中提及类型名称,除非在声明中。
这就是你的代码从一开始就应该是这样的
int **matrix;
matrix = malloc(mat_w * sizeof *matrix);
for (i = 0; i < mat_w; i++)
matrix[i] = malloc(mat_h * sizeof *matrix[i]);
for (i = 0; i < mat_w; i++)
for (j = 0; j < mat_h; j++)
matrix[i][j] = 0;
注意,为了在这个版本中从“int”切换到“short”,您只需要更改“matrix”的声明即可。
(当然,这段代码还有很多可以改进的地方,但我只是想解决错误的直接原因。)
【讨论】:
【参考方案4】:您正在将您的 int**
转换为 int*
malloc 的返回值(简称相同)。 malloc
应该这样使用:
matrix = (int**)malloc(sizeof(int*) * mat_w);
或
matrix = (short**)malloc(sizeof(short*) * mat_w);
矩阵内的每个分配都相同:
matrix[i] = (int*)malloc(sizeof(int) * mat_h);
或
matrix[i] = (short*)malloc(sizeof(short) * mat_h);
【讨论】:
【参考方案5】:是的,你做错了什么。
int *matrix;
表示matrix
是一个整数数组。如果你希望它是一个整数数组,你应该像这样声明它:
int **matrix;
//mem allocation
matrix=(int**)malloc(sizeof(int*)*mat_w);
for (i=0; i<mat_w; i++)
matrix[i]=(int*)malloc(sizeof(int)*mat_h);
//init
for (i=0; i<mat_w; i++)
for (j=0; j<mat_h; j++)
matrix[i][j]=0;
当然,如果你事先知道矩阵的维数,就这样做吧:
int matrix[mat_w][mat_h];
//init
for (i=0; i<mat_w; i++)
for (j=0; j<mat_h; j++)
matrix[i][j]=0;
【讨论】:
+1,关于第二个例子的说明,这里矩阵存储在堆栈上,有时如果矩阵足够大,编译器会拒绝在堆栈上创建它,并且有必要在堆上分配它。【参考方案6】:sizeof(int)
等于特定系统的总线宽度。您正在尝试将 32 位(或 64,具体取决于您的平台)地址值放入 16 位分配的内存中。
查看 Checkers 帖子中的第二个示例。这是正确且可取的内存分配方式。
【讨论】:
以上是关于C中奇怪的malloc行为的主要内容,如果未能解决你的问题,请参考以下文章