Home > Mobile >  Pointer arrays allocated with malloc/calloc initializing with values other than 0
Pointer arrays allocated with malloc/calloc initializing with values other than 0

Time:11-23

I have been given a school assignment in C to create a program that multiplies matrices. I will list assignment constraints below so people don't respond with questions as to why I am doing things this way. Constraints from instructor:

  • Cannot use square brackets anywhere in code (use pointer notation instead)
  • Matrices A, B, C must be single integer pointer variables (int *A, *B, *C)
  • Can only use main function and those specified by header
  • Must compile with "gcc -ansi -Wall -o p2 p2.c"

I have not implemented the matrix multiplication function yet, as the issues I am having relate to either file reading or memory allocation.

The specific problem I am having is when I allocate space to the pointer matrix with either malloc OR calloc (tried both), the program inserts 33 in some places in the output instead of 0. I've tried everything at this point and am convinced my knowledge of pointers is fundamentally flawed.

p2.h (given by instructor)

#include <stdio.h>
#include <stdlib.h>
/* This function reads m, n, and p from the datafile.  
    It then allocates the correct amount of memory required for matrices
    A, B, and C.
    Then matrices A and B are filled from the datafile.
    The values for m, n, and p are passed by reference, and are
    thus filled in by this function
    PARAMETERS in order are:
    int **      matrix A
    int **      matrix B
    int **      matrix C    
    int *       m   The number of rows in matrix A
    int *       n   The number of columns in matrix A and
                    The number of rows in matrix B
    int *       p   The number of columns in matrix B
    char *      The name of the datafile, from the command line
*/
void read_matrices(int **, int **, int **,  int *, int *, int *, char *);
/*  This function prints a matrix.  Rows and columns should be preserved.
    PARAMETERS in order are:
    int *       The matrix to print
    int         The number of rows in the matrix
    int         The number of columns in the matrix
*/    
void print_matrix(int *, int, int);
/*  The two matrices A and B are multiplied, and matrix C contains the
    result.
    PARAMETERS in order are:
    int *       Matrix A
    int *       Matrix B
    int *       Matrix C
    int         m
    int         n
    int         p
*/    
void mult_matrices(int *, int *, int *, int, int, int);

p2.c (sorry for the mess a lot of debugging went on)

#include <stdio.h>
#include <stdlib.h>
#include "./p2.h"

/* constants for testing */
#define cM 3
#define cN 2
#define cP 5

int main(int argc, char **argv) {
    if (argc < 2) {
        printf("Must include an argument.\n");
        exit(1);    
    }
    char *path = *(argv   1);

    int *m = (int *) malloc(sizeof(int));
    int *n = (int *) malloc(sizeof(int));
    int *p = (int *) malloc(sizeof(int));
    *m = cM; *n = cN; *p = cP;

    int i,j; /* loop counters */
    /* allocate space for 2d pointer arrays */
    int **A = NULL; 
    A = (int **) malloc(*m * sizeof(int *));
    for (i = 0; i < *m; i  ) {
        *(A i) = (int *) malloc(*n * sizeof(int)); 
    }   

    int **B = NULL;
    B = (int **) malloc(*n * sizeof(int *));
    for (i = 0; i < *n; i  ) {
        *(B i) = (int *) malloc(*p * sizeof(int)); 
    }   

    int **C = NULL;
    C = (int **) malloc(*m * sizeof(int *));
    for (i = 0; i < *m; i  ) {
        *(C i) = (int *) malloc(*p * sizeof(int)); 
    }   

    /* write data to A */
    for (i = 0; i < *m; i  ) {
        for (j = 0; j < *n; j  ) {
            *(*(A i) j) = 0;    
        }
    }

    /* testing a */
    for (i = 0; i < *m; i  ) {
        for (j = 0; j < *n; j  ) {
            if (*(*(A i) j) != 0) {
                printf("[x]");
            } else {
                printf("[0]");  
            }
        }
    }
    printf("\n");

    /* write data to B */
    for (i = 0; i < *n; i  ) {
        for (j = 0; j < *p; j  ) {
            *(*(B i) j) = 0;    
        }
    }

    /* testing b */
    for (i = 0; i < *n; i  ) {
        for (j = 0; j < *p; j  ) {
            if (*(*(B i) j) != 0) {
                printf("[x]");
            } else {
                printf("[0]");  
            }
        }
    }
    printf("\n");

    /* write data to C */
    for (i = 0; i < *m; i  ) {
        for (j = 0; j < *p; j  ) {
            *(*(C i) j) = 0;    
        }
    }

    /* testing c */
    for (i = 0; i < *m; i  ) {
        for (j = 0; j < *p; j  ) {
            if (*(*(C i) j) != 0) {
                printf("[x]");
            } else {
                printf("[0]");
            }
        }
    }
    printf("\n");



    printf("Matrix A: \n");
    print_matrix(*A, *m, *n);
    printf("Matrix B: \n");
    print_matrix(*B, *n, *p);
    printf("Matrix C: \n");
    print_matrix(*C, *m, *p);

    return 0;
}

void read_matrices(int **A, int **B, int **C, int *m, int *n, int *p, char *path) {
    FILE *fptr;
    fptr = fopen(path, "r");
    if (fptr == NULL) {
        printf("Cannot open file: ./p2 [filename].txt\n");  
        exit(1);
    }

    /* get first 3 numbers from file, set m,n,p */
    *m = fgetc(fptr);
    fgetc(fptr);
    *n = fgetc(fptr);
    fgetc(fptr);
    *p = fgetc(fptr);
    fgetc(fptr);

    /* read first matrix */
    /* 1) calculate matrix size m x n
     * 2) loop through malloc'ed matrix
     * 3) each loop, insert char in loc
     * 4) if next char NOT 10/32, add nextchar*10 to value in loc 
     */
    char cur;
    while ( (cur = fgetc(fptr)) != EOF ) {
        if (cur == 10 || cur == 32) {
            /* do nothing :) */
        } else {
            *m = cur;
            *n = cur;
            *p = cur;
            break;
        }
    }
    
    printf("m: %c\n", *m);
    printf("n: %c\n", *n);
    printf("p: %c\n", *p);
    printf("next: %c\n", fgetc(fptr));

    fclose(fptr);
}

void print_matrix(int *X, int rows, int cols) {
    int r, c;
    int k = 0;
    for (r = 0; r < rows; r  ) {
        for (c = 0; c < cols; c  )  {
            printf("\t%d", *(X k));
            k  ;
        }
        printf("\n");
    }
}

void mult_matrices(int *A, int *B, int *C, int m, int n, int p) {

}

d2.txt (data file)

3
2
4
1 2
3 4
5 6
7 8 9 10
11 12 13 14

Output: ./p2 d2.txt

[0][0][0][0][0][0]
[0][0][0][0][0][0][0][0][0][0]
[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]
Matrix A:
        0       0
        0       0
        0       0
Matrix B:
        0       0       0       0       0
        0       33      0       0       0
Matrix C:
        0       0       0       0       0
        0       33      0       0       0
        0       0       0       0       33

If you notice, I have some debug code that checks whether or not the current item in the array is 0. It seems to indicate that they are all 0, making me think it is a printing problem, but I am even more lost on what would be causing that. The ascii code for 33 is an exclamation point, but I am not sure what relevance it has.

Please let me know if I forgot any important info or anything needs elaboration. Any help is greatly appreciated :)

Edit: Thanks everyone for submitting! I'm surprised the comments got so heated, and I definitely deserve the downvote for not thinking haha

CodePudding user response:

Based on the function signatures you're supposed to use, you need to implement your 2D arrays as 1D with the correct index math. This will result in all memory being laid out contiguously, which is not at all guaranteed with the way you're allocating memory now (two calls to malloc for each matrix). For example:

#include <stdio.h>
#include <stdlib.h>

void print_matrix(int* A, int rows, int cols)
{
  for (int r=0; r<rows; r  )
  {
    for (int c=0; c<cols; c  )
    {
      // If you want to treat A as a 2D matrix, this is where we have to do a bit of
      // fancy index math to give you what double bracket notation [][] does for you
      //    r * cols gives you the index of the right row
      //        c give you the column offset in that row
      //        add that offset to A then dereference
      printf("%d\t", *(A   (r * cols   c)));
    }
    printf("\n");
  }
}

int main(void)
{
  // matrix A is supposed to be m by n
  int* A;
  // read these from file, or where ever they're supposed to come from
  int m = 2;
  int n = 10;
  // Allocate the memory in one chunk. This makes the memory all contiguous, just the
  // same as if you had done A[m][n]. However, the double call malloc for each int**
  // matrix probably will not give you contiguous memory for the entire matrix. Each
  // call to malloc is independent.
  A = malloc(m * n * sizeof(int)); // or sizeof(*A) would be even better
  if (A == NULL)
  {
      // handle error
  }

  // We can initialize values for A at this point, still not needing to care about
  // rows or columns
  for (int i=0; i<m*n; i  )
  {
    *(A   i) = i;  // using i for a better visual when we print
  }

  print_matrix(A, m, n);
  free(A);

  return 0;
}

Demo

CodePudding user response:

You are ovecomplicating simple things. Use pointers to arrays and allocate 2D array.

Use the correct type of your size variables.

Try to avoid side effects. Use parameters and function return values.

//this function is for the test purposes only
int writefile(const char *fn)
{
    FILE *fo = fopen(fn, "w");
    fprintf(fo, 
    "3\n"
    "2\n"
    "4\n"
    "1 2\n"
    "3 4\n"
    "5 6\n"
    "7 8 9 10\n"
    "11 12 13 14\n");
    fclose(fo);
}

void *allocIntMatrix(size_t rows, size_t cols)
{
    int (*m)[cols] = malloc(rows * sizeof(*m));
    return m;
}

void printIntMatrix(size_t rows, size_t cols, int (*m)[cols])
{
    for(size_t row = 0; row < rows; row  )
    {
        for(size_t col = 0; col < cols; col  )
        {
            printf("[]] ", m[row][col]);
        }
        printf("\n");
    }
}

int readData(FILE *fi, size_t rows, size_t cols, int (*m)[cols])
{
    for(size_t row = 0; row < rows; row  )
    {
        for(size_t col = 0; col < cols; col  )
        {
            fscanf(fi, "%d", &m[row][col]);
        }
    }
    return 0;
}

int main(int argc, char **argv) 
{
    size_t n,m,p;

    writefile("a.aaa");

    FILE *fi = fopen("a.aaa", "r");
    fscanf(fi, "%zu", &m);
    fscanf(fi, "%zu", &n);
    fscanf(fi, "%zu", &p);

    printf("n = %zu, m = %zu, p = %zu\n", n, m, p);

    int (*A)[n] = allocIntMatrix(m, n);
    int (*B)[p] = allocIntMatrix(n, p);

    readData(fi, m, n, A);
    readData(fi, n, p, B);

    fclose(fi);

    printIntMatrix(m, n, A);
    printf("\n");
    printIntMatrix(n, p, B);

    return 0;
}

https://godbolt.org/z/adoEx1r4f

You need to check for errors (file, memory etc). I skipped it for the sake of simplicity of the example.

  • Related