matrix operations reading input from file - c

I'd like to perform matrix operations like A*B+C. The matrix are read from a file thus formatted:
1 3 4 5
0 1 0 6
0 0 1 7
2 7 0 1
*
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
*
1 2
3 4
I can already read the matrices and the operators, I don't know how to perform the operations. Suppose that you have: AB+C so you must perfom firstly (AB) then I think the best strategy is that this result becomes B and ultimately perform B+C. I'm not sure on how to reallocate B and perform the operations in the correct order. To keep it simple I'm just considering multiplication for the moment.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MINA 2 /* if you need a constant, #define one (or more) */
#define MAXC 1024
struct m{
int **data;
size_t row, col;
};
void multiply(struct m *A, struct m *B)
{
int i, j, k;
struct m C;
C.data = malloc(sizeof(int) * A->row);
C.row = A->row;
C.col = B->col;
/*initialize C to 0*/
for ( j = 0; j < C.row; j++) /* for each row */
for ( k = 0; k < C.col; k++) /* for each col */
C.data[j][k] = 0; /* output int */
// Multiplying matrix A and B and storing in C.
for(i = 0; i < A->row; ++i)
for(j = 0; j < B->col; ++j)
for(k=0; k < A->col; ++k)
C.data[i][j] += A->data[i][k] * B->data[k][j];
//free(B->data);
*B = C;
}
void print_matrix(struct m *matrix)
{
int j, k;
for ( j = 0; j < matrix->row; j++) { /* for each row */
for ( k = 0; k < matrix->col; k++) /* for each col */
printf ("%4d", matrix->data[j][k]); /* output int */
putchar ('\n'); /* tidy up with '\n' */
free (matrix->data[j]); /* free row */
}
free (matrix->data); /* free pointers */
}
int main (int argc, char **argv)
{
struct m *matrix; /* pointer to array type */
size_t aidx = 0, maxa = MINA, /* matrix index, max no. allocated */
nrow = 0, ncol = 0, /* current row/col count */
maxrow = MINA, nop = 0; /* alloc'ed rows current array, no. op */
char buf[MAXC], /* buffer to hold each line */
op[MAXC]; /* array to hold operators */
int i;
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
/* allocate/validate maxa no. of matrix */
if (!(matrix = calloc (maxa, sizeof *matrix))) {
perror ("calloc-matrix");
return 1;
}
while (fgets (buf, MAXC, fp)) { /* read each line into buf */
int off = 0, n; /* offset from start of line, n for "%n" */
size_t tidx = 0; /* temporary array index */
char *p = buf; /* pointer to advance in sscanf */
int tmp[MAXC / 2 + 1]; /* temporary array, sized for max no. ints */
if (!isdigit(*buf)) { /* if 1st char non-digit, end of array */
op[nop++] = *buf; /* store operator */
if (nrow) /* if rows stored */
matrix[aidx++].row = nrow; /* set final number of rows */
nrow = ncol = 0; /* reset nrow/ncol counters */
maxrow = MINA; /* reset allocate rows */
continue; /* get next line of data */
}
if (aidx == maxa) { /* check if no. of structs need realloc */
void *atmp = realloc (matrix, 2 * maxa * sizeof *matrix); /* realloc */
if (!atmp) { /* validate */
perror ("realloc-matrix");
return 1;
}
matrix = atmp; /* assign new block to matrix */
/* set all new bytes zero (realloc doesn't initialize) */
memset (matrix + maxa, 0, maxa * sizeof *matrix);
maxa *= 2; /* update struct count */
}
/* read all integers in line into tmp array */
while (sscanf (p + off, "%d%n", &tmp[tidx], &n) == 1) {
off += n;
tidx++;
}
if (tidx) { /* if integers stored in tmp */
if (nrow == 0) { /* if first row in array */
/* allocate/validate maxrow pointers */
if (!(matrix[aidx].data = malloc (maxrow * sizeof *matrix[aidx].data))) {
perror ("malloc-matrix[aidx].data");
return 1;
}
matrix[aidx].col = tidx; /* fix no. cols on 1st row */
}
else if (nrow == maxrow) { /* realloc of row ptrs req'd? */
/* always realloc with temp ptr */
void *atmp = realloc (matrix[aidx].data, 2 * maxrow * sizeof *matrix[aidx].data);
if (!atmp) { /* validate every alloc/realloc */
perror ("realloc-matrix[aidx].data");
return 1;
}
matrix[aidx].data = atmp; /* assign realloced block to ptr */
maxrow *= 2; /* update maxrow to current alloc */
}
if (tidx != matrix[aidx].col) { /* validate no. of columns */
fprintf (stderr, "error: invalid number of columns " "matrix[%zu].data[%zu]\n", aidx, nrow);
return 1;
}
if (!(matrix[aidx].data[nrow] = /* allocate storagre for integers */
malloc (tidx * sizeof *matrix[aidx].data[nrow]))) {
perror ("malloc-matrix[aidx].data[nrow]");
return 1;
}
/* copy integers from tmp to row, increment row count */
memcpy (matrix[aidx].data[nrow++], tmp, tidx * sizeof *tmp);
}
} /*end of while (fgets (buf, MAXC, fp)) */
if (nrow) /* handle final array */
matrix[aidx++].row = nrow; /* set final number of rows */
if (fp != stdin) fclose (fp); /* close file if not stdin */
/*Printing the file */
for(i=0; i<aidx; i++){
print_matrix(&matrix[i]);
printf("%c\n",op[i]);
}
printf("=\n");
for(i=0; i<aidx; i++){
if(op[i] =='*')
multiply(&matrix[aidx],&matrix[aidx+1]);
}
print_matrix(&matrix[aidx-1]); /*Print the result */
free (matrix); /* free structs */
return 0;
}

My original answer is still correct in its content, I will leave it quoted at the end. Now the problem is more clear. A "naive" algorithm to solve this problem could be to, if you only have multiplications or sums, read the file and keep a list where you put:
If you have a * sign, multiply the operands, saving only the result
If you have a + sign, go to the next item
When you are done sum all the items in the list. In pseudocode:
list = []
i = 0
op = +
for item in file {
if item is operator {
op = item
if op == + {
i++
}
} else if item is matrix {
if len(list) > i {
list[i] = list[i] op item
} else {
list[i] = item //auto append if i < len(list)
}
}
}
result = list[0]
for item in list[1:] {
result += item
}
Keep in mind this:
Is pseudo code
By all mean not the best way to do it I think
If I understood correctly the question you want to know: Where should you put the result of the operation and how to decide in which order should you do the operations. So, firstly: Your idea that, when doing AB+C you should put the result of AB in B is not bad, but, before doing something like this you should know that B is no longer used in the rest of the equation. Consider AB+B, now if you overwrite B, you lost it and are unable to complete the equation. You need a graph of relations of variables to do that operation, if you have it you can not only overwrite an unused variable with a result of an operation (usually free the old variable if now unused and allocate a new one) but also reuse the result of an operation later, for instance if you have to do ABC + AB, you can see that there is no point in re-calculating AB. The second question similarly requires you to build an operation tree, I suggest to you to do so using a LL(1) parser.

Related

Why do I encounter an error on a simple matrix function

I don't understand why my program crashes every time I finish reading and my showing function comes....
The error says read access violation
void read(int **m, int n)
{
int i, j;
for(i=0;i<n;i++)
for (j = 0; j < n; j++)
{
printf("a[%d][%d]=", i, j);
scanf("%d", (m + i * n + j));
}
}
void show(int **m, int n)
{
int i, j;
for (i = 0; i < n; i++)
for (j = 0; j <= n; j++)
{
printf("%d ", *(m + i * n + j));//where the error occurs
printf("\n");
}
}
int main()
{
int **m;
int opt,n;
printf("Introduceti nr de linii si coloane:");
scanf("%d", &n);
m= (int*)malloc(n*n * sizeof(int));
Continuing from my comment, your primary issue is you allocate storage for n * n pointers, but then fail to allocate any storage for the int values. When working with pointers and/or allocating storage dynamically, you should always be able to answer "To what valid storage do each of my pointers point?". If you can't you have no idea what address you are attempting to use.
(note: you only need to allocate n pointers -- one for each row)
As #RetiredNinja also points out, you have an Off-By-One error in for (j = 0; j <= n; j++) which attempts to read the address for n + 1 integer values per row.
Since you have allocated n * n pointers, you now need to allocate storage for n integers assigning the address for each new valid block of memory to each of your pointers in turn. Additionally, in read() since your read with scanf() or allocation with malloc() can fail, you must provide a return type for the read() function that can indicate success or failure. Making the return type int and returning 1 on success or 0 on failure is fine.
(note: since read() conflicts with an existing syscall name, you should rename your read() function, e.g. mtrxread() or the like)
Putting that altogether, you can do something like:
/* type must be capable of indicating success/failure */
int mtrxread (int **m, int n)
{
int i, j;
for (i = 0; i < n; i++) { /* guard each block with {...} */
/* allocate n int / validate EVERY allocation */
if (!(m[i] = malloc (n * sizeof *m[i]))) {
perror ("malloc-m[i]");
return 1;
}
for (j = 0; j < n; j++) {
printf("a[%d][%d] = ", i, j);
if (scanf ("%d", &m[i][j]) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
return 0;
}
}
}
return 1;
}
(note: In C, there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?)
(also fix the <= making it < in show())
In main(), you need to validate EVERY input and EVERY allocation - just as you do everywhere else. You also need to validate whether mtrxread() succeeds or fails. Putting that together, you can do:
int main (void) {
int **m; /* NOT an array, a pointer-to-pointer-to int */
int n;
fputs ("Introduceti nr de linii si coloane: ", stdout);
if (scanf("%d", &n) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
/* validate EVERY allocation */
if (!(m = malloc (n * sizeof *m))) {
perror ("malloc-m");
return 1;
}
if (!mtrxread (m, n)) { /* validate read of elements */
return 1;
}
show (m, n); /* show the matrix */
for (int i = 0; i < n; i++) {
free (m[i]); /* free int storage */
}
free (m); /* free pointers */
}
(note: the additional information provided by comments in the code)
The complete code could be:
#include <stdio.h>
#include <stdlib.h>
/* type must be capable of indicating success/failure */
int mtrxread (int **m, int n)
{
int i, j;
for (i = 0; i < n; i++) { /* guard each block with {...} */
/* allocate n int / validate EVERY allocation */
if (!(m[i] = malloc (n * sizeof *m[i]))) {
perror ("malloc-m[i]");
return 1;
}
for (j = 0; j < n; j++) {
printf("a[%d][%d] = ", i, j);
if (scanf ("%d", &m[i][j]) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
return 0;
}
}
}
return 1;
}
void show (int **m, int n)
{
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
printf("%d ", m[i][j]);//where the error occurs
}
putchar ('\n'); /* you putchar() a single character */
}
}
int main (void) {
int **m; /* NOT an array, a pointer-to-pointer-to int */
int n;
fputs ("Introduceti nr de linii si coloane: ", stdout);
if (scanf("%d", &n) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
/* validate EVERY allocation */
if (!(m = malloc (n * sizeof *m))) {
perror ("malloc-m");
return 1;
}
if (!mtrxread (m, n)) { /* validate read of elements */
return 1;
}
show (m, n); /* show the matrix */
for (int i = 0; i < n; i++) {
free (m[i]); /* free int storage */
}
free (m); /* free pointers */
}
Example Use/Output
$ ./bin/ptr2ptr2int-allocate
Introduceti nr de linii si coloane: 3
a[0][0] = 1
a[0][1] = 2
a[0][2] = 3
a[1][0] = 4
a[1][1] = 5
a[1][2] = 6
a[2][0] = 7
a[2][1] = 8
a[2][2] = 9
1 2 3
4 5 6
7 8 9
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/ptr2ptr2int-allocate
==5081== Memcheck, a memory error detector
==5081== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5081== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==5081== Command: ./bin/ptr2ptr2int-allocate
==5081==
Introduceti nr de linii si coloane: 3
a[0][0] = 1
a[0][1] = 2
a[0][2] = 3
a[1][0] = 4
a[1][1] = 5
a[1][2] = 6
a[2][0] = 7
a[2][1] = 8
a[2][2] = 9
1 2 3
4 5 6
7 8 9
==5081==
==5081== HEAP SUMMARY:
==5081== in use at exit: 0 bytes in 0 blocks
==5081== total heap usage: 6 allocs, 6 frees, 2,156 bytes allocated
==5081==
==5081== All heap blocks were freed -- no leaks are possible
==5081==
==5081== For lists of detected and suppressed errors, rerun with: -s
==5081== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Option For Single-Allocation/Single-Free with Pointer to VLA
C provides a, now optional, feature called a Variable Length Array, that in your case can provide a single-allocation/single-free. While this feature was made optional in C11, it will remain widely supported for some time. By using a pointer-to-VLA-of int[n], you can make a single call to malloc() in main() to allocate all storage required. The changes required are:
int main (void) {
int n;
fputs ("Introduceti nr de linii si coloane: ", stdout);
if (scanf("%d", &n) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
int (*m)[n]; /* pointer to VLA of n int */
/* validate EVERY allocation */
if (!(m = malloc (n * sizeof *m))) {
perror ("malloc-m");
return 1;
}
if (!mtrxread (n, m)) { /* validate read of elements */
return 1;
}
show (n, m); /* show the matrix */
free (m); /* free allocated memory */
}
The order of your parameters for each function will need to change so the size n is known before the pointer to VLA is provided. For example mtrxread() would reduce to:
/* type must be capable of indicating success/failure */
int mtrxread (int n, int (*m)[n])
{
int i, j;
for (i = 0; i < n; i++) { /* guard each block with {...} */
for (j = 0; j < n; j++) {
printf("a[%d][%d] = ", i, j);
if (scanf ("%d", &m[i][j]) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
return 0;
}
}
}
return 1;
}
(change the order for show() in like manner)
Now all memory is allocated at once and requires only a single call to free(). Quite convenient, but with the caveat of the VLA now having optional support from compilers.
Let me know if you have further questions.

Where is my program going out of bounds? I get "Process returned -1073740940 (0xC0000374)" at the end

I really can't see an issue, but then again, I just started learning C a few weeks ago, as a way to get faster code than what I was using.My guess is it has to do with my memory allocation. This is small, but eventually I will be using this process with Count values up to 25.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main()
{
int i;
int j;
int Count = 2; /* set number of bits */
int Combos = pow(2,Count); /* calculate count of all 6 bit binary numbers */
int SIZE = (Combos + 1) * (Count + 1); /* calculate number of array elements */
/* rows * columns */
/* rows = Combos + 1 */
/* columns = count +1 (row number + bits)*/
/* 0th spot will hold row number */
printf("SIZE = %d\n", SIZE); /* print number of array elements */
int (*a)[Count + 1] = malloc(SIZE); /* allocate memory for array based on size of */
/* int variable times SIZE */
/* (SIZE) is number of elements */
if (a == NULL) /* if not enough memory, print error message */
{
fprintf(stderr,"Could not allocate that much memory");
return 1;
}
/* do something with array */
for (i =0; i<= Combos; i++){
a[i][0] = i; /* set 0th element of this row to row number */
printf("a[%d][0] = %d ", i,a[i][0]); /* print 0th element of this row */
for (j =1; j<= Count; j++){ /* print the rest of the elements in this row */
a[i][j] = 1;
printf("a[%d][%d] = %d ", i,j,a[i][j]);
} /* end j loop */
printf("\n"); /* line feed */
} /* end i loop */
free(a); /* release memory allocated for array */
return 0;
}
Note that malloc(K) allocates K bytes of memory.
If you'd like to allocate an array consisting of N elements of type T, you need to call malloc(N * sizeof(T)).
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, j;
const size_t COUNT = 30;
const size_t COMBOS = (size_t)1 << COUNT;
const size_t SIZE = (COMBOS + 1) * (COUNT + 1);
printf("SIZE = %zu\n", SIZE);
int (*a)[COUNT + 1] = malloc(SIZE * sizeof(int));
if (a == NULL)
{
fprintf(stderr, "Could not allocate that much memory\n");
return 1;
}
for (i = 0; i <= COMBOS; i++)
{
a[i][0] = i;
printf("a[%d][0] = %d%s", i, a[i][0], " ");
for (j = 1; j <= COUNT; j++)
{
a[i][j] = 1;
printf("a[%d][%d] = %d%s", i, j, a[i][j], (j == COUNT ? "\n" : " "));
}
}
free(a);
return 0;
}

Matrix (2d array) and its values is not written into txt file correctly

In my program, I enable the user to decide the dimensions of their matrix and then input each cell's value in the matrix. This matrix is then saved to a .txt file as binary data. Sometimes, with certain matrices of certain values and dimensions, the matrix is not read back properly with the correct values in the correct cells.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
int numberOfMatrices = 0;
int orderedMatricesInfo[100][1][2];
int matrixRows = 0;
int matrixCols = 0;
int** initMatrix(int rows, int cols);
void saveMatrix(int** matrix, int rows, int cols);
void* allocateMatrix(int rows, int cols);
int** readMatrix(int rows, int cols, int matrix[matrixRows][matrixCols], int matrixNum);
void displayMatrices();
void displayMatrix(int rows, int cols, int** matrix);
int main()
{
int n, m;
int** matrixPointer;
printf("Please enter the number of rows in your matrix: \n");
scanf("%d", &n);
printf("Please enter the number of columns in your matrix: \n");
scanf("%d", &m);
matrixPointer = initMatrix(n, m);
printf("%d\n", matrixPointer[0][0]);
displayMatrices();
printf("SUCCESS");
}
int** initMatrix(int rows, int cols)
{
int matrix[rows][cols];
int **matrixPointer;
matrixPointer = malloc(sizeof(int*)*cols);
for (int i =0; i < cols; ++i)
{
matrixPointer[i] = malloc(sizeof(int*)*cols);
}
for (int i = 0; i < rows; ++i)
{
for (int j = 0; j < cols; ++j)
{
printf("\nPlease enter element for [%d][%d]: \n", i, j);
scanf("%d", &matrixPointer[i][j]);
}
}
++numberOfMatrices;
orderedMatricesInfo[numberOfMatrices-1][0][0] = rows;
orderedMatricesInfo[numberOfMatrices-1][0][1] = cols;
allocateMatrix(rows, cols);
saveMatrix(matrixPointer, rows, cols);
return matrixPointer;
}
void saveMatrix(int** matrix, int rows, int cols)
{
char fullFileName[100] = "matrix";
char fileNameExtension[100] = ".txt";
char strNum[100];
sprintf(strNum, "%d", numberOfMatrices);
strcat(strNum, fileNameExtension);
strcat(fullFileName, strNum);
FILE *file = fopen(fullFileName, "ab");
for(int i=0; i<rows; ++i)
{
fwrite(matrix[i], sizeof(int), rows, file);
}
fclose(file);
}
void* allocateMatrix(int rows, int cols)
{
return malloc(sizeof(int[rows][cols]));
}
int** readMatrix(int rows, int cols, int matrix[matrixRows][matrixCols], int matrixNum)
{
int **matrixPointer;
matrixPointer = malloc(sizeof(int*)*cols);
for (int i =0; i < cols; ++i)
{
matrixPointer[i] = malloc(sizeof(int*)*cols);
}
char fullFileName[100] = "matrix";
char fileNameExtension[100] = ".txt";
char strNum[100];
sprintf(strNum, "%d", matrixNum);
strcat(strNum, fileNameExtension);
strcat(fullFileName, strNum);
FILE *file;
file=fopen(fullFileName, "rb");
fread(matrix, sizeof(int[rows][cols]), 1, file); // read 1 2D-array
for (int i = 0; i < rows; ++i)
{
for (int j = 0; j < cols; ++j)
{
matrixPointer[i][j] = matrix[i][j];
printf("%d", matrixPointer[i][j]);
}
}
allocateMatrix(rows, cols);
return matrixPointer;
}
void displayMatrices()
{
for (int matrixNum = 1; matrixNum <= numberOfMatrices; ++matrixNum)
{
char fullFileName[100] = "matrix";
char fileNameExtension[100] = ".txt";
char strNum[100];
sprintf(strNum, "%d", matrixNum);
strcat(strNum, fileNameExtension);
strcat(fullFileName, strNum);
matrixRows = orderedMatricesInfo[matrixNum -1][0][0];
matrixCols = orderedMatricesInfo[matrixNum -1][0][1];
int matrix[matrixRows][matrixCols];
int** matrixPointer;
matrixPointer = readMatrix(matrixRows, matrixCols, matrix, matrixNum);
printf("matrix %d", matrixNum);
displayMatrix(matrixRows, matrixCols, matrixPointer);
}
}
void displayMatrix(int rows, int cols, int** matrix)
{
for (int i = 0; i < rows; ++i)
{
printf("\n");
for (int j = 0; j < cols; ++j)
{
printf("%d ", matrix[i][j]);
}
}
printf("\n");
}
In the main function, when the user creates the matrix, the matrix is saved in a newly created file named "matrix1.txt" as binary data. However, it is not stored properly I think as when read back, the matrix is not shown correctly with the correct values.
For example, if I create a matrix:
[12, 19, 17, 15,
120, 566, 214, 153,
124, 1, 2, 3]
And then attempt to display the matrix then the matrix above is not shown, instead this is shown:
[12, 19, 17, 120,
566, 214, 124, 1,
2, 0, 101792956, 1]
Have I assigned memory incorrectly into this program? What would the problem be? As it does manage to get the first 3 elements of the top row retrieved and shown correctly. I am new to C so I cannot pinpoint the problem. When the matrix is smaller like a 2x2 matrix, then it works fine...
Thank you!
Your code is still missing information, but your initMatrix() function has a large number of small issues. You use cols where rows should be used to allocate pointers. You fail to validate any of the allocations or user-inputs. That is a recipe for Undefined Behavior. Additionally, you don't provide the code to determine what numberOfMatrices is, or how orderedMatricesInfo is declared. With those caveats noted, you can fix the immediate errors in initMatrix() with the following:
int **initMatrix(int rows, int cols)
{
int matrix[rows][cols];
int **matrixPointer;
/* allocate rows number of pointers */
matrixPointer = malloc (sizeof *matrixPointer * rows);
if (!matrixPointer) { /* validate EVERY allocation */
perror ("malloc-*matrixPointer");
return NULL;
}
/* you must allocate rows number of cols * sizeof(int) blocks
* assigning the starting address to each of your allocated pointers.
* (always use the dereferenced pointer to set type-size)
*/
for (int i = 0; i < rows; ++i)
{ /* use calloc on rows to initialize all bytes zero */
matrixPointer[i] = calloc (sizeof *matrixPointer[i], cols);
if (!matrixPointer[i]) { /* validate EVERY allocation */
perror ("calloc-matrixPointer[i]");
while (i--) /* on error, free prior memory */
free (matrixPointer[i]);
free (matrixPointer);
return NULL;
}
}
for (int i = 0; i < rows; ++i)
{
for (int j = 0; j < cols; ++j)
{
while (1) { /* loop continually until valid integer provided */
printf ("\nPlease enter element for [%d][%d]: \n", i, j);
/* validate EVERY user-input */
if (scanf("%d", &matrixPointer[i][j]) == 1)
break;
fputs (" error: invalid integer input.\n", stderr);
}
}
}
/* your code does not provide information on the following */
++numberOfMatrices;
orderedMatricesInfo[numberOfMatrices-1][0][0] = rows;
orderedMatricesInfo[numberOfMatrices-1][0][1] = cols;
allocateMatrix(rows, cols); /* why allocate -- that's what you just did?? */
saveMatrix(matrixPointer, rows, cols);
return matrixPointer;
}
(untested since your code is incomplete. The code is commented explaining the additions)
Note, your allocateMatrix(int rows, int cols) simply leaks memory. The return isn't assigned to any pointer so you have lost the beginning address to the allocated block with no way to free it.
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
Let me know if you have questions and please provide A Minimal, Complete, and Verifiable Example (MCVE) for further assistance.
Further Update on Errors
The remainder of your code has the same rows and cols problem where you attempt to allocate cols number of pointers (instead of rows number of pointers). However, the problem leading to your SEGFAULT was due to numberOfMatrices and the file you attempt to open being off-by-one. This was resolved by assuring your loops are consistently indexing 0 < numberOfMatrices and accommodating the file number with:
matrixPointer = readMatrix(matrixRows, matrixCols, matrix, matrixNum + 1);
Adding 1 to the matrixNum passed to readMatrix. That is a simple way to keep the numbering straight. You code writes and reads the file correctly, but note you are Appending to the file, so you will have to further work to access each of the matricies stored in your output file (you should write the number of rows and cols to the file before each matrix is written, so you can read the file back in, reading the 2 int values to determine the size of the matrix that follows -- that is left to you.
As it sits, your display function will read the file assuming the first integers in the file are for the current matrix -- which isn't the case. The integer values read to display are the elements for the first matrix that was written to the file, which will not be the same as the current matrix values unless you are writing and reading the first set of values. Otherwise, the current matrix values are contained in the file after the bytes for all previous matricies that were written to the file. A more useful file format would be:
no_matricies rows cols ...... rows cols ......
Where the first integer value written contains the number of matricies written to the file, followed by the row, col and .... data for each matrix which would allow all matricies to be accessed and allow the first integer value in the file to be updated without re-writing the entire file. (that too is left for you to consider)
Your cleaned-up code is as follows. Note: I changed your use of sprintf and eliminated the unnecessary concatenation. I also simplified copying from matrix to matrixPointer using memcpy():
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
int numberOfMatrices = 0;
int orderedMatricesInfo[100][1][2];
int matrixRows = 0;
int matrixCols = 0;
int** initMatrix(int rows, int cols);
void saveMatrix(int** matrix, int rows, int cols);
void* allocateMatrix(int rows, int cols);
int** readMatrix(int rows, int cols, int matrix[matrixRows][matrixCols], int matrixNum);
void displayMatrices();
void displayMatrix(int rows, int cols, int** matrix);
int main()
{
int n, m;
int** matrixPointer;
printf("Please enter the number of rows in your matrix: \n");
if (scanf("%d", &n) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
printf("Please enter the number of columns in your matrix: \n");
if (scanf("%d", &m) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
matrixPointer = initMatrix(n, m);
// printf("%d\n", matrixPointer[0][0]);
displayMatrices();
printf("SUCCESS");
}
int **initMatrix(int rows, int cols)
{
int **matrixPointer;
/* allocate rows number of pointers */
matrixPointer = malloc (sizeof *matrixPointer * rows);
if (!matrixPointer) { /* validate EVERY allocation */
perror ("malloc-*matrixPointer");
return NULL;
}
/* you must allocate rows number of cols * sizeof(int) blocks
* assigning the starting address to each of your allocated pointers.
* (always use the dereferenced pointer to set type-size)
*/
for (int i = 0; i < rows; ++i)
{ /* use calloc on rows to initialize all bytes zero */
matrixPointer[i] = calloc (sizeof *matrixPointer[i], cols);
if (!matrixPointer[i]) { /* validate EVERY allocation */
perror ("calloc-matrixPointer[i]");
while (i--) /* on error, free prior memory */
free (matrixPointer[i]);
free (matrixPointer);
return NULL;
}
}
for (int i = 0; i < rows; ++i)
{
for (int j = 0; j < cols; ++j)
{
while (1) { /* loop continually until valid integer provided */
printf ("\nPlease enter element for [%d][%d]: \n", i, j);
/* validate EVERY user-input */
if (scanf("%d", &matrixPointer[i][j]) == 1)
break;
fputs (" error: invalid integer input.\n", stderr);
}
}
}
/* move numberOfMatrices++ below the assignment */
orderedMatricesInfo[numberOfMatrices][0][0] = rows;
orderedMatricesInfo[numberOfMatrices][0][1] = cols;
numberOfMatrices++;
// allocateMatrix(rows, cols); /* why allocate -- that's what you just did?? */
saveMatrix(matrixPointer, rows, cols);
return matrixPointer;
}
void saveMatrix(int** matrix, int rows, int cols)
{
char fullFileName[256];
sprintf (fullFileName, "matrix-%02d.txt", numberOfMatrices);
FILE *file = fopen(fullFileName, "ab");
if (!file) { /* validate file open for writing */
perror ("fopen-file");
return;
}
for(int i=0; i<rows; ++i)
{
fwrite(matrix[i], sizeof *matrix[i], cols, file);
}
if (fclose(file) == EOF) /* always validate close after write */
perror ("fclose-file");
}
void *allocateMatrix(int rows, int cols)
{
return malloc(sizeof(int[rows][cols]));
}
int **readMatrix(int rows, int cols, int matrix[matrixRows][matrixCols], int matrixNum)
{
int **matrixPointer;
matrixPointer = malloc(sizeof *matrixPointer * rows); /* rows not cols!! */
if (!matrixPointer) { /* validate EVERY allocation */
perror ("malloc-*matrixPointer");
return NULL;
}
for (int i =0; i < rows; ++i) /* rows not cols!! */
{
matrixPointer[i] = calloc (sizeof *matrixPointer[i], cols);
if (!matrixPointer[i]) { /* validate EVERY allocation */
perror ("calloc-matrixPointer[i]");
while (i--) /* on error, free prior memory */
free (matrixPointer[i]);
free (matrixPointer);
return NULL;
}
}
char fullFileName[256];
sprintf (fullFileName, "matrix-%02d.txt", matrixNum);
FILE *file = fopen(fullFileName, "rb");
if (!file) { /* validate file open for reading */
perror ("fopen-file");
for (int i = 0; i < rows; i++) /* on error free memory */
free (matrixPointer[i]);
free (matrixPointer);
return NULL;
}
/* validate EVERY input */
if (fread (matrix, sizeof(int[rows][cols]), 1, file) < 1) { // read 1 2D-array
for (int i = 0; i < rows; i++) /* on error free memory */
free (matrixPointer[i]);
free (matrixPointer);
return NULL;
}
for (int i = 0; i < rows; ++i)
{
memcpy (matrixPointer[i], matrix[i], sizeof *matrixPointer[i] * cols);
/*
for (int j = 0; j < cols; ++j)
{
matrixPointer[i][j] = matrix[i][j];
printf("%d", matrixPointer[i][j]);
}
*/
}
// allocateMatrix(rows, cols); /* not needed */
return matrixPointer;
}
void displayMatrices()
{
for (int matrixNum = 0; matrixNum < numberOfMatrices; matrixNum++)
{
char fullFileName[256];
sprintf (fullFileName, "matrix-%02d.txt", numberOfMatrices);
matrixRows = orderedMatricesInfo[matrixNum][0][0];
matrixCols = orderedMatricesInfo[matrixNum][0][1];
int matrix[matrixRows][matrixCols];
int **matrixPointer;
matrixPointer = readMatrix(matrixRows, matrixCols, matrix, matrixNum + 1);
displayMatrix(matrixRows, matrixCols, matrixPointer);
}
}
void displayMatrix(int rows, int cols, int** matrix)
{
for (int i = 0; i < rows; ++i)
{
for (int j = 0; j < cols; ++j)
{
printf (" %2d", matrix[i][j]);
}
putchar ('\n');
}
putchar ('\n');
}
(note: there are a number of additional comments left in the code above, rather then detailing each suggested change in paragraph form)
Example Use/Output
$ ./bin/write_matrix
Please enter the number of rows in your matrix:
2
Please enter the number of columns in your matrix:
2
Please enter element for [0][0]:
1
Please enter element for [0][1]:
2
Please enter element for [1][0]:
3
Please enter element for [1][1]:
4
1 2
3 4
SUCCESS
Look things over and let me know if you have further questions.

How to initialize a 3D contiguous array in C

I know how to do a potentioal non-contiguous array in the following way:
int main () {
int ***array = (int***)malloc(3*sizeof(int**));
int i, j;
for (i = 0; i < 3; i++) {
// Assign to array[i], not *array[i] (that would dereference an uninitialized pointer)
array[i] = (int**)malloc(3*sizeof(int*));
for (j = 0; j < 3; j++) {
array[i][j] = (int*)malloc(3*sizeof(int));
}
}
array[1][2][1] = 10;
return 0;
}
with the code above, the array[0][j] blocks can be not contiguous. To get contiguous, I feel that we need to malloc in this way
int* array = (int*)malloc(3*3*3*sizeof(int));
int** y = (int**)malloc(3*3*sizeof(int**));
int*** x = (int***)malloc(3*sizeof(int***));
for(i = 0; i < 3; i++)
{
vals = vals + i*m*n;
x[i] = &vals;
for(j = 0; j < 3; j++)
{
x[i][j] = vals + j * n;
}
}
However, I got troulbe with address assignment. I am not a c programmer, can anyone correct my fault? Thanks in advance...
int*** x = (int***)malloc(3*sizeof(int***));
should be
int*** x = (int***)malloc(3*sizeof(int**));
Now initialization can be :
for(i = 0; i < 3; i++)
{
x[i] = y + 3*i;
for(j = 0; j < 3; j++)
{
x[i][j] = array + i*3*3 + j*3;
}
}
So that x[0] points to the first element of y, x[1] to the fourth, etc.
And x[0][0]=y[0] to the first of array, x[0][1]=y[1] to the fourth of array, etc.
To allocate a contiguous 3D array, you only need to do the following (assumes all dimensions are known at compile time):
#define D0 ...
#define D1 ...
#define D2 ...
...
T (*arr)[D1][D2] = malloc( sizeof *arr * D0 ); // for any type T
...
arr[i][j][k] = some_value();
...
arr is declared as a pointer to a D1xD2 array. We then allocate enough space for D0 such arrays (sizeof *arr == sizeof (T [D1][D2])).
With this method, all of the memory for the array is allocated contiguously. Also, you only need one call to free to deallocate the whole thing.
If your dimensions are not known until runtime and you're using a C99 compiler or a C2011 compiler that supports variable-length arrays, you're still in luck:
size_t d0, d1, d2;
...
T (*arr)[d1][d2] = malloc( sizeof *arr * d0 );
The main issue is how to pass this as an argument to a function. Assuming that D1 and D2 are known at compile time, if you decide to pass it as
foo( arr, D0 );
then the prototype for foo will need to be
void foo( T (*aptr)[D1][D2], size_t n )
{
...
aptr[i][j][k] = ...;
}
and it will only be useful for n x D1 x D2-sized arrays.
If you go the VLA route, you'll need to declare the dimensions and pass values for them as well:
void foo( size_t d0, size_t d1, size_t d2, T (*aptr)[d1][d2] ) // d1 and d2 *must* be
// declared before aptr
{
...
arr[i][j][k] = some_value();
}
void bar( void )
{
size_t d0, d1, d2;
...
T (*arr)[d1][d2] = malloc( sizeof *arr * d0 );
...
foo( d0, d1, d2, arr );
...
}
If you don't have a compiler that supports VLAs, but you still want to allocate this memory contiguously, then you'll have to go the old-fashioned route - allocate it as a 1D array and compute your offsets manually:
T *arr = malloc( sizeof *arr * d0 * d1 * d2 );
...
arr[i * d0 * d1 + j * d1 + k] = some_value();
I am using some pretty neat methods for allocating multi-dimensional arrays with row pointers. The functions multi_malloc and multi_free can be used for arrays with arbitrary dimensions and arbitrary types and they work on basically all platforms and from C and C++
You can allocate, e.g. a 3-dimensional array with row-pointers recursively. E.g. a 10x20x30 dimensional array
float*** data = (float***) multi_malloc(sizeof(float),3, 10,20,20);
access elements like
data[2][3][4] = 2.0;
and free everything like (data as well as row pointers)
multi_free(data,3);
The header, which I think should be part of C is
#pragma once
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#if (defined(_MSC_VER) && defined(_WIN32))
// Note when used inside a namespace, the static is superfluous
# define STATIC_INLINE_BEGIN static inline //__forceinline
# define STATIC_INLINE_END
#elif (defined(__GNUC__))
# define STATIC_INLINE_BEGIN static inline
# if defined(__CYGWIN__)
# define STATIC_INLINE_END
# else
# define STATIC_INLINE_END __attribute__ ((always_inline))
# endif
#endif
STATIC_INLINE_BEGIN void* multi_malloc(size_t s, size_t d, ...) STATIC_INLINE_END;
STATIC_INLINE_BEGIN void multi_free(void *r, size_t d) STATIC_INLINE_END;
/**
* Allocate multi-dimensional array and establish row pointers
*
* #param s size of each element
* #param d number of dimension
*
* #return
*/
STATIC_INLINE_BEGIN void* multi_malloc(size_t s, size_t d, ...) {
char* tree;
va_list ap; /* varargs list traverser */
size_t max, /* size of array to be declared */
*q; /* pointer to dimension list */
char **r, /* pointer to beginning of the array of the
* pointers for a dimension */
**s1, *t; /* base pointer to beginning of first array */
size_t i, j; /* loop counters */
size_t *d1; /* dimension list */
va_start(ap,d);
d1 = (size_t *) malloc(d*sizeof(size_t));
for(i=0;i<d;i++)
d1[i] = va_arg(ap,size_t);
r = &tree;
q = d1; /* first dimension */
if (d==1) {
max = *q;
free(d1);
return malloc(max*d);
}
max = 1;
for (i = 0; i < d - 1; i++, q++) { /* for each of the dimensions
* but the last */
max *= (*q);
r[0]=(char *)malloc(max * sizeof(char **));
r = (char **) r[0]; /* step through to beginning of next
* dimension array */
}
max *= s * (size_t) (*q); /* grab actual array memory */
r[0] = (char *)malloc(max * sizeof(char));
/*
* r is now set to point to the beginning of each array so that we can
* use it to scan down each array rather than having to go across and
* then down
*/
r = (char **) tree; /* back to the beginning of list of arrays */
q = d1; /* back to the first dimension */
max = 1;
for (i = 0; i < d - 2; i++, q++) { /* we deal with the last
* array of pointers later on */
max *= (*q); /* number of elements in this dimension */
for (j=1, s1=r+1, t=r[0]; j<max; j++) { /* scans down array for
* first and subsequent
* elements */
/* modify each of the pointers so that it points to
* the correct position (sub-array) of the next
* dimension array. s1 is the current position in the
* current array. t is the current position in the
* next array. t is incremented before s1 is, but it
* starts off one behind. *(q+1) is the dimension of
* the next array. */
*s1 = (t += sizeof (char **) * *(q + 1));
s1++;
}
r = (char **) r[0]; /* step through to begining of next
* dimension array */
}
max *= (*q); /* max is total number of elements in the
* last pointer array */
/* same as previous loop, but different size factor */
for (j = 1, s1 = r + 1, t = r[0]; j < max; j++)
*s1++ = (t += s * *(q + 1));
va_end(ap);
free(d1);
return((void *)tree); /* return base pointer */
}
/**
* Free multi-dimensional array and corresponding row pointers
*
* #param r data
* #param d number of dimensions
*/
STATIC_INLINE_BEGIN void multi_free(void *r, size_t d) {
void **p;
void *next=NULL;
size_t i;
for (p = (void **)r, i = 0; i < d; p = (void **) next,i++)
if (p != NULL) {
next = *p;
free(p);
p = NULL;
}
}
You can allocate memory for buffer of items where each item is a two dimensional array. So it is effectively is a three dimensional array:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 3
int main()
{
int (*array)[N][N] = malloc(N * N * N * sizeof(int));
/* set 0 to all values */
memset(array, 0, N * N * N * sizeof(int));
/* use as 3D array */
array[0][0][0] = 1;
array[1][1][1] = 2;
array[2][2][2] = 3;
int i;
/* print array as contiguous buffer */
for (i = 0; i < N * N * N; ++i)
printf("i: %d\n", ((int*) array)[i]);
free(array);
return 0;
}
So, in memory the array is placed as regular int array[N][N][N].
Although I think a normal array, created on the stack would be best:
int array[3][3][3];//can avoid a lot of free() calls later on
Here is a way to create a 3D array dynamically:
(I use calloc here instead of malloc as it creates initialized memory space)
int *** Create3D(int p, int c, int r)
{
int ***arr;
int x,y;
arr = calloc(p, sizeof(arr)); //memory for int
for(x = 0; x < p; x++)
{
arr[x] = calloc(c ,sizeof(arr)); //memory for pointers
for(y = 0; y < c; y++)
{
arr[x][y] = calloc(r, sizeof(int));
}
}
return arr;
}
Usage could be:
int ***array = Create3D(3,3,3);
for(i=0;i<3;i++)
for(j=0;j<3;j++)
for(k=0;k<3;k++)
array[i][j][k] = (i+1)*(j+1)*(k+1);
Note that the return of [c][m][re]alloc() is not cast in this example. Although not strictly forbidden in C, it is not recommended. (this is not the case in C++, where it is required)
Keep in mind, everything allocated, must be freed. Notice freeing is done in reverse order of allocating:
void free3D(int ***arr, int p, int c)
{
int i,j;
for(i=0;i<p;i++)
{
for(j=0;j<c;j++)
{
if(arr[i][j]) free(arr[i][j]);
}
if(arr[i]) free(arr[i]);
}
if(arr) free(arr);
}
Usage could be:
free3D(array,3,3);

Adding elements of an array using shared memory in C

I have a project to illustrate how to use shared memory in C. And this is my suggested assignment for my project this semester: adding up all elements in a 2d array, in a special way:
take input from user the row size (m) and column size (n), for example m = 4, n = 3.
the program will be called, for example: myadder 9 8 7 3 2 1 2 3 4 2 10 12 (these 12 numbers input are separated by white-space or return key)
create a shared memory 1d array of enough size to hold the entire above 2d array
then, create a shared memory 1d array of the size of the number of rows m. This array will be used to store the totals of each of the rows after it is calculated
the program then fork off a child process for each row in the array. This child process will total up its associated row and only it's row from shared memory, and store result in its associated element in another 1d array, called total_row
The parent process will wait until all children have finished, then add up all elements in total_row.
Can you give me hints to finish the above task?
I believe this should do the trick:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
int main ()
{
int w, h, i, j;
/* Read the width and height */
scanf ("%d %d", &w, &h);
/* Create and read the entire array */
int *arr = malloc (w * h * sizeof (int));
for (i = 0; i < w * h; ++i)
scanf ("%d", &arr[i]);
/* Obtain a shared memory segment with the key 42 */
int shm = shmget (42, h * sizeof (int), IPC_CREAT | 0666);
if (shm < 0)
{
perror ("shmget");
return 1;
}
/* Attach the segment as an int array */
int *row = shmat (shm, NULL, 0);
if (row < (int *) NULL)
{
perror ("shmat");
return 1;
}
for (i = 0; i < h; ++i)
/* Create h children and make them work */
if (!fork ())
{
for (j = row[i] = 0; j < w; ++j)
row[i] += arr[i * w + j];
return 0;
}
/* Wait for the children to finish up */
for (i = 0; i < h; ++i)
wait (&j);
/* Sum the row totals */
for (i = j = 0; i < h; ++i)
j += row[i];
printf ("%d\n", j);
/* Detach the shared memory segment and delete its key for later reuse */
shmdt (row);
shmctl (shm, IPC_RMID, NULL);
free (arr);
return 0;
}
Consider the following array declaration:
int arr[8];
What happens in memory when we make this declaration?
32 bytes are immediately reserved in memory, 4 bytes each for the 8 integers. Since the array is not being initialized, all 8 values present in it would be garbage values.
This happens because
the storage class of this array is assumed to be AUTO. If the storage class is declared to be STATIC, then all of the array elements would have a default initial value of 0.
Whatever be the initial values, all of the array elements would always be present in contiguous memory locations.
This arrangement of array elements in memory is shown in fig.
12 34 66 -45 23 346 77 90
65508 65512 65516 65520 65524 65528 65532 65536
This below code uses 2 shared memory segments..
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#define KEY_2D 12345
#define KEY_ROW 54321
int main(int argc, char **argv) {
int rows, cols;
scanf("%d %d", &rows, &cols);
if(rows <= 0 || cols <= 0) {
printf("invalid input\n");
return 1;
}
int *dataa_user = NULL; /* To get user input for 2D array */
int i = 0;
int shm_2d = -1;
dataa_user = (int *) malloc(rows * cols * sizeof(int));
/* Do you need to take input from user as 2D array? and then
* convert it back to 1D array?
* I wonder as this is probably your assignment to understand
* some C and Unix concepts
*/
for(i = 0; i < rows * cols; i ++)
scanf("%d", &dataa_user[i]);
/* Creating shared memory that holds 2D array as 1D array */
shm_2d = shmget(KEY_2D, rows * cols * sizeof (int), IPC_CREAT | 0666);
if(shm_2d < 0) {
perror("shmget");
if(dataa_user) free(dataa_user);
dataa_user = NULL;
return 1;
}
/* Attach to the shared memory */
void *data_2d = shmat(shm_2d, NULL, 0);
if(data_2d == (void *)-1) {
perror("shmat");
shmctl (shm_2d, IPC_RMID, NULL);
if(dataa_user) free(dataa_user);
dataa_user = NULL;
return 1;
}
int shm_row = -1;
/* Copy the 1D array to shared memory */
memcpy( data_2d, dataa_user, rows * cols * sizeof(int));
free(dataa_user);
dataa_user = NULL;
/* Creating shared memory to keep the sum of each row as 1D array */
shm_row = shmget(KEY_ROW, rows * sizeof (int), IPC_CREAT | 0666);
if(shm_row < 0) {
perror("shmget");
shmdt(data_2d);
shmctl (shm_2d, IPC_RMID, NULL);
return 1;
} /* this closing brace was missed when i posted it first time.. */
/* Attach to the shared memory */
void *data_row = shmat(shm_row, NULL, 0);
if(data_row == (void *)-1) {
perror("shmat");
shmdt (data_2d);
shmctl (shm_2d, IPC_RMID, NULL);
shmctl (shm_row, IPC_RMID, NULL);
return 1;
}
/* Initialize it to 0. */
memset(data_row, 0, rows * sizeof(int));
for(i = 0; i < rows; i ++) {
if(!fork()) {
int k = 0;
int *dataa_2d = (int *)data_2d;
int *total_row = (int *)data_row;
for(; k < cols; k ++)
total_row[i] += dataa_2d[i * cols + k]; //add data to shm[row index] for each col in that row
return 0;
}
}
int sts = 0;
for(i = 0; i < rows; i ++) {
wait(&sts); /* wait for all the children to exit. */
}
int total_2d = 0;
int *total_row = (int *)data_row;
for(i = 0; i < rows; i ++) {
total_2d += total_row[i]; /* main process adding up all the row sum values */
}
printf("%d\n", total_2d);
/* clean up of IPC(shms used) */
shmdt(data_2d);
shmdt(data_row);
shmctl (shm_2d, IPC_RMID, NULL);
shmctl (shm_row, IPC_RMID, NULL);
return 0;
}
Your problem statement only mandates use of fork() system call.. So, the problem as such is simple (taking advantage of COW)..
(If you were supposed to use exec() system calls, then it might help you understand the reality in linux systems.. Also if totalling of total_row was assigned to each child process, like summing up to 3rd shared memory or something, it would have helped in understanding synchronization.. )
Anyway, hope this helps..

Resources