写入二维数组时出现分段错误
我的程序中有一个小的内存访问问题,但我没有找到错误,也许有人可以帮助我。
我创建了一个新类型来存储 RGB 颜色值。 该类型如下所示:
typedef struct pixel {
unsigned char r;
unsigned char g;
unsigned char b;
} pixel;
在我的主程序中,我使用 calloc 创建一个 2D 动态数组,以存储红色信息。
pixel **pixelvalue = (pixel **) calloc(imginformation.width, sizeof(pixel));
for (i = 0; i < imginformation.width; i++) {
pixelvalue[i] = (pixel *) calloc(imginformation.height, sizeof(pixel));
}
之后,我调用我的函数,该函数读取颜色值以及谁应该将它们安全地保存到数组中。该函数获取数组作为参数。
ReadFile(file, imginformation (Stuff like height and so one), pixelvalue (The calloc array));
在该函数中,我尝试用 Here 写入值
pixelvalue[i][j].r = (unsigned char)fgetc(in);
,但出现内存访问错误,我做错了什么?
编辑
嗨,首先很抱歉缺少语言,我昨天有点累了:)。
为了理解,我创建了一个像素数组,并且元素指向另一个像素数组?像[指向另一个一维数组像素]
之类的东西?
使用像素 **pixelvalue = calloc(imginformation.width, sizeof(pixel *));
我创建了 imginformation.width
个来自像素类型的指针,每个指针显示到像素, 正确的?
如果我错了,如果你能多解释一下,那就太好了。我真的很想了解它。
@carl-norum 你的意思是:
“您不应该强制转换 calloc() 的返回值。这样做可以 使用 #include 隐藏错误,这些错误可能会回来咬你一口 路”。
?我使用分配空间作为函数的参数,而不是作为返回值。
感谢您的帮助!
Greetz
I have a small memory access problem in my program and I do not find the error, maybe someone could help me.
I have created a new type to store rgb color values.
That type looks like:
typedef struct pixel {
unsigned char r;
unsigned char g;
unsigned char b;
} pixel;
In my main program I create with calloc a 2D dynamically array, to store the red color information’s.
pixel **pixelvalue = (pixel **) calloc(imginformation.width, sizeof(pixel));
for (i = 0; i < imginformation.width; i++) {
pixelvalue[i] = (pixel *) calloc(imginformation.height, sizeof(pixel));
}
After that I call my function, which read the color values and who should safe them to the array. The function gets as parameter the array.
ReadFile(file, imginformation (Stuff like height and so one), pixelvalue (The calloc array));
In that function I try to write the values with
pixelvalue[i][j].r = (unsigned char)fgetc(in);
Here I get the memory access error, what did I wrong?
Edit
Hi, first of all sorry about the missing language, I was a little bit tired yesterday :).
To understanding, I created an array of pixel and the elements are pointing to another array of pixel? Something like [Point to another 1D array pixel]
?
With pixel **pixelvalue = calloc(imginformation.width, sizeof(pixel *));
I create imginformation.width
numbers of pointers from type pixel and each pointer show to pixel, right?
It would be awesome if you could explain it a little bit more, if I’m wrong. I would really like to understand it.
@carl-norum What do you mean with:
"you shouldn't be casting the return values of calloc(). Doing so can
hide bugs with #include that could come back to bite you down the
road".
? I use the alloc space as parameter for a function, not as return value.
Thanks for your help!
Greetz
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您并不是真正创建一个二维数组,而是创建一个指向像素数组的指针数组。这意味着您的第一个
calloc
调用应该为指针分配足够的空间,而不是像素:您没有用语言标记您的问题,但假设它是 C (基于您的
typedef
,这在 C++ 中不是必需的),您不应该强制转换calloc()
的返回值。这样做可以隐藏#include
中的错误,这些错误可能会回来咬你一口。编辑:
您提出了几个后续问题。我认为其他几个答案已经很好地回答了第一个问题,但我会尝试总结一下。按照进行分配的方式,您首先要分配一个指针数组 - 每个指针都将指向数组的一行。然后需要分配行本身 - 每个像素对象的空间都存放在那里,并且指向行的指针存储在第一个指针数组中。
你的第二个问题,关于 calloc() 的返回值非常简单。如果您强制转换返回值,您可以隐藏自己的隐式声明错误。由于
calloc
的返回类型是void *
,如果您执行以下操作:一切都会正常工作。现在假设您没有包含
stdlib.h
,因此翻译单元中没有calloc()
原型。这将导致编译器假定calloc()
的签名为int calloc(int, int)
,但事实并非如此。上面的同一行代码会向您发出关于假设该函数的默认签名的警告。使用代码中的类型转换会掩盖该警告,并且您可能永远不知道您错过了#include
行。You're not really making a 2D array, you're making an array of pointers that point to arrays of pixels. That means your first
calloc
call should allocate enough space for pointers, not for pixels:You didn't tag your question with a language, but assuming it's C (based on your
typedef
, which wouldn't be necessary in C++), you shouldn't be casting the return values ofcalloc()
. Doing so can hide bugs with#include
that could come back to bite you down the road.Edit:
You asked a couple of follow-up questions. The first has been answered pretty well by several other answers, I think, but I'll try to summarize. The way you're doing the allocation, you are first going to allocate an array of pointers - each of those pointers is going to point to one row of your array. The rows themselves then need to be allocated - space for each
pixel
object goes there, and the pointers to the rows are stored in the first array of pointers.Your second question, bout the return value from
calloc()
is pretty straightforward. If you cast the return value, you can hide implicit declaration bugs from yourself. Since the return type ofcalloc
isvoid *
, if you do something like:Everything works nicely. Now imagine that you didn't include
stdlib.h
, and therefore had no prototype ofcalloc()
in your translation unit. That would lead the compiler to assume the signature ofcalloc()
to beint calloc(int, int)
, which isn't true. The same line of code above would throw you a warning about assuming a default signature for that function. Using a typecast like you have in your code will mask that warning and you might never know you were missing that#include
line.请参阅图表进行解释
因此,您首先创建
pixel * 数组
使用 calloc.使用calloc
和pixel
填充该数组。Please see the diagram for an explaination
So you first create the array of
pixel *
using calloc. Populate that array usingcalloc
withpixel
.代码
pixelvalue
是一个指向像素指针的指针——你的typedef。你需要写
。
The code
pixelvalue
is a pointer to a pointer to pixel - your typedef.You need to write
instead.
其他发帖者已正确识别出您应该以像素 * 为单位而不是以像素为单位分配第一个内存块。
但为什么这个问题会导致段错误呢?
在 32 位机器上,上面定义的像素结构占用 3 个字节,但指针占用 32 位(4 个字节)。
也就是说,
sizeof(pixel) == 3
sizeof(pixel*) == 4
所以您只分配了所需内存的 75%。当访问图像的底部四分之一时,您将访问从未分配的内存。
(在某些 64 位平台上,问题肯定只会变得更糟。在某些 16 位平台上,您也许可以摆脱这个问题,尽管它仍然很草率)
The other posters have correctly identified that you should be allocating your first block of memory in units of
pixel*
instead of in units ofpixel
.But why does this problem cause segfault?
On a 32 bit machine, your pixel struct as defined above takes 3 bytes, but a pointer takes 32 bits (4 bytes).
That is,
sizeof(pixel) == 3
sizeof(pixel*) == 4
So you're only allocating 75% of the memory you need. When accessing the bottom quarter of the image, you'll access memory you never allocated.
(On some 64 bit platforms, the problem definitely only gets worse. On some 16 bit platforms, you might be able to get away with this, although it'd still be sloppy)