我试图获取bmp文件并制作灰度副本。我正在学习动态分配,我必须动态分配一个2D数组,我将bmp文件导入并操作它,因此它可以处理各种图像大小。但接近尾声(我标记在哪里)我得到了一个Seg Fault,我不明白为什么。如果我不动态分配"像素"。
,一切都很有效#include <stdio.h>
#include <stdlib.h>
int main(void) {
const int HEADER_SIZE = 54;
FILE *infile = fopen("test1.bmp", "rb");
FILE *outfile1 = fopen("copy1.bmp", "wb");
int i, width, height, r, c, bmpsize;
char header[HEADER_SIZE], filename[32];
char **pixels; //initialize pixels here
puts("Enter the filename: ");
i = -1;
while(filename[i] != '\n')
{
i++;
scanf("%c", &filename[i]);
}
filename[i] = '.';
filename[i+1] = 'b';
filename[i+2] = 'm';
filename[i+3] = 'p';
filename[i+4] = '\0';
i = -1;
while(filename[i] != '\0')
{
i++;
printf("%c", filename[i]);
}
infile = fopen(filename, "rb");
puts("Enter the height and width (in pixels): ");
scanf("%d%d", &height, &width);
bmpsize = 3 * width * height;
pixels = malloc(height * sizeof(char*)); //DA part 1
for(i = 0; i < height; i++)
{
pixels[i] = malloc((width * 3) * sizeof(char)); //DA part 2
}
fread(header, 1 , HEADER_SIZE, infile);
fread(pixels, 1 , bmpsize, infile);
for( r = 0; r < height; r++) {
for ( c = 0; c < width*3; c += 3) {
int avg= 0;
puts("THIS PUTS PRINTS: THE NEXT LINE IS MY PROBLEM");
avg = ((int) pixels[r][c] + (int) pixels[r][c+1] + (int) pixels[r][c+2]) / 3;//This is my problem line, why?
puts("THIS PUTS DOESN'T PRINT. ERROR: SEG. FAULT(core dumped)");
pixels[r][c] = (char) avg;
pixels[r][c+1] = (char) avg;
pixels[r][c+2] = (char) avg;
}
}
puts("Done. Check the generated images.");
fwrite(header, sizeof(char) , HEADER_SIZE, outfile1);
fwrite(pixels, sizeof(char) , bmpsize, outfile1);
fclose(infile);
fclose(outfile1);
return 0;
}
答案 0 :(得分:1)
我认为问题在于您的fread
调用以及如何为文件内容设置输入缓冲区
pixels = malloc(height * sizeof(char*)); //DA part 1
for(i = 0; i < height; i++)
{
pixels[i] = malloc((width * 3) * sizeof(char)); //DA part 2
}
fread(pixels, 1 , bmpsize, infile);
您已分配总计的内存为bmpsize
字节,但pixels
的长度仅为height
字节 - 但您将其传递给{ {1}}好像它是fread
字节长度的缓冲区。 bmpsize
中的每个元素都是pixels
- 每个元素的地址都是动态分配的数组块,但这并不意味着您可以将char*
数组视为连续的内存块。
因此,在循环中动态分配的这些数组不会被初始化,这可能会导致在循环中稍后读取它们时导致段错误(读取未初始化的变量是未定义的行为)。
这可能解释了为什么你的代码在使用非动态分配的2D数组时有效 - 因为这样的2D数组在内存中是连续的。
答案 1 :(得分:0)
c
的答案几乎是正确的,因为您正在从您已分配的区域外部访问数据,但内部循环中3*width-1
的最后一个索引不是{{ 1}}也不是3*width-3
,但它实际上是width*3
。
您应该将内循环调整为:
for ( c = 0; c < width*3-3; c += 3)
这种方式c
将持续到width*3-3
,然后您可以执行c
,c+1
和c+2
,然后您将访问这些行的最后字节与c+2
。