I'm working on a GDB project for class an I'm finding issues with a segfault portion in a piece of code that reads a file and creates a matrix with the input. GDB brings me to the "printf("%.2d\t", mat[row][col]);" in printMatrix() but I can't seem to grasp what exactly goes wrong.
int main(int argc, char* argv[])
{
FILE* fp = fopen(argv[1], "r");
int size = 0;
int **mat = readFile(fp, &size);
printMatrix(mat, size);
return 0;
}
int** readFile(FILE* fp, int *size)
{
fscanf(fp, "%d", size);
int num = *size;
int index = 0;
int** mat = (int**)malloc(num * sizeof(int));
for(index = 0; index < num; index++)
mat[index] = (int*)malloc(num * sizeof(int));
int row = 0;
int col = 0;
for(; row < num; row++)
{
for(; col < num; col++)
{
fscanf(fp, "%d", &mat[row][col]);
}
}
return mat;
}
void printMatrix (int** mat, int num)
{
int row = 0;
int col = 0;
for(row = 0; row < num; row++)
{
for(col = 0; col < num; col++)
{
printf("%.2d\t", mat[row][col]); /* gdb indicates segfault here */
}
printf("\n");
}
}
I tried tinkering with the for loop but can't seem to get the expected output.
int** mat = (int**)malloc(num * sizeof(int));
It should be
int** mat = malloc(num * sizeof(int *));
or better
int** mat = malloc(num * sizeof(*mat));
Also use site_t for sizes not int.
I personally would use pointer to array not array of pointers to remove one level of indirection (difficult (de)/allocation , performance penalty)
Always check the result of malloc and scanf
void *readFile(FILE* fp, size_t *size)
{
if(fscanf(fp, "%d", size) != 1) { /* handle error */}
int (*mat)[*size] = malloc(*size * sizeof(*mat));
if(mat)
{
for(size_t row = 0; row < *size; row++)
{
for(size_t col = 0; col < *size; col++)
{
if(fscanf(fp, "%d", &mat[row][col]) != 1) { /* handle error */}
}
}
}
return mat;
}
void printMatrix (size_t num, int (*mat)[num])
{
if(mat)
{
for(size_t row = 0; row < num; row++)
{
for(size_t col = 0; col < num; col++)
{
printf("%.2d\t", mat[row][col]); /* gdb indicates segfault here */
}
printf("\n");
}
}
}
Related
I am trying to return a contiguous memory allocated array from a function but I keep on receiving errors.
Compiler returns a warning saying return from incompatible pointer type [-Wincompatible-pointer-types]
Can someone tell me what I am doing wrong?
int *test() {
size_t rows, cols;
// assign rows and cols
rows = 3;
cols = 3;
int count = 0;
int (*arr)[cols] = malloc(sizeof *arr * rows);
if (arr) {
// do stuff with arr[i][j]
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; j++) {
arr[i][j] = count;
count++;
}
/* code */
}
}
return arr;
}
int main() {
size_t rows, cols;
// assign rows and cols
rows = 3;
cols = 3;
int count = 0;
int (*arr)[cols] = malloc(sizeof *arr * rows);
arr = test();
int i = 0;
int j = 0;
for (i = 0; i < rows; ++i) {
for (j = 0; j < 3; ++j)
printf("%d ", arr[i][j]);
printf("\n");
}
free(arr);
}
it should return a 2D array but returns an error and am using gcc on ubuntu
Your allocation function is fine, except for a few details:
you should pass rows and cols as arguments
you should use type size_t for i and j and iterate to rows and cols instead of hard coded bounds.
you should use parentheses in malloc(sizeof *arr * rows); for readability:
malloc(sizeof(*arr) * rows);
you should return &arr[0][0] or arr[0] for type correctness.
The problem is you cannot define the return type of test to be pointer to 2D array of a parametric second dimension. Hence the type error on the assignment arr = test(); cannot be fixed. You can work around this shortcoming by casting the return value to (int (*)[cols]) or simply (void *).
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int *test(size_t rows, size_t cols) {
int (*arr)[cols] = malloc(sizeof(*arr) * rows);
if (arr) {
// initialize the matrix
size_t count = 0;
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++) {
arr[i][j] = count;
count++;
}
/* code */
}
return &arr[0][0];
}
return NULL;
}
int main() {
// assign rows and cols
size_t rows = 3;
size_t cols = 3;
int (*arr)[cols] = (int (*)[cols])test(rows, cols);
if (arr) {
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++)
printf("%d ", arr[i][j]);
printf("\n");
}
free(arr);
}
return 0;
}
Output:
0 1 2
3 4 5
6 7 8
If all what you need is
to return a contiguous memory allocated array from a function
You can ignore this answer.
If what you are trying to do is to model a bidimensional container (like a matrix) using a dynamically allocated contiguous block of memory, you could define a struct and pass that around:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct {
int rows, cols;
int values[]; // I'm using a Flexible Array Member here.
} iMat;
iMat *alloc_matrix(int rows, int columns)
{
assert(rows > 0 && columns > 0);
iMat *tmp = malloc(sizeof *tmp + sizeof *(tmp->values) * rows * columns);
if (tmp)
{
tmp->rows = rows;
tmp->cols = columns;
}
return tmp;
}
void fill_matrix_iota(iMat *m, int start)
{
if ( m )
for (size_t i = 0, n = m->rows * m->cols; i < n; ++i)
m->values[i] = start + i;
}
void print_matrix(iMat *m, int width)
{
if (m)
{
for (int i = 0, k = 0; i < m->rows; ++i)
{
for(int j = 0; j < m->cols; ++j, ++k)
{
printf("%*.d", width, m->values[k]);
}
putchar('\n');
}
}
}
iMat *make_transposed(iMat *m)
{
if ( !m )
return NULL;
iMat *tmp = alloc_matrix(m->cols, m->rows);
if ( tmp )
{
for (int i = 0; i < m->rows; ++i)
{
for(int j = 0; j < m->cols; ++j)
{
tmp->values[j * m->rows + i] = m->values[i * m->cols + j];
}
}
}
return tmp;
}
int main(void)
{
iMat *a = alloc_matrix(3, 4);
if (!a)
exit(EXIT_FAILURE);
fill_matrix_iota(a, 1);
print_matrix(a, 3);
iMat *b = make_transposed(a);
if (!b)
{
free(a);
exit(EXIT_FAILURE);
}
putchar('\n');
print_matrix(b, 3);
free(b);
free(a);
return EXIT_SUCCESS;
}
i try to create dynamic matrix and enter values with scanf.
Its work only for 1 row, when i increase the error begins.
Can not make progress from the first line and thus can not get values.
int main()
{
int **matrix1;
BuildMatrix(&matrix1, 3, 3);
}
void BuildMatrix(int*** matrix, int row, int column)
{
int i, j, flag = 1, num;
*matrix = (int**)malloc(row * sizeof(int*));
if (*matrix == NULL)
{
printf("Not enough memory!\n");
}
else
{
for (i = 0; i < row && flag; i++)
{
*matrix[i] = (int* )malloc(column * sizeof(int));
if (*matrix[i] == NULL)
{
printf("Not enough memory!\n");
for (j = 0; j < i; j++)
{
free(*matrix[j]);
flag = 0;
}
free(*matrix);
}
}
if (flag)
{
for (i = 0; i < row; i++)
{
for (j = 0; j < column; j++)
{
scanf("%d", &*matrix[i][j]);
}
}
}
}
}
Due to operator precedence, the expression *matrix[i] is equal to *(matrix[i]). That is, it dereferences matrix[i] and not matrix.
You need to use (*matrix)[i] instead.
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
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);
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);
}
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.
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);
}
I have a serious problame.
at the line **c = (int*)malloc(size1 * sizeof(int*));
the compiler gives me this error which I don't really know what it says.
Unhandled exception thrown: read access violation.
c was nullptr. occurred
I don't know what I'm doing wrong..
I initialize every pointer like this.
void BuildMatrix(int ***, int, int);
void FreeMatrix(int ***, int);
void PrintMatrix(int **, int, int);
int **MultiplyMatrixes(int **, int**, int, int, int);
int main() {
int **matrix1 = NULL, **matrix2 = NULL, **matrix3 = NULL;
int * newCol = NULL;
int size1, size2, size3, newRow;
printf("-How many rows in the first matrix?: ");
scanf("%d", &size1);
printf("-How many columns in the first matrix and second?[size2, size3]: ");
scanf("%d %d", &size2, &size3); /*size2 = rows of matrix2.*/
/*Build both matrices*/
printf("-First matrix input.\n");
BuildMatrix(&matrix1, size1, size2);
PrintMatrix(matrix1, size1, size2);
printf("-Second matrix input.\n");
BuildMatrix(&matrix2, size2, size3);
PrintMatrix(matrix2, size2, size3);
/*Combine the 2 matrices to a new matrix*/
matrix3 = MultiplyMatrixes(matrix1, matrix2, size1, size2, size3);
FreeMatrix(&matrix2, size2); //Free the second matrix
printf("\n-Multiplied matrix: \n");
PrintMatrix(matrix3, size1, size3);
FreeMatrix(&matrix3, size1);
FreeMatrix(&matrix1, size1);
}
void BuildMatrix(int *** pMat, int row, int col) {
int i, j;
(*pMat) = (int **)malloc(row * sizeof(int*));
if (*pMat == NULL) {
free(pMat);
printf("*Not enough RAM.\nTerminating.\n");
exit(1);
}
for (i = 0; i < row; i++) {
(*pMat)[i] = (int *)malloc(col * sizeof(int*));
if ((*pMat)[i] == NULL) {
printf("*Not enough RAM.\nTerminating.\n");
FreeMatrix(pMat, row);
exit(1);
}
for (j = 0; j < col; j++) {
printf("-Enter %d element in %d row: ", j + 1, i + 1);
scanf("%d", &(*pMat)[i][j]);
}
printf("\n");
}
//FreeMatrix(pMat, row);
}
void PrintMatrix(int ** pMat, int row, int col) {
for (int i = 0; i < row; ++i) {
for (int j = 0; j < col; ++j) {
printf("%d ", pMat[i][j]);
}
printf("\n");
}
}
int** MultiplyMatrixes(int ** a, int ** b, int size1, int size2, int size3) {
int i, j, k, **c = NULL;
**c = (int*)malloc(size1 * sizeof(int*));
if (c == NULL) {
free(*c);
printf("*Not enough RAM.\nTerminating.\n");
exit(1);
}
for (i = 0; i < size1; i++) {
for (j = 0; j < size3; j++) {
c[i] = (int *)malloc(size3 * sizeof(int));
if (c[i] == NULL) {
printf("*Not enough RAM.\nTerminating.\n");
FreeMatrix(&c, size1);
exit(1);
}
for (k = 0; k < size2; k++) {
c[i][j] += (a[i][k] * b[k][j]);
}
}
}
return c;
}
(*pMat)[i] = (int *)malloc(col * sizeof(int*));
will be
(*pMat)[i] = malloc(col * sizeof(int));
You have allocated space for col number of int* where you are reading int-s.
Also
**c = (int*)malloc(size1 * sizeof(int*));
will be
c = malloc(size1 * sizeof(int*));
Otherwise you were trying to dereference NULL value which triggered the error you got.
Also the loop will be
for (i = 0; i < size1; i++) {
c[i] = malloc(size3 * sizeof(int));
if (c[i] == NULL) {
printf("*Not enough RAM.\nTerminating.\n");
FreeMatrix(&c, size1);
exit(1);
}
for (j = 0; j < size3; j++) {
c[i][j]=0;
for (k = 0; k < size2; k++) {
c[i][j] += (a[i][k] * b[k][j]);
}
}
}
Don't cast the return value of malloc.
While compiling in the terminal I keep getting the error Segmentation Fault: 11. The goal is to make dark circles on a picture of a boarder, ect with command. My reasoning that it isn't working if because of my File IO. I did it without the in & out FILE types and changed the two functions that are called in pgmUtility to not call in files and the program ran smoothly. So I'm assuming I need to have help focusing on the issues I have with my file IO.
Command used:
$ ./a.out -c 470 355 100 < balloons.ascii.pgm > TestImages/balloons_c100_4.pgm
It uses main.c program that relates to pgmUtility.c
This is Main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "pgmUtility.h"
#define ROWS 4
#define COLS 100
void usage(void)
{
printf("Usage\n");
printf(" -h Help Dialog\n");
printf(" -e edgeWidth < OldImageFile > NewImageFile\n");
printf(" -c centerRow centerCol radius < OldImageFile > NewImageFile\n");
printf(" -e edgeWidth -c radius centerRow centerCol < OldImageFile > NewImageFile\n");
exit (8);
}
int main(int argc, char * argv[]) {
FILE *fp;
FILE *out;
int i, j;
int flag1 = 0; //-e switch (edge draw)
int flag2 = 0; //-c switch (circle draw)
int numRows, numCols, centerRow, centerCol, radius, edgeWidth;
char originalImage[100], newImageFile[100];
char **header = (char**) malloc (sizeof(char*)*4);
int **pixels;
//command line argument parsing
//turn flag switches on or off
if(argc < 3)
usage();
if(argc > 7)
usage();
for(i = 1; i < argc; i++) {
if(strncmp(argv[i], "-e", 2) == 0) {
//set flag on
//get edge with values)
if(atoi(argv[i+1]) == 0) {
usage();
}
edgeWidth = atoi(argv[i+1]);
if(argv[i+2] != NULL) {
if(atoi(argv[i+2]) != 0) {
usage();
}
}
flag1 = 1;
}
if(strncmp(argv[i], "-c", 2) == 0) {
//set flag on
//get radius and center values
if(atoi(argv[i+1]) == 0) {
usage();
}
centerRow = atoi(argv[i+1]);
centerCol = atoi(argv[i+2]);
radius = atoi(argv[i+3]);
flag2 = 1;
strcpy(originalImage, argv[5]);
strcpy(newImageFile, argv[6]);
fp = fopen(originalImage, "r");
out = fopen(newImageFile, "w");
}
if(strncmp(argv[i], "-h", 2) == 0) {
usage();
}
}
//allocate memory for header array
header = (char **)malloc(ROWS * sizeof(char));
for(i = 0; i < ROWS; i++) {
for(j = 0; j < COLS; j++) {
header[i] = (char *)malloc(COLS * sizeof(char *));
}
}
//read pgm file
pixels = pgmRead(header, &numRows, &numCols, fp);
if(pixels == NULL)
usage();
switch(flag1) {
case 1 :
if(flag2 == 1) {
//execute circle draw and edge draw
pgmDrawCircle(pixels, numRows, numCols, centerRow, centerCol, radius, header);
pgmDrawEdge(pixels, numRows, numCols, edgeWidth, header);
}
else {
//execute only edge draw only
pgmDrawEdge(pixels, numRows, numCols, edgeWidth, header);
}
break;
case 0 :
if(flag2 == 1) {
//execute circle draw
pgmDrawCircle(pixels, numRows, numCols, centerRow, centerCol, radius, header);
}
break;
default :
usage();
break;
}
//write new pgm file
pgmWrite((const char **)header, (const int **)pixels, numRows, numCols, out);
//Garbage Collection
//Fix this
//free(pixels);
//free(header);
for(i = 0; i < numRows; i++) {
int *current= pixels[i];
free(current);
}
for(i = 0; i < ROWS; i++) {
char *current = header[i];
free(current);
}
return 0;
}
This is two functions from pgmUtility.c that I think may be the cause of the issue.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "pgmUtility.h"
#define ROWS 4
#define COLS 100
// Implement or define each function prototypes listed in pgmUtility.h file.
// NOTE: You can NOT change the input, output, and argument type of the functions in pgmUtility.h
// NOTE: You can NOT change the prototype (signature) of any functions listed in pgmUtility.h
int ** pgmRead( char **header, int *numRows, int *numCols, FILE *in ){
int r, c;
int **array;
for(r = 0; r < ROWS; r++) {
fgets(header[r], COLS, stdin);
if(header == NULL)
return NULL;
}
//sscanf parses the numRows and numCols
sscanf(header[ROWS - 2], "%d %d", numCols, numRows);
//read in pixel map
array = (int **)malloc(*numRows * sizeof(int *));
for(r = 0; r < *numRows; r++) {
array[r] = (int *)malloc(*numCols * sizeof(int));
}
for(r = 0; r < *numRows; r++) {
for(c = 0; c < *numCols; c++) {
fscanf(in, "%d", *(array + r) + c );
}
}
fclose(in);
return array;
}
int pgmWrite( const char **header, const int **pixels, int numRows, int numCols, FILE *out ){
//iterate straight through pixels
//setup with a loop to insert a new line every "numCols" and keep printing until "numRows + 1" is reached (as soon as numRows + 1 break loop)
int i, j;
for(i = 0; i < 4; i++){
//printf("%s", *header[i]);
fprintf(out, "%c", *header[i]);
}
//for(i = 0; i < 4; i++)
//fprintf(out, "*I=%d**%s**", i, header[i]);
for(j = 0; j < numRows; j++){
for(i = 0; i < numCols; i++)
fprintf(out, "%d ", pixels[i][j]);
fprintf(out, "\n");
}
fclose(out);
return 0;
}
You're not allocating the header arrays correctly. It should be:
header = malloc(ROWS * sizeof(char*));
for(i = 0; i < ROWS; i++) {
header[i] = malloc(COLS * sizeof(char));
}
You had the wrong types in the two sizeof calls.
You didn't need the inner j loop at all, you were repeatedly assigning to the same header[i].
And for C (but not C++) see: Do I cast the result of malloc?
Also, at the beginning of main() you have an extra allocation that you never use or free:
char **header = (char**) malloc (sizeof(char*)*4);
You should get rid of this.
It's not related to the error, but this is wrong:
if(header == NULL)
return NULL;
You should be testing header[r].
For clarity, I recommend rewriting:
fscanf(in, "%d", *(array + r) + c );
as:
fscanf(in, "%d", &array[r][c]);
It appears (even after correcting the malloc call as correctly suggested), you are allocating header[i] COLS number of times.
header = malloc(ROWS * sizeof(char*));
for(i = 0; i < ROWS; i++) {
for(j = 0; j < COLS; j++) {
header[i] = malloc(COLS * sizeof(char)); // this happens COLS times
}
}
That will leave COLS number of each header[i] allocated. As I read your code, you need only allocate a single char array for each header[i]. To do this, you need to move header[i] = malloc(COLS * sizeof(char)); outside the for(j = 0; j < COLS; j++) loop:
header = malloc(ROWS * sizeof(char*));
for(i = 0; i < ROWS; i++) {
header[i] = malloc(COLS * sizeof(char));
}
You should also validate that header and each header[i] were successfully allocated.