分配有 malloc/calloc 的指针数组用 0 以外的值初始化

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

学校给我布置了一项 C 语言作业,要求我创建一个矩阵乘法程序。我将在下面列出分配限制,这样人们就不会回答关于我为什么这样做的问题。 来自讲师的约束:

我还没有实现矩阵乘法函数,因为我遇到的问题与文件读取或内存分配有关。

我遇到的具体问题是当我使用 malloc 或 calloc(都尝试过)将 space 分配给指针矩阵时,程序在输出的某些地方插入 33 而不是 0。我'此时我已经尝试了所有方法,我确信我对指针的了解存在根本性的缺陷。

p2.h(导师给的)

#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(抱歉,由于大量调试而造成的混乱)

#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(数据文件)

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

输出:./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

如果你注意到,我有一些调试代码检查数组中的当前项是否为 0。它似乎表明它们都是 0,让我认为这是一个打印问题,但我是甚至更多地迷失了造成这种情况的原因。 33的ascii码是感叹号,不知道有什么关系。

根据您应该使用的函数签名,您需要使用正确的索引数学将二维数组实现为一维数组。这将导致所有内存被连续布置,这完全不能用您现在分配内存的方式来保证(每个矩阵两次调用 malloc )。例如:

#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

你把简单的事情复杂化了。使用指向数组的指针并分配二维数组。

使用正确的尺寸变量类型。

尽量避免副作用。使用参数和函数 return 值。

//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("[%5d] ", 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

您需要检查错误(文件、内存等)。为了示例的简单起见,我跳过了它。