I have a task of creating a matrix, that is the size of NxN
, where N
is a given parameter.
The matrix should be filled with random 0
s and 1
s.
I have tried the following code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <sys/wait.h>
#include <pthread.h>
int** createMatr(int N){
int** matr[10][10];
for(int i = 0; i < N; i ){
for(int j = 0; j < N; j ){
int rnd = rand() % 2;
matr[i][j] = rnd;
}
}
return matr;
}
void setValMatr(int N, int** matr[][10], int** newMatr[][10]){
for(int i = 0; i < N; i ){
for(int j = 0; j < N; j ){
newMatr[i][j] = matr[i][j];
}
}
}
void printMatr(int N, int** matr[][10]){
for(int i = 0; i < N; i ){
for(int j = 0; j < N; j ){
printf("%d ",matr[i][j]);
}
printf("\n");
}
}
int main(int argc, char* argv[]){
if(argc!=2){
perror("parameter error\n");
}
int N = atoi(argv[1]);
int** matrix[10][10];
int** helper[10][10];
setValMatr(N,createMatr(N), matrix);
setValMatr(N,matrix,helper);
printMatr(N, matrix);
return 0;
}
The compilation warnings this gives me are:
┌──(kali㉿kali)-[~/Desktop/Cprog/Linux2_Lab2]
└─$ gcc gvim2135_L2_1.c -o p
gvim2135_L2_1.c: In function ‘createMatr’:
gvim2135_L2_1.c:15:24: warning: assignment to ‘int **’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
15 | matr[i][j] = rnd;
| ^
gvim2135_L2_1.c:18:12: warning: returning ‘int ** (*)[10]’ from a function with incompatible return type ‘int **’ [-Wincompatible-pointer-types]
18 | return matr;
| ^~~~
gvim2135_L2_1.c:18:12: warning: function returns address of local variable [-Wreturn-local-addr]
gvim2135_L2_1.c: In function ‘main’:
gvim2135_L2_1.c:47:18: warning: passing argument 2 of ‘setValMatr’ from incompatible pointer type [-Wincompatible-pointer-types]
47 | setValMatr(N,createMatr(N), matrix);
| ^~~~~~~~~~~~~
| |
| int **
gvim2135_L2_1.c:21:30: note: expected ‘int ** (*)[10]’ but argument is of type ‘int **’
21 | void setValMatr(int N, int** matr[][10], int** newMatr[][10]){
| ~~~~~~^~~~~~~~~~
After running I get the error:
Segmentation fault
CodePudding user response:
With the int** matrix[][]
notation you are not create a matrix but a matrix of matrix pointer. You can see a matrix as a pointer to an array of array: int** matrix
.
So, your code become:
int** create_matrix(int size) {
int i, j, **matrix = (int **)malloc(size * sizeof(int*));
for (i = 0; i < size; i) {
matrix[i] = (int *)malloc(size * sizeof(int));
for (j = 0; j < size; j) {
matrix[i][j] = rand() % 2;
}
}
return matrix;
}
void print_matrix(int** matrix, int size) {
int i, j;
for (i = 0; i < size; i) {
for (j = 0; j < size; j) {
printf("%d | ", matrix[i][j]);
}
printf("\n");
}
}
CodePudding user response:
Use a structure to describe matrices in general, for example
typedef struct imatrix imatrix;
struct imatrix {
int rows;
int cols;
int *data;
};
static inline int imatrix_get(const imatrix *im, int row, int col, int outside)
{
if (!im || row < 0 || col < 0 || row >= im->rows || col >= im->cols)
return outside;
else
return im->data[row * (size_t)(im->cols) col];
}
static inline void imatrix_set(imatrix *im, int row, int col, int value)
{
if (im && row >= 0 && col >= 0 && row < im->rows && col < im->cols)
im->data[row * (size_t)(im->cols) col] = value;
}
void imatrix_free(imatrix *im)
{
if (im) {
free(im->data);
im->rows = 0;
im->cols = 0;
im->data = NULL;
}
}
int imatrix_new(imatrix *im, int rows, int cols)
{
if (!im)
return -1; /* No matrix specified */
im->rows = 0;
im->cols = 0;
im->data = NULL;
if (rows < 1 || cols < 1)
return -2; /* Invalid size */
const size_t rowsize = (size_t)cols * sizeof im->data[0];
const size_t datasize = (size_t)rows * rowsize;
if ((size_t)(datasize / rows) != rowsize ||
(size_t)(rowsize / cols) != sizeof im->data[0])
return -3; /* Matrix is too large */
im->data = malloc(datasize);
if (!im->data)
return -4; /* Not enough memory available */
im->rows = rows;
im->cols = cols;
return 0;
}
The idea is that imatrix
is a structure that contains the number of rows and columns in the matrix, and a pointer to the (array of) data elements. If m
is a properly initialized imatrix
, element at row r
, column c
is m->data[r*(size_t)(m->cols) c]
.
Note that the int
type is not large enough on many architectures to for the index, so we need to cast the number of columns to the proper type, size_t
(which is the proper type for all in-memory sizes and offsets).
If you have e.g. imatrix m;
, you need to initialize it (and dynamically allocate memory for it, say 30 rows and 20 columns) by calling imatrix_new(&m, 30, 20);
. It will return 0
if successful, and negative error code if it fails.
The imatrix_get()
and imatrix_set()
functions are convenient accessor functions, that will not try to access the matrix contents outside of bounds. You do not need to use them in your own functions, if you make sure your loops etc. are always within range; you can then safely use the im->data[r * (size_t)(im->cols) c]
idiom.
When you no longer need the matrix, you discard it with a simple imatrix_free(&m)
call.