c - segmentation fault assigning to 2d array - c

I'm trying to take a bmp file and make a grayscale copy. I'm learning about dynamic allocation and I have to dynamically allocate a 2D array which I import the bmp file to and manipulate it from, so it will work with various picture sizes. But near the end (I labeled where) I get a Seg Fault and I have no idea why. Everything works great if I don't dynamically allocate "pixels".
#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;
}

I think the problem is with your fread call and how you are setting up the input buffer for the file contents
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);
The memory you have allocated in total is bmpsize bytes but the length of pixels is just height bytes - and yet you are passing it to fread as if it were a buffer of bmpsize bytes in length. Each element in pixels is a char* - the address of each is block of dynamically allocated array but this does not mean that you can treat your pixels array as a contiguous block of memory.
These arrays allocated dynamically in your loops are thus not initialised which could be leading to the segfaults when you read from them later in your loop (reading uninitialised variables is undefined behaviour).
This probably explains why your code works when you use a non dynamically allocated 2D array - because such a 2D array is a contiguous in memory.

The answer of mathematician1975 is almost correct, since you are accessing data from outside of the area you've allocated, but the last index of c in the inner loop is not 3*width-1 nor 3*width-3, but it's actually width*3.
You should adapt the inner loop to:
for ( c = 0; c < width*3-3; c += 3)
This way c will go until width*3-3 and then you can do c, c+1 and c+2 and you will visit the last bytes of the lines with c+2.

Related

free() function causes a breakpoint

{
char name_entry[ARRAY_SIZE];//bunu dinamik olarak atamıyorum her seferinde gireceğimiz ismin uzunluğunu sormak pratik olmayacaktır
int isimsayisi;
char** names;
printf("Kac Isim Gireceksiniz:");
scanf("%d", &isimsayisi);
names = (char**)malloc(sizeof(char) * (isimsayisi));
for (int k = 0; k < isimsayisi; k++) {
printf("\nismi giriniz :");
scanf("%s", name_entry);
names[k] = (char*)malloc(strlen(name_entry) + 1);
if (names[k] == NULL) {
printf("bellek yetersiz!..\n");
exit(EXIT_FAILURE);
}
strcpy(names[k], name_entry);
}
printf("\nGirilen Isimler : \n");
for (int k = 0; k < isimsayisi; k++) {
printf("%s \n", names[k]);
}
printf("\n");
for (int i = 0; i < isimsayisi; i++)
free(names[i]);
_getch();
}
In this code Im try to take names to a 2d string array then printf what have ı took from user then deallocate the memory but ı cant if I print free(names); after the for loop it gives a windows tab error. Its work like that to 2 names if I take more then 2 names its causes a breakpoint
Edit:isimsayisi means how much names the users wants to enter
This
names = (char**)malloc(sizeof(char) * (isimsayisi));
should be
names = malloc(sizeof(char *) * (isimsayisi));
you don't need to cast malloc() in C (different story for C++).
names is char **; therefore, when allocating memory, you need to use the sizeof(char *), which is definitely different than sizeof(char).
sizeof(char) is the size of a single character and is guaranteed to be 1, while sizeof(char *) is the size of an address and varies based on your machine (8 for a 64-bit CPU).

Input in specific format (matrix)

I have an issue with input in my homework. On stdin, I will get a specifically formatted input.
In first line, there will be 2 integers, that determine the size of a matrix (rows and cols). All the lines after represent rows of the matrix.
I essentially want to do something like getline(), but I don't want to use getline(). In fact I can't, its forbidden in the homework. Therefore I have to scan int by int (or char by char I guess). The issue here is I need it to be bulletproof (almost). Dummy-proof at least.
I'm imagining a big while loop that keeps going until EOF and inside that another loop (perhaps?) which always reads a line, saves it to my allocated matrix and carries on to the next. I'm aware that I'm supposed to be checking for '\n', but I kind of lack the ability to think of a solution today.
Here's what I'm working with: My matrices are a structure.
struct Matrix{
int nrows;
int ncols;
int** matrix;
};
I then have multiple functions.
A function to dynamically allocate space for the matrix of specific size:
struct Matrix init_matrix(int r, int c)
{
struct Matrix mat;
mat.nrows = r;
mat.ncols = c;
mat.matrix = calloc(r, sizeof(int *));
for(int i = 0; i < r; ++i)
{
*(mat.matrix+i) = calloc(c, sizeof(int));
}
return mat;
}
A function to free the previously allocated space:
void free_matrix(struct Matrix mat)
{
int top = mat.nrows;
for(int i = 0; i < top; ++i)
{
free(mat.matrix[i]);
}
free(mat.matrix);
}
Those 2 functions work perfectly fine.
Now I'm trying to make a function create_matrix(void) (at least I think it shouldn't take any args), that will read the input I'm supposed to receive, for example:
3 3
1 2 3
4 5 6
7 8 9
when the function reads the input, it could tell if the input is incorrect or is in incorrect format and exit the program with corresponding exit value (like 100 f.e.) If the input is correct and in correct format, it calls init_matrix() and then saves input to the matrix.
For your deeper understanding: the whole input I'm supposed to receive is:
matrix A (like above, size in first line, values in lines after)
an operation (+,-,*)
matrix B
Then execute the operation (A*B, A+B etc.). I'm trying to make most things into functions, so the main would be very simple, f.e.
int main(int argc, char *argv[])
{
struct Matrix mat1 = create_matrix();
char operation = get_operation();
struct Matrix mat2 = create_matrix();
struct Matrix result = compute(mat1,mat2, operation);
return 0;
}
Something in those lines, if you get me. The thing is I want to make the program complex enough so that I could later edit it to handle a bigger sequence (up to 100) of matrices than just two. Right now I could do it the dirty way, make it work for two matrices with one operation, but that's not what I really want.
Well, here's how I solved it. It works. It's not anywhere close to perfect, but it works, upload system took it and gave it full amount of points, so I'm satisfied.
struct Matrix read_matrix(FILE *fp)
{
struct Matrix mat;
//FIRST LINE
int ch;
int i = 0;
int n = 20;
char* line = calloc(n,sizeof(char));
while((ch = fgetc(fp)) != EOF && ch != '\n')
{
*(line + i++) = ch;
}
*(line + n-1) = '\0';
int r,c;
int k = sscanf(line,"%d %d", &r, &c);
if(k != 2)
{
fprintf(stderr, "Error: Chybny vstup!\n");
exit(100);
}
free(line);
//MATRIX
line = calloc(c, sizeof(int));
mat = init_matrix(r, c);
i = 0;
r = 0;
while(r < mat.nrows && (ch = fgetc(fp)))
{
if(ch == '\n' || ch == EOF)
{
*(line + i) = '\0';
int offset;
char *data = line;
for(int j = 0; j < mat.ncols; ++j)
{
int d = sscanf(data, " %d%n", &mat.matrix[r][j], &offset);
if(d != 1){
fprintf(stderr, "Error: Chybny vstup!\n");
exit(100);
}
data += offset;
}
i = 0;
++r;
if(ch == EOF){
break;
}
} else
{
*(line + i++) = ch;
}
}
free(line);
return mat;
}

how to use a 2D array in C

I am new in C and I am trying to create a 2D array of chars.
The logic behind this is to get unknown amount of string inputs
from the user and to be able to get to those strings
(each string ends with a ":") but when I tried to debug I got:
<Error reading characters of string>
This is the code:
int main()
{
int j = 0, rows = 50;
int i=0, lines = 50;
char **names;
names = (char**)malloc(lines*sizeof(char*));
if (i >= lines)
{
names = (char**)realloc(names, 10 * sizeof(char*));
lines = lines * 10;
}
for (j ; names[i][j] != ':'; j++)
{
*names = (char*)malloc(rows * sizeof(char));
if (j >= rows)
{
*names = (char*)realloc(names, 10 * sizeof(char));
rows = rows * 10;
}
scanf("%c", &names[i][j]);
}
i++;
return 0;
}
for (j ; names[i][j] != ':'; j++)
In this loop your test condition tests for ':' in names . names has been allocated memory but it does not contain any content (what will it compare to ?).
Use a do-while loop , in order to execute loop before reading characters in names.
Also you allocate memory for char *'s but you don't allocate memory to these pointers correctly . And without allocating memory correctly you try to store characters at location they point to . This will cause problem .
Allocate memory to each char * and then take input .
Some this like this can be done -
do{
names[i] =malloc(rows * sizeof(char));
if(names!=NULL){
if (j >= rows)
{
*names = (char*)realloc(names, 10 * sizeof(char));
rows = rows * 10;
}
scanf("%c", &names[i][j]);
j++;
i++;
}
}while(names[i][j]!=':')'
Note-
1. You should free the allocated memory . And you first if will not execute (can't understand its use ).
2. Check return of malloc.

Using pointers in 2D arrays

I'm attempting to store arrays of integers that I read from a file (with a separate function) in a 2D array but I keep having issues with Segmentation fault. I know it's an issue with my pointers but I can't figure out exactly what I'm doing wrong.
Here is my function (takes an integer and compares it with an integer read from a file before storing it in my 2D array).
int **getStopTimes(int stop_id) {
int **result = malloc(sizeof(*result));
char const* const fileName = "stop_times_test.txt";
FILE* txt = fopen(fileName, "r");
char line[256];
int count = 0;
while (fgets(line, sizeof(line), txt) != NULL) {
int *formattedLine = getStopTimeData(line); //getStopTimeData returns a pointer to an array of ints, memory is allocated in the function
if (formattedLine[1] == stop_id) {
result[count] = formattedLine;
count++;
}
}
fclose(txt);
return result;
}
And my main:
int main(int argc, char *argv[]) {
int **niceRow = getStopTimes(21249);
for (int i=0; i<2; i++) { //Only looping 3 iterations for test purposes
printf("%d,%d,%d,%d\n",niceRow[i][0], niceRow[i][1], niceRow[i][2], niceRow[i][3]);
}
free(niceRow);
return 0;
}
getStopTimeData function thats being called (Pulls certain information from an array of chars and stores/returns them in an int array):
int *getStopTimeData(char line[]) {
int commas = 0;
int len = strlen(line);
int *stopTime = malloc(4 * sizeof(*stopTime)); //Block of memory for each integer
char trip_id[256]; //Temp array to build trip_id string
char stop_id[256]; //Temp array to build stop_id string
int arrival_time; //Temp array to build arrival_time string
int departure_time; //Temp array to build departure_time string
int counter;
for(int i = 0; i <len; i++) {
if(line[i] == ',') {
commas++;
counter = 0;
continue;
}
switch(commas) { //Build strings here and store them
case 0 :
trip_id[counter++] = line[i];
if(line[i+1] == ',') trip_id[counter] = '\0';
break;
case 1: //Convert to hours past midnight from 24hr time notation so it can be stored as int
if(line[i] == ':' && line[i+3] == ':') {
arrival_time = (line[i-2]-'0')*600 + (line[i-1]-'0')*60 + (line[i+1]-'0')*10 + (line[i+2]-'0');
}
break;
case 2 :
if(line[i] == ':' && line[i+3] == ':') {
departure_time = (line[i-2]-'0')*600 + (line[i-1]-'0')*60 + (line[i+1]-'0')*10 + (line[i+2]-'0');
}
break;
case 3 :
stop_id[counter++] = line[i];
if(line[i+1] == ',') stop_id[counter] = '\0';
break;
}
}
//Assign and convert to ints
stopTime[0] = atoi(trip_id);
stopTime[1] = atoi(stop_id);
stopTime[2] = arrival_time;
stopTime[3] = departure_time;
return stopTime;
}
This line:
int **result = malloc(sizeof(*result));
allocates just memory for one single pointer. (*result is of type int *, so it's a pointer to data -- the sizeof operator will tell you the size of a pointer to data ... e.g. 4 on a 32bit architecture)
What you want to do is not entirely clear to me without seeing the code for getStopTimeData() ... but you definitely need more memory. If this function indeed returns a pointer to some ints, and it handles allocation correctly, you probably want something along the lines of this:
int result_elements = 32;
int **result = malloc(sizeof(int *) * result_elements);
int count = 0;
[...]
if (formattedLine[1] == stop_id) {
if (count == result_elements)
{
result_elements *= 2;
result = realloc(result, result_elements);
}
result[count] = formattedLine;
count++;
}
Add proper error checking, malloc and realloc could return (void *)0 (aka null) on out of memory condition.
Also, the 32 for the initial allocation size is just a wild guess ... adapt it to your needs (so it doesn't waste a lot of memory, but will be enough for most use cases)
The upper answer is good,
just to give you an advice try to avoid using 2D array but use a simple array where you can store all your data, this ensures you to have coalescent memory.
After that, you can access your 1D array with an easy trick to see it like a 2D array
Consider that your 2D array has a line_size
To access it like a matrix or a 2d array you need to find out the corresponding index of your 1d array for given x,y values
index = x + y * line size;
In the opposite way:
you know the index, you want to find x and y corresponding to this index.
y = index / line_size;
x = index mod(line_size);
Of course, this "trick" can be used if you already know your line size

Invalid read - Valgrind and C

New to C and Valgrind and manual memory management and I'm having trouble locating an error that I'm getting when I run Valgrind. I have this function which gets strings from the user:
char **get_fragments_from_user(){
// No more than 20k strings containing at most 1k characters
char **strings = malloc(20000 * sizeof(char *));
char tempstring[MAX_INPUT]; //MAX_INPUT = 1001
int count = 0;
while(true){
printf("\n> ");
fgets(tempstring, MAX_INPUT, stdin);
if((strlen(tempstring) > 0) && (tempstring[strlen(tempstring) - 1] == '\n')){
tempstring[strlen(tempstring) - 1] = '\0';
}
if(tempstring[0] == 'q') break;
strings[count] = malloc(sizeof(char) * (strlen(tempstring)+1));
strcpy(strings[count], tempstring);
count++;
}
int i = 0;
char **fstrings = malloc((count)*sizeof(char *)); // count+1 needed? Something I tried removing while debugging
for(i = 0; i < count; i++){
fstrings[i] = malloc(sizeof(char) * (strlen(strings[i])+1));
strcpy(fstrings[i], strings[i]);
free(strings[i]);
}
free(strings);
return fstrings;
}
The idea here is simply to get strings and put them in an array. I initially allocate an array that is large enough to fit the maximum number of strings that could ever be entered (20,000), but I then resize the array so that I don't allocate more memory than the each string needs. I am a little embarrassed with the above code, since its less clean than anything I would have written in another language, but that was my first pass through.
I then get "Invalid read of size 8" from Valgrind when I try to calculate the number of strings in the array using this function:
int lengthOf(char **arr){
int i = 0;
while(arr[i] != NULL){
i++;
}
return i;
}
I'm pretty sure this is due to a dereferenced pointer or something, but I can't find it for the life of me and I've been looking at this code for an hour or so.
So, I believe the problem was that I wasn't allocating enough memory to store the whole array.
Instead of doing:
malloc(count * sizeof(char *));
I should have been allocating count+1, so either:
malloc((count + 1) * sizeof(char *))
or
calloc((count + 1), sizeof(char *));

Resources