I'm trying to read in the data from a .bmp image file so that I can manipulate it. However, after I read in the data I get two problems that I feel are related. Firstly, on the call of fclose() I get a sigabrt, and secondly, if I simply comment out the fclose() all the data I read into the structure array is set to 255 even though it was read-in correctly earlier. I'm pretty new to C so this is almost certainly rookie mistake with allocating dynamic memory.
Pixel** readFile(FILE* fp,Header* header,InfoHeader* infoHeader)
{
if(fp == NULL)
{
printf("file not found\n");
return NULL;
}
fread(&header->Type,SHORTSIZE,1,fp);
fread(&header->Size,INTSIZE,1,fp);
fread(&header->Reserved1,SHORTSIZE,1,fp);
fread(&header->Reserved2,SHORTSIZE,1,fp);
fread(&header->Offset,INTSIZE,1,fp);
fread(&infoHeader->Size,INTSIZE,1,fp);
fread(&infoHeader->Width,INTSIZE,1,fp);
fread(&infoHeader->Height,INTSIZE,1,fp);
fread(&infoHeader->Planes,SHORTSIZE,1,fp);
fread(&infoHeader->Bits,SHORTSIZE,1,fp);
fread(&infoHeader->Compression,INTSIZE,1,fp);
fread(&infoHeader->ImageSize,INTSIZE,1,fp);
fread(&infoHeader->xResolution,INTSIZE,1,fp);
fread(&infoHeader->yResolution,INTSIZE,1,fp);
fread(&infoHeader->Colors,INTSIZE,1,fp);
fread(&infoHeader->ImportantColors,INTSIZE,1,fp);
int rows = infoHeader->Height;
int cols = infoHeader->Width;
Pixel** pixelArr = malloc(rows * sizeof(Pixel*));
int i;
for (i = 0; i < cols; i++)
{
pixelArr[i] = (Pixel*) malloc(sizeof(Pixel));
}
int j;
for(i = 0; i < rows; i++)
{
for(j = 0; j < cols; j++)
{
fread(&pixelArr[i][j].Red,CHARSIZE,1,fp);
fread(&pixelArr[i][j].Green,CHARSIZE,1,fp);
fread(&pixelArr[i][j].Blue,CHARSIZE,1,fp);
}
printf("\n");
}
fclose(fp);
return pixelArr;
}
Related
I have a project on zybooks. And my code appears to be working properly as it can correctly highlight the edges of different images.But, zybooks is automated and it is failing my edgedetect function.
This is my code for both functions:
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>
#include<limits.h>
typedef struct _image {
int** pixels;
int width;
int height;
} Image;
Image* readImage(char* filename) {
Image *pic= malloc(sizeof(Image));
char type[3];
int maxvalue;
FILE *f1=NULL;
f1= fopen(filename,"r");
if(f1==NULL){
printf("Unable to read image: %s\n",filename);
return NULL;
}
fscanf(f1,"%s",type);
fscanf(f1,"%d",&pic->width);
fscanf(f1,"%d",&pic->height);
fscanf(f1,"%d",&maxvalue);
pic->pixels = (int **)malloc(sizeof(int *) * pic->height);
for (int i = 0; i < pic->height; i++) {
pic->pixels[i] = (int *)malloc(sizeof(int) * pic->width);
}
for (int i = 0; i < pic->height; i++) {
for (int j = 0; j < pic->width; j++) {
fscanf(f1,"%d",&pic->pixels[i][j]);
}
}
fclose(f1);
return pic;
}
Image* edgeDetect(Image* img, int threshold) {
Image *edges;
edges=malloc(sizeof(Image));
edges->pixels = (int **)malloc(sizeof(int *) * img->height);
for (int i = 0; i < img->height; i++) {
edges->pixels[i] = (int *)malloc(sizeof(int) * img->width);
}
edges->height = img->height;
edges->width = img->width;
for (int i = 0; i < img->height; i++) {
for (int j = 0; j < img->width; j++) {
edges->pixels[i][j]=0;
}
}
for(int i=0; i< edges->height;i++){
for(int j=0; j<edges->width; j++){
if( i > 0 && i< (edges->height-1) && j>0 && j<(edges->width-1) ){
if(abs(img->pixels[i][j] - img->pixels[i][j+1]) > threshold || abs(img->pixels[i][j] - img->pixels[i-1][j]) > threshold)
edges->pixels[i][j]=255;
}
}
}
return edges;
}
int saveImage(char* filename, Image* img) {
FILE* f1= NULL;
f1= fopen(filename,"w");
if(f1==NULL){
printf("Unable to write image: %s\n",filename);
return 1;
}
fprintf(f1,"P2\n");
fprintf(f1,"%d %d\n",img->width,img->height);
fprintf(f1,"255\n");
for (int i = 0; i < img->height; i++) {
for (int j = 0; j < img->width; j++) {
fprintf(f1,"%d ",img->pixels[i][j]);
}
fprintf(f1,"\n");
}
fclose(f1);
return 0;
}
void freeImage(Image* img) {
for (int i = 0; i < img->height; i++) {
free(img->pixels[i]);
}
free(img->pixels);
free(img);
}
int main(int argc, char** argv) {
if( argc !=4){
printf("Usage: ./a.out input.pgm output.pgm threshold\n");
return 1;
}
int threshold= atoi(argv[3]);
Image *data;
data=readImage(argv[1]);
if (data==NULL)
return 1;
Image *edge;
edge= edgeDetect(data,threshold);
freeImage(data);
int result= saveImage(argv[2],edge);
if (result==1)
return 1;
freeImage(edge);
return 0;
}
Any tip would be helpful.I know the code might be confusing as it might not follow standard formatting but this is literally my first coding class.
regarding:
Image *pic= malloc(sizeof(Image));
Always check (!=NULL) the returned value to assure the operation was successful. If not successful, call
perror( "your error message" );
to output to stderr both your error message and the text reason the system thinks the error occurred.
regarding:
printf("Unable to read image: %s\n",filename);
Error messages should be output to stderr, not stdout. Suggest using:
fprintf( stderr, "Unable to read image: %s\n %s\n", filename, strerror( errno ) );
When calling any of the scanf() family of functions, like fscanf(), always check the returned value (not the parameter values) to assure the operation was successful. Note: That family of functions returns the number of successful 'input format conversion' specifiers.
regarding:
fscanf(f1,"%s",type);
any returned value other than 1 indicates an error occurred.
when using %s and/or %[...] always include a MAX CHARACTERS
modifier that is one less than the length of the input buffer to
avoid any buffer overflow and the resulting undefined behavior, because those 'input format conversion' specifiers always append a NUL byte to the input.
regarding:
pic->pixels = (int **)malloc(sizeof(int *) * pic->height);
in C, the returned type is void* which can be assigned to any pointer. Casting just clutters the code. Suggest removing the cast.
for ease of readability and understanding:
separate code blocks: for if else while do...while switch case default should be separated via a single blank line.
consistently indent the code. Indent after every opening brace '{'.
Unindent before every closing brace '}'. Suggest each indent level
be 4 spaces
insert appropriate horizontal space: inside parens,
inside braces, inside brackets, after commas, after semicolons,
around C operators
the function: malloc() expects the parameter to be of type size_t, however; statements like:
edges->pixels = (int **)malloc(sizeof(int *) * img->height);
are being passed a int as part of the parameter. ( I.E. the img->height ) This results in an implicit conversion between int and size_t which is 'usually' harmless, but is still a risky conversion.
I am trying to randomly fill a 2d array with values then multiply them, but for some odd reason when I run my code, on the last iteration, I get a segmentation fault. I have tried decreasing the number I am passing it and everything, but the fault still persists. Here is the code I am trying to execute, any help is much appreciated, thanks.
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *matrixFile;
int n = atoi(argv[1]); // the number of matrices
int i, j; // must declare outside of for loop due to resolve C99 mode error
double arrA[n][n];// = CreateRandomMatrix(n);
double arrB[n][n];
double sumArr[n][n];
matrixFile = fopen("home/acolwell/Documents/CPE631_HW2_Number1/results.txt", "w+");
printf("Usage: %s <size of nxn matrices>\n", argv[1]);
// randomly populate arrA and arrB
for(i = 0; i < n; i++)
{
printf("%d\n", i);
for(j = 0; j < n; j++)
{
printf("%4d", j);
arrA[i][j] = (double)rand()/(double)RAND_MAX;
arrB[i][j] = (double)rand()/(double)RAND_MAX;
}
}
printf("Exiting Matrix randomization");
// multiply the matrices and write them to the file
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
{
sumArr[i][j] = arrA[i][j] * arrB[i][j];
printf("Writing matrix ");
fprintf(matrixFile, "%0.3lf\n", sumArr[i][j]);
}
}
if(matrixFile)
{
fclose(matrixFile);
}
matrixFile = NULL;
return 0;
}
This error is going to come down to writing off the end of your array or failure to open your file. I would suggest running gdb to check out your program when it is running, but from a quick glance I wonder if you don't mean to have
"/home/acolwell/Documents/CPE631_HW2_Number1/results.txt"
as the file to write instead of
"home/acolwell/Documents/CPE631_HW2_Number1/results.txt"
I would suggest checking the result of your fopen call before calling fprintf.
If n is large enough, you'll generate a stack overflow using VLAs. I've verified this experimentally with your code (e.g. use n of 5000).
So, you'll need to use malloc to allocate from heap. But, that would require a bit of a rewrite.
Here's a way to use heap allocation and get the benefit of a VLA [using some slight trickery]:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define C(_arr) (double (*)[(size_t)(n)]) _arr
void
docalc(FILE *fout,int n,double arrA[n][n],double arrB[n][n],double sumArr[n][n])
{
// must declare outside of for loop due to resolve C99 mode error
int i,
j;
// randomly populate arrA and arrB
for (i = 0; i < n; i++) {
printf("%d\n", i);
for (j = 0; j < n; j++) {
printf("%4d", j);
arrA[i][j] = (double) rand() / (double) RAND_MAX;
arrB[i][j] = (double) rand() / (double) RAND_MAX;
}
}
printf("Exiting Matrix randomization");
// multiply the matrices and write them to the file
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
sumArr[i][j] = arrA[i][j] * arrB[i][j];
printf("Writing matrix\n");
fprintf(fout, "%0.3lf\n", sumArr[i][j]);
}
}
}
int
main(int argc, char *argv[])
{
FILE *matrixFile;
int n = atoi(argv[1]); // the number of matrices
printf("Usage: %s <size of nxn matrices>\n", argv[1]);
matrixFile = fopen("/tmp/results.txt", "w+");
if (matrixFile == NULL) {
perror("fopen");
exit(1);
}
double *arrA = malloc(sizeof(double) * n * n);
double *arrB = malloc(sizeof(double) * n * n);
double *sumArr = malloc(sizeof(double) * n * n);
docalc(matrixFile,n,C(arrA),C(arrB),C(sumArr));
if (matrixFile)
fclose(matrixFile);
matrixFile = NULL;
return 0;
}
I just compiled and tested your code. The file name you are giving is incorrect; you need a "/" in front of "home".
Not sure what the requirements are, but write your matrixFile like a matrix: add a new line after each row of the matrix is "multiplied", not after every element:
for(i = 0; i < n; i++) {
for(j = 0; j < n; j++) {
sumArr[i][j] = arrA[i][j] * arrB[i][j];
printf("Writing matrix ");
fprintf(matrixFile, "%0.3lf ", sumArr[i][j]);
}
fprintf(matrixFile, "\n");
}
Also, take Craig Easley's comment seriously. Stack Overflow can happen, even off the premises this website ;) Consider allocating your matrix dynamically on the heap.
I have a piece of code that calculates coordinates from a user defined size of grid, and prints them to a text file. However when I run the program I get a segmentation fault but only for values of 5 or 7 for the grid, all other values work as intended.
The code is as follows
// Writing OUTPUT 1 to file
// Creating & opening file
FILE *f1 = fopen("coords_output.txt", "w");
if(f1 == NULL)
{
printf("Error in opening file\n");
exit(0);
}
// Writing to file
for(i=0; i < arrayLength; i++)
{
for(j=0; j < arrayLength; j++)
{
fprintf(f1, "\n%d,%d %d", i, j, coordArray[i][j]);
}
}
// Close file
fclose(f1);here
If the whole section under //writing to file is removed the program works, and no matter what I place there the program will fail.
I don't have a great understanding of c, especially when it comes to areas like this, however I have spent a lot of time on trying to fix this problem and cannot seem to come to an answer.
EDIT:
coordArray is defined as
coordArray = malloc(arrayLength * sizeof(int *));
for(i=0; i <= arrayLength; i++)
{
coordArray[i] = malloc(arrayLength * sizeof(int));
}
arrayLength is taken from user input
validInput = validInput && sscanf(argv[1], "%d", &arrayLength);
This code doesn't work (modified from the code you provided):
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int arrayLength = 5;
int i,j;
int **coordArray;
coordArray = malloc(arrayLength * sizeof(int *));
for(i=0; i <= arrayLength; i++)
{
coordArray[i] = malloc(arrayLength * sizeof(int));
}
for(i=0; i < arrayLength; i++)
{
for(j=0; j < arrayLength; j++)
{
printf("\n%d,%d %d", i, j, coordArray[i][j]);
}
}
return 0;
}
It doesn't work because the first for loop is accessing 1 beyond the end of the array. Even though it may appear to work, the code is broken regardless of the value of arrayLength. The reason it may work for some values is due to how segmentation faults occur, there are lots of resources on the Internet about when and why they occur, here's a random one which seems to explain it well.
This code works (notice the change from <= to < in the first for loop):
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int arrayLength = 5;
int i,j;
int **coordArray;
coordArray = malloc(arrayLength * sizeof(int *));
for(i=0; i < arrayLength; i++)
{
coordArray[i] = malloc(arrayLength * sizeof(int));
}
for(i=0; i < arrayLength; i++)
{
for(j=0; j < arrayLength; j++)
{
printf("\n%d,%d %d", i, j, coordArray[i][j]);
}
}
return 0;
}
It can be difficult to find bugs like this without using a debugger or an analysis tool like Valgrind. I'd strongly recommend that you take the time to learn how to use tools like that so that you can find the source of these bugs in the future.
#include <stdio.h>
#include <stdlib.h>
#define MAX_ROWS 5
#define MAX_COLS 5
int globalvariable = 100;
void CreateMatrix(int ***Matrix)
{
int **ptr;
char *cp;
int i = 0;
*Matrix = (int**)malloc((sizeof(int*) * MAX_ROWS) + ((MAX_ROWS * MAX_COLS)*sizeof(int)));
ptr = *Matrix;
cp = (char*)((char*)*Matrix + (sizeof(int*) * MAX_ROWS));
for(i =0; i < MAX_ROWS; i++)
{
cp = (char*)(cp + ((sizeof(int) * MAX_COLS) * i));
*ptr = (int*)cp;
ptr++;
}
}
void FillMatrix(int **Matrix)
{
int i = 0, j = 0;
for(i = 0; i < MAX_ROWS; i++)
{
for(j = 0; j < MAX_COLS; j++)
{
globalvariable++;
Matrix[i][j] = globalvariable;
}
}
}
void DisplayMatrix(int **Matrix)
{
int i = 0, j = 0;
for(i = 0; i < MAX_ROWS; i++)
{
printf("\n");
for(j = 0; j < MAX_COLS; j++)
{
printf("%d\t", Matrix[i][j]);
}
}
}
void FreeMatrix(int **Matrix)
{
free(Matrix);
}
int main()
{
int **Matrix1, **Matrix2;
CreateMatrix(&Matrix1);
FillMatrix(Matrix1);
DisplayMatrix(Matrix1);
FreeMatrix(Matrix1);
getchar();
return 0;
}
If the code is executed, I get the following error messages in a dialogbox.
Windows has triggered a breakpoint in sam.exe.
This may be due to a corruption of the heap, which indicates a bug in sam.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while sam.exe has focus.
The output window may have more diagnostic information.
I tried to debug in Visual Studio, when printf("\n"); statement of DisplayMatrix() is executed, same error message is reproduced.
If I press continue, it prints 101 to 125 as expected. In Release Mode, there is no issue !!!.
please share your ideas.
In C it is often simpler and more efficient to allocate a numerical matrix with calloc and use explicit index calculation ... so
int width = somewidth /* put some useful width computation */;
int height = someheight /* put some useful height computation */
int *mat = calloc(width*height, sizeof(int));
if (!mat) { perror ("calloc"); exit (EXIT_FAILURE); };
Then initialize and fill the matrix by computing the offset appropriately, e.g. something like
for (int i=0; i<width; i++)
for (int j=0; j<height; j++)
mat[i*height+j] = i+j;
if the matrix has (as you show) dimensions known at compile time, you could either stack allocate it with
{ int matrix [NUM_COLS][NUM_ROWS];
/* do something with matrix */
}
or heap allocate it. I find more readable to make it a struct like
struct matrix_st { int matfield [NUM_COLS][NUM_ROWS]; };
struct matrix_st *p = malloc(sizeof(struct matrix_st));
if (!p) { perror("malloc"); exit(EXIT_FAILURE); };
then fill it appropriately:
for (int i=0; i<NUM_COLS; i++)
for (int j=0; j<NUM_ROWS, j++)
p->matfield[i][j] = i+j;
Remember that malloc returns an uninitialized memory zone so you need to initialize all of it.
A two-dimensional array is not the same as a pointer-to-pointer. Maybe you meant
int (*mat)[MAX_COLS] = malloc(MAX_ROWS * sizeof(*mat));
instead?
Read this tutorial.
A very good & complete tutorial for pointers, you can go directly to Chapter 9, if you have in depth basic knowledge.
I feel that a piece of code I have would cause a memory leak. I have a data structure with two two-dimensional arrays, one containing ints and one containing pointers to dynamically-allocated objects (sprites). The data structure is a tilemap, and the ints are the numeric index of each location, which are read from a file. I call that index 'tiles'. This tells what kind of tile it is, for behavioral purposes (i.e. player responds differently to water than to dirt or ice). The objects are the sprites to draw at their respective locations. That index is known as 'images'. That index tells the tilemap what sprite to draw at that position.
typedef struct
{
int** tiles;
sprite*** images;
int w, h;
} tilemap;
I have a function that creates a new tilemap, initializes it, and returns it.
tilemap* new_tilemap(int w, int h, const char* filename)
{
tilemap* tm = malloc(sizeof(tilemap));
tm->w = w;
tm->h = h;
/*allocate memory space for the tiles index*/
tm->tiles = malloc(sizeof(int) * h);
int i, j;
for (i = 0; i < h; ++i)
{
tm->tiles[i] = malloc(sizeof(int) * w);
}
/*fill the index with the appropriate data from a file*/
FILE* file = fopen (filename, "rb");
if (file == NULL)
{
printf("Failed to open map %s\n", filename);
}
for (j = 0; j < h; ++j)
{
for (i = 0; i < w; ++i)
{
fscanf(file, "%d", &(tm->tiles[j][i]));
}
}
fclose(file);
/*allocate space for the images*/
tm->images = malloc(sizeof(sprite*) * h);
for (i = 0; i < h; ++i)
{
tm->images[i] = malloc(sizeof(sprite*) * w);
}
/*load images based on what type of tile is at that position*/
for (j = 0; j < h; ++j)
{
for (i = 0; i < w; ++i)
{
switch (tm->tiles[j][i])
{
case 0:
tm->images[j][i] = new_sprite_file("dat/tiles/0.bmp", 1);
break;
case 1:
tm->images[j][i] = new_sprite_file("dat/tiles/1.bmp", 2);
break;
}
tm->images[j][i]->x = i*tm->images[j][i]->w;
tm->images[j][i]->y = j*tm->images[j][i]->h;
}
}
return tm;
}
Then, to free the tilemap and all it's structures I have this function:
void free_tilemap(tilemap* tm)
{
/*loop through and free each of the images in the array*/
int i, j;
for (j = 0; j < tm->h; ++j)
{
for (i = 0; i < tm->w; ++i)
{
free(tm->images[j][i]);
}
}
/*free the actual array*/
free(tm->images);
/*free the tile array?*/
free(tm->tiles);
/*free the entire tilemap structure*/
free(tm);
}
However, I feel that it isn't freeing up all the memory I have allocated, because I used malloc twice on the tiles, but only free'd once. I don't know if this is a problem though, seeing as they are ints, but I think that I may have to loop through the tiles array, free every row, then loop through and free every column (containing the rows), in the same manner as it was allocated. Is that what needs to be done or am I just being ignorant and/or paranoid? The same with the images array. Also, feel free to point out other flaws in my code as I know I'm not the best programmer.
Of course you should mirror the mallocs when you free.
for (i = 0; i < h; ++i)
{
tm->tiles[i] = malloc(sizeof(int) * w);
}
/* Inside free_tilemap. */
for (i = 0; i < h; ++i)
{
free(tm->tiles[i]);
}
free(tm->tiles);
Same goes for the other fors that closely resemble this one. Freeing just tiles doesn't automatically free tiles[0..h] in cascade.
Looking at the code quickly I would say that you are indeed missing the free's on the tiles. I would suggest to use a memory analyzer to find out for yourself. E.g. http://www.cprogramming.com/debugging/valgrind.html
That will give you a good overview of allocated memory, and possible memory leaks when the program exits.