Triple pointer as a param - Matrix Multiplication - c

I am working on a Matrix Multiplication problem and I am dynamically allocating arrays
Here is what I currently have:
global:
int **a;
in my allocatematrix function: (m - row, k - col)
a = (int **)malloc(m * sizeof(int *));
for (i=0; i<m; i++)
{
a[i] = (int *)malloc(k * sizeof(int));
}
// Note that arr[i][j] is same as *(*(arr+i)+j)
// just to test my array allocation is working
for (i = 0; i < m; i++)
{
for (j = 0; j < k; j++)
{
a[i][j] = ++count; // OR *(*(arr+i)+j) = ++count
}
}
for (i = 0; i < m; i++)
{
for (j = 0; j < k; j++)
{
printf("%d ", a[i][j]);
}
printf("\n");
}
// I would like to pass my pointer to pointer
// into a subroutine, such that it transforms the
// the global double array, but it keeps blowing up here
loadMatrix(fp, &a, m, k);
load matrix function:
// read in the file
void loadMatrix(FILE *fp, int ***arr, int size1, int size2)
{
//fp = fopen(name, "r");
if (fp == NULL)
{
printf("Error while opening file!\n");
exit(0);
}
int i, j;
for(i = 0; i < size1; i++)
{
for(j = 0; j < size2; j++)
{
int value = 0;
fscanf(fp, "%d", &value);
printf("Current Value: %d\n", value);
//value = (((arr + i)) + j);
// line below is where I think I have the issue
*(*(*(arr+i)+j)) = value;
}
}
}
sample run: with this line commented ((*(arr+i)+j)) = value;
3 2 3
1 2
3 4
5 6
Current Value: 1
Current Value: 4
Current Value: 2
Current Value: 5
Current Value: 3
Current Value: 6
with out commented out:
3 2 3
1 2
3 4
5 6
Current Value: 1
Current Value: 4
Current Value: 2
Segmentation fault (core dumped)

You don't need a int *** pointer, if you are passing a pointer, the data it points to will be modified by the function, what you can do is this
// read in the file
void loadMatrix(FILE *fp, int **arr, int size1, int size2)
{
if (arr == NULL)
return;
if (fp == NULL)
{
printf("Error while opening file!\n");
exit(0);
}
int i, j;
for (i = 0 ; i < size1 ; i++)
{
for (j = 0 ; j < size2 ; j++)
{
int value = 0;
/* test that fscanf() succeeded reading an integer */
if (fscanf(fp, "%d", &arr[i][j]) != 1)
arr[i][j] = 0; /* this just prevents that arr[i][j] be uninitialized */
}
}
}
Where you say you test your allocation is working, that doesn't test anything, the only test you can performa is the return value from malloc(), if the allocation fails it returns NULL, so testing that your allocation worked is done like this
a = malloc(m * sizeof(int *));
if (a == NULL)
pleaseDoSomethingAboutIt_AllocationFailed_DoNotContinue();
for (i = 0 ; i < m ; i++)
{
a[i] = malloc(k * sizeof(int));
if (a[i] == NULL)
{
while (--i)
free(a[i]);
free(a);
pleaseDoSomethingAboutIt_AllocationFailed_DoNotContinue();
}
}
If the allocation fails, and you still dereference the pointer, like in your test, you will invoke undefined behavior, and hence you can't test for anything, because you can't know what is going to happen.

Related

Reallocing and manipulating a 2d-array inside a function

I am trying to reallocate both elements of a 2D-array and also manipulate the values in the 2D-array within the same function. But I just can't seem to get it to work. On compiling the code doesn't show any errors, but when running it will only ever print the amount of lines I specified as the initial_size at the beginning of the main function.
So it seems that the inner realloc is working fine, as it always prints an entire row once it gets started. But the outer realloc is not working, as it will only print a couple of rows.
Note: The real code takes input of unknown size, from getchar() / scanf(). That is why the realloc functions are inside loops in the function.
Simplified version of the function, with error handling omitted:
void func(int ***A) {
int i, j;
int len = 2;
int len2 = 2;
for (i = 0; i < 10; i++) {
// Check to see if a realloc is needed.
if (i >= len) {
len *= 2;
int **tmp = realloc(*A, len * sizeof(int*));
*A = tmp;
printf("Len1 = %d\n", len);
}
len2 = 2;
for (j = 0; j < 20; j++) {
// Check to see if a realloc is needed.
if (j >= len2) {
len2 *= 2;
int *new_row = realloc((*A)[i], len2 * sizeof(int));
(*A)[i] = new_row;
}
// Assign value.
(*A)[i][j] = i * j;
}
}
}
int main() {
int i, j;
int initial_size = 2;
int **A;
// Malloc with a starting size of 2 (could be any size).
A = malloc(initial_size * sizeof(int*));
for (i = 0; i < initial_size; i++) {
A[i] = malloc(initial_size * sizeof(int));
}
// Call function.
func(&A);
// Print the results, row by row.
for (i = 0; i < 10; i++) {
for (j = 0; j < 20; j++) {
printf("%d, ", A[i][j]);
}
printf("\n");
}
return 0;
}
I have been stuck for a while now, so any help is greatly appreciated :)
When you realloc in the outer loop, you increase the numbers of pointers from two (those created in main) to four.
The value of the two pointers from main are copied to the new memory area.
The value of the two new pointers are indeterminate and that's your problem. You never initialize them by allocating memory - yet you use them in the other loop.
Further, it seems that you realloc the inner array dimensions individually but you only track one length (i.e. len2). That's also a problem.
And the line len2 = 2 between the loops are wrong as you loose information about previously allocated memory.
There are multiple problems in your code:
you reallocate the pointer array but do not initialize the pointers in the newly allocated portion
you only reallocate the first int array pointed to by the pointer array
you do not initialize the newly allocated area in this int array.
Note that 2D-matrices are more idiomatic in C as arrays of arrays, but it is difficult to manipulate such arrays when the outer dimension is not fixed at compile time.
You should use a reallocation function with specified dimensions for the current and target sizes and deal with reallocating and freeing the blocks appropriately. Also avoid triple pointers: just return the potentially reallocated outer array.
#include <stdio.h>
#include <stdlib.h>
int **func(int **A, int rows, int cols, int new_rows, int new_cols) {
int i, j;
/* free the rows that are discarded */
if (new_rows < rows) {
for (i = new_rows; i < rows; i++) {
free(A[i]);
}
}
/* free the outer array if new rows is zero */
if (new_rows == 0) {
free(A);
return NULL;
}
/* reallocate the outer array if required */
if (new_rows != rows) {
A = realloc(A, sizeof(*A) * new_rows);
}
/* reallocate the existing rows */
if (new_cols != cols) {
for (i = 0; i < rows; i++) {
A[i] = realloc(A[i], sizeof(int) * new_cols);
if (new_cols > cols) {
for (j = cols; j < new_cols; j++)
A[i][j] = 0;
}
}
}
/* allocate the new rows (initialized to 0) */
for (i = rows; i < new_rows; i++) {
A[i] = calloc(sizeof(int), new_cols);
}
return A;
}
int main() {
int **A = NULL;
/* reallocate to 10x20 */
A = func(A, 0, 0, 10, 20);
// Print the results, row by row.
for (i = 0; i < 10; i++) {
for (j = 0; j < 20; j++) {
printf("%d, ", A[i][j]);
}
printf("\n");
}
/* reallocate to 0x0 (free the matrix) */
func(A, 10, 20, 0, 0);
return 0;
}
Note that the above code does not check for memory allocation failure. To deal with this possibility, it would be much simpler to allocate a new array and copy the current values, then free the previous matrix if no allocation error occurred. It would also be more efficient to allocate all rows as a single block of memory. Below is an example of this approach:
#include <stdio.h>
#include <stdlib.h>
int **func(int **A, int rows, int cols, int new_rows, int new_cols) {
int i, j;
int **B = NULL;
if (new_rows == rows && new_cols == cols)
return A;
if (new_rows != 0 && new_cols != 0) {
/* allocate the new matrix */
B = malloc(sizeof(*B) * new_rows);
if (B == NULL)
return NULL;
B[0] = calloc(sizeof(int) * new_cols, new_rows);
if (B[0] == NULL) {
free(B);
return NULL;
}
/* initialize the row pointers */
for (i = 1; i < new_rows; i++) {
B[i] = B[i - 1] + new_cols;
}
/* copy the current data */
for (i = 0; i < new_rows && i < rows; i++) {
for (j = 0; j < new_cols && j < cols; i++) {
B[i][j] = A[i][j];
}
}
}
/* free the previous matrix */
if (A != NULL) {
free(A[0]);
free(A);
}
return B;
}
int main() {
int **A = NULL;
int i, j;
/* reallocate to 10x20 */
A = func(A, 0, 0, 10, 20);
if (A == NULL) {
printf("Matrix reallocation failed\n");
return 1;
}
// Print the results, row by row.
for (i = 0; i < 10; i++) {
for (j = 0; j < 20; j++) {
printf("%d, ", A[i][j]);
}
printf("\n");
}
/* reallocate to 0x0 (free the matrix) */
func(A, 10, 20, 0, 0);
return 0;
}

initialization of arrays while operating with mallocs

Given the following piece of code, I don't understand why do we have to initialize every single row of the matrix when we have already created enough space in the stack.
#include <stdio.h>
#include <stdlib.h>
main() {
int **w;
int i, j;
int m, n;
printf("Number of rows in the matrix: ");
scanf("%d", &m);
printf("Number of columns in the matrix: ");
scanf("%d", &n);
w = (int **)malloc(m * n * sizeof(int));
for (i = 0; i < m; i++)
w[i] = (int *)malloc(n * sizeof(int));
for (i = 0; i < m; i++)
for (j = 0; j < n; j++) {
printf("Element [%d][%d]: ", i + 1, j + 1);
scanf("%d", &w[i][j]);
}
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
printf("Element [%d][%d]: %d\n", i + 1, j + 1, w[i][j]);
}
There are many issues in your code:
space is not allocated on the stack, but from the heap.
in both cases, memory allocated for the objects is uninitialized, which means it is not initialized to anything in particular and can have any value whatsoever. Relying on any particular contents is undefined behavior.
the matrix dimensions and all the matrix elements are read from standard input with scanf(). Yet you do not check for scanf() failure to convert integers from the characters read from stdin, so any invalid or missing input is going to cause undefined behavior at some point in the program.
your matrix is actually structured as an array of pointers to arrays of int, which is fine, but inconsistent with the size arguments used to allocate the first array: w = (int **)malloc(m * n * sizeof(int)); should be
w = malloc(m * sizeof(*w));
you could easily get objects pre-initialized to 0 by using calloc() instead of malloc():
for (i = 0; i < m; i++)
w[i] = calloc(n, sizeof(int));
you should also check for malloc() failure and exit with an appropriate diagnostic message.
main() is an obsolete prototype for the main function. You should either use int main(), int main(void) or int main(int argc, char *argv[])...
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int get_int(void) {
int n;
if (scanf("%d", &n) != 1) {
printf("invalid input\n");
exit(EXIT_FAILURE);
}
return n;
}
void xalloc(size_t size) {
void *p = calloc(size, 1);
if (p == NULL) {
printf("out of memory for %zu bytes\n", size);
exit(EXIT_FAILURE);
}
return p;
}
int main() {
int **w;
int i, j;
int m, n;
printf("Number of rows in the matrix: ");
m = get_int();
printf("Number of columns in the matrix: ");
n = get_int();
w = xalloc(m * sizeof(*w));
for (i = 0; i < m; i++) {
w[i] = xalloc(n * sizeof(int));
}
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
printf("Element [%d][%d]: ", i + 1, j + 1);
w[i][j] = get_int();
}
}
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
printf("Element [%d][%d]: %d\n", i + 1, j + 1, w[i][j]);
}
}
for (i = 0; i < m; i++) {
free(w[i]);
}
free(w);
return 0;
}

Is it possible to load a matrix and its size from a file?

Basically, the input file should look like this:
4
1 2 3 4
2 1 4 3
4 3 2 1
3 4 1 2
Where the first line is the size of the square matrix. However, I can't properly load the input directly into n and then into the matrix. I avoided such problem by creating a "loader" array.
int n, loader[100], p=0;
while(feof(data) == 0) {
if(p == 0) {
fscanf(data, "%d", &n); //taking n
p++;
} else {
fscanf(data, "%d", &loader[p]); //taking matrix values for p>0
p++;
}
}
//loading the matrix
int mat[n][n], o = 1; //o is set to 1, as the loader
//has been loaded from position 1.
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++){
printf("%d\n", loader[o]);
mat[i][j] = loader[o];
o++;
}
}
However, I think it is just unnecessary and there might be a faster way to directly take the matrix size and its values. When I programmed in such way, I received a welcoming Segmentation Fault error.
This code seems to work:
int loadMatrix(char *pth)
{
int i, j, n, **mat, p = 0, num;
FILE *fd;
fd = fopen(pth, "r");
if(fd == NULL) return(-1);
/* Read matrix size */
if(fscanf(fd, "%d", &n) == EOF) return(-1);
printf("Size: %d\n", n);
mat = malloc(n * sizeof(int *));
for(i = 0; i < n; i++) mat[i] = malloc(sizeof(int) * n);
while(fscanf(fd, "%d", &num) != EOF && p < (n * n)) {
mat[p / n][p % n] = num;
p++;
}
for(i = 0; i < n; i++) {
for(j = 0; j < n; j++) {
printf("%d ", mat[i][j]);
}
printf("\n");
}
for(i = 0; i < n; i++) free(mat[i]);
free(mat);
fclose(fd);
return(0);
}

Signal 11 SIG error and passing argument 1 of free makes pointer from integer without a cast

I am writing a program to read and store a 3D array and then print all 2D sections, I get this warning (for the free(*mat1)[i][j]):
|warning: passing argument 1 of 'free' makes pointer from integer without a cast|
When I run the program in my computer, the program works just fine but when I submit it in the system I get an error like this:
Type of error: SIG
Message: Program was stopped by signal 11 [0.000000 sec]. Either Memory limit of 4000 Kb exceeded or invalid memory operation.
Here is my complete code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int m,n,p,i,j,k;
int *** mat1;
scanf("%d",&m);
scanf("%d",&n);
scanf("%d",&p);
mat1 =(int ***) malloc(m * sizeof(int **));
if (mat1 == NULL)
{
printf("Error 1");
exit(1);
}
for(i = 0; i < m; i++)
{
mat1[i] =(int **) malloc(n * sizeof(int *));
if (mat1[i] == NULL)
{
printf("Error 2");
exit(1);
}
for (j=0 ; j<n ; j++)
{
mat1[i][j] = (int * )malloc(p * sizeof(int ));
if (mat1[i][j] == NULL)
{
printf("Error 3");
exit(1);
}
}
}
for(i=0;i<m;i++) // reading matrix A input
{
for(j=0;j<n;j++)
{
for (k = 0 ; k < p ; k++)
scanf("%d",&mat1[i][j][k]);
}
}
for(i=0;i<p;i++) //output matrix A
{
printf("Section %d: \n", i+1);
for(j=0;j<n;j++)
{
for (k = 0 ; k <m ; k++)
{
printf("%d ",mat1[k][j][i]);
}
printf("\n");
}
}
for (i = 0; i < m; i++)
{
for (j = 0; j< n; j++)
free((*mat1)[i][j]); //this row is where the warning is coming from
free((*mat1)[i]);
}
free(*mat1);
return 0;
}
This line worked:
mat1[i][j] = (int * )malloc(p * sizeof(int ));
because mat1 is a int***, so that mat1[i][j] is an int*.
But this doesn't:
free((*mat1)[i][j]);
because *mat1 is a int**, so that (*mat1)[i][j] is an int, which is exactly what the warning in complaining about.
I believe what you want is:
free(mat1[i][j]);
which corresponds to the malloc referenced above.

Reading a text file into a two dimentional array in C

I have a text file that looks like the following.
5
2 7
3 4 2
Basically,
row 1 has 1 element,
row 2 has 2 elements,
row 3 has 3 elements,
...
up to n rows with n elements.
I need to read them, and put into a 2-d array in this fashion:
a[0][0] = 5
a[1][0] = 2
a[1][1] = 7
a[2][0] = 3
a[2][1] = 4
a[2][2] = 2
...
You get the drift.
However I know n (the number of rows) only at run time. How would I go about reading the file into a 2x2 array?
I know I can do the following if I know the number of elements in each line of text, and if that number is the same for each line.
fa = fopen("file.txt", "r");
for(i = 0; i < n; i++) {
fgets(str, 1000, fa);
sscanf(str, "%d %d %d", &a[i][0], &a[i][1], &a[i][2]);
}
fclose(fa);
But it wouldn't help me here as I have varying number of elements in each row.
How do I go about this?
Allocate memory for the array like this:
int** array;
array = malloc(n * sizeof(*array)); /* Assuming `n` is the number of rows */
if(!array) /* If `malloc` failed */
{
fputs(stderr, "Error allocating memory; Bailing out!");
exit(-1);
}
int count = 1;
for(int i = 0; i < n; i++)
{
array[i] = malloc(count * sizeof(**array));
if(!array[i]) /* If `malloc` failed */
{
for(int j = 0; j < i; j++) /* free previously allocated memory */
{
free(array[j]);
}
free(array);
fputs(stderr, "Error allocating memory; Bailing out!");
exit(-1);
}
count++;
}
Then, read data from the file into the array by using:
FILE* fp = fopen("file.txt", "r");
if(!fp)
{
for(int i = 0; i < n; i++) /* free previously allocated memory */
{
free(array[i]);
}
free(array);
fputs(stderr, "Error opening 'file.txt'; Bailing out!");
exit(-1);
}
int max = 1;
for(int i = 0; i < n; i++)
{
for(count = 0; count < max; count++)
{
fscanf(fp, "%d", &array[i][count]);
}
max++;
}
Then print the results:
max = 1;
for(int i = 0; i < n; i++)
{
for(count = 0; count < max; count++)
{
printf("array[%d][%d] = %d", i, count, array[i][count]);
}
max++;
}
And finally, free the allocated memory:
for(int i = 0; i < n; i++)
{
free(array[i]);
}
free(array);

Resources