Solobexus
Solobexus

Reputation: 33

why does realloc throws me "Segmentation fault (core dumped)"

I am really new to C and this is for a school assignment. So, I am tasked to transpose a given matrix.

My current function is the following:

void matrixTranspose(int rows, int cols, int **array) {
    int temp[rows][cols];
    int i, j;

    for (i = 0; i < rows; i++) {
        for(j = 0; j < cols; j++) {
            temp[i][j] = array[i][j];
        }
    }

    array = realloc(array, cols * sizeof(int *));

    for (i = 0; i < cols; i++) {
        array[i] = realloc(array[i], rows * sizeof(int));
    }

    for (i = 0; i < cols; i++) {
        for(j = 0; j < rows; j++) {
            array[i][j] = temp[j][i];
        }
    }
 }

If I introduce equal values for columns and rows or if the value of rows is bigger than the value of columns it works fine, but for some reason when the value of rows is smaller than the value of columns, it does not works. (Throws me "Segmentation fault (core dumped)" error).

My main looks like this:

int main() {
    int **mat;
    int cols, rows;
    int i, j;

   printf("Enter number of rows\n");
    scanf("%d", &rows);
    printf("Enter number of columns\n");
    scanf("%d", &cols);

   mat = (int **) malloc (sizeof(int *) * rows);

   for (i = 0; i < rows; i++) {
       mat[i] = (int *) malloc (sizeof(int) * cols);
   }

   for (i = 0; i < rows; i++) {
       for(j = 0; j < cols; j++) {
           mat[i][j] = rand() % 10;
       }
   }

   printf("\nBefore transpose: \n");
    for (i = 0; i < rows; i++) {
       for(j = 0; j < cols; j++) {
           printf("%d ", mat[i][j]);
       }
       printf("\n");
   }

   matrixTranspose(rows, cols, mat);
   printf("\nAfter transpose: \n");

   for (i = 0; i < cols; i++) {
       for(j = 0; j < rows; j++) {
           printf("%d ", mat[i][j]);
      }
       printf("\n");
   }

 }

I hope I explained myselft correctly, sorry for my english, it is not my first language. Thanks

Upvotes: 3

Views: 101

Answers (4)

chux
chux

Reputation: 153338

I am tasked to transpose a given matrix.

Key problem: Code passed the pointer by value and matrixTranspose() need to receive its address in order to modify it. Well answered by others without changing much.


Yet consider a larger change instead. Do not modify the original matrix, make a transposed copy and free matrix helper functions.

int **matrixTranspose_copy(int rows, int cols, const int **array) {
  int **transpose = malloc(sizeof *transpose * cols);
  for (int r = 0; r < cols; r++) {
    transpose[r] = malloc(sizeof *transpose[r] * rows);
    for(int c = 0; c < rows; c++) {
      transpose[r][c] = array[c][r];
      }
    }
  }
  return transpose;
}

void matrixFree(int rows, const int **array) {
  for (int r = 0; r < rows; r++) {
    free(array[r]);
    }
  free(array);
}

void matrixTranspose_inplace(int rows, int cols, int ***array) {
  int **original = *array;
  *array = matrixTranspose_copy(rows, cols, original);
  matrixFree(original);
}

Upvotes: 0

dbush
dbush

Reputation: 223699

When you modify array in matrixTranspose, you're changing a local variable. That change isn't visible in the calling function, so mat in main no longer points to valid memory.

You need to change the function to accept address of a int ** and dereference it as needed.

void matrixTranspose(int rows, int cols, int ***array) {
    int temp[rows][cols];
    int i, j;

    for (i = 0; i < rows; i++) {
        for(j = 0; j < cols; j++) {
            temp[i][j] = (*array)[i][j];
        }
    }

    *array = realloc(*array, cols * sizeof(int *));
    if (!*array) {
        perror("realloc failed");
        exit(1);
    }

    int min = rows < cols ? rows : cols;
    for (i = 0; i < min; i++) {
        (*array)[i] = realloc((*array)[i], rows * sizeof(int));
        if (!(*array)[i]) {
            perror("realloc failed");
            exit(1);
        }
    }
    if (rows > cols) {
        for (i = min; i < rows; i++) {
            free((*array)[i]);
        }
    } else if (cols > rows) {
        for (i = min; i < cols; i++) {
            (*array)[i] = malloc(rows * sizeof(int));
            if (!(*array)[i]) {
                perror("malloc failed");
                exit(1);
            }
        }
    }

    for (i = 0; i < cols; i++) {
        for(j = 0; j < rows; j++) {
            (*array)[i][j] = temp[j][i];
        }
    }
 }

Note that if the number of rows and columns are not the same, you'll need to either free the extra rows you no longer have or use malloc to allocate new rows.

Note also that you should be checking the return value of malloc and realloc for failure.

Then pass the address of mat to this function:

matrixTranspose(rows, cols, &mat);

Upvotes: 4

Your array is passed by value (i.e. you don't pass a pointer to your matrix). Yet you change it.

array = realloc(array, cols * sizeof(int *));

This is just a local change. Also,

for (i = 0; i < cols; i++) {
       array[i] = realloc(array[i], rows * sizeof(int));
}

If rows < col this piece of code will try to reallocate memory for array[i] where i>rows-1. That implies deallocating the memory pointed to by array[i] has never been allocated and you have no idea where it points to.

Upvotes: 0

klutt
klutt

Reputation: 31296

You can change the transpose function like this:

int ** matrixTranspose(int rows, int cols, int **array) {
    ...
    return array;
}

And then in main call it like this:

mat = matrixTranspose(rows, cols, mat);

Apart from that, I recommend these thanges. I have changed the argument to sizeof to be the actual variable instead of the type.

array = realloc(array, cols * sizeof(*array));

for (i = 0; i < cols; i++) {
    array[i] = realloc(array[i], rows * sizeof(*array[0]));
}

and

mat = (int **) malloc (sizeof(*mat) * rows);

for (i = 0; i < rows; i++) {
    mat[i] = (int *) malloc (sizeof(*mat[0]) * cols);
}

Upvotes: 0

Related Questions