1

在我的程序中,我使用户能够决定其矩阵的维度,然后在矩阵中输入每个单元格的值。然后将该矩阵作为二进制数据保存到 .txt 文件中。有时,对于具有某些值和维度的某些矩阵,无法在正确单元格中正确读取正确值的矩阵。

#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");
}

在主函数中,当用户创建矩阵时,矩阵作为二进制数据保存在一个新创建的名为“matrix1.txt”的文件中。但是,我认为它没有正确存储,因为当回读时,矩阵没有正确显示正确的值。例如,如果我创建一个矩阵:

[12, 19, 17, 15,
120, 566, 214, 153,
124, 1, 2, 3]

然后尝试显示矩阵然后上面的矩阵没有显示,而是显示:

[12, 19, 17, 120,
566, 214, 124, 1,
2, 0, 101792956, 1]

我是否错误地为该程序分配了内存?会有什么问题?因为它确实设法检索并正确显示了顶行的前 3 个元素。我是 C 新手,所以我无法查明问题所在。当矩阵像 2x2 矩阵一样小时,它可以正常工作......

谢谢!

4

1 回答 1

2

您的代码仍然缺少信息,但您的initMatrix()函数存在大量小问题。您使用colswhererows应该用于分配指针。您无法验证任何分配或用户输入。这是Undefined Behavior的秘诀。此外,您不提供代码来确定声明的内容numberOfMatricesorderedMatricesInfo声明方式。注意到这些警告后,您可以initMatrix()使用以下方法修复直接错误:

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;
}

(未经测试,因为您的代码不完整。代码注释解释了添加)

请注意,您allocateMatrix(int rows, int cols)只是泄漏内存。返回值没有分配给任何指针,因此您丢失了分配块的起始地址,无法释放它。

在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您有 2 个责任:(1)始终保留指向内存块起始地址的指针,(2)它可以在它不存在时被释放更需要。

如果您有任何问题,请告诉我,并请提供一个最小、完整和可验证的示例 (MCVE)以获得进一步的帮助。

错误的进一步更新

您的代码的其余部分具有相同的rows问题cols,您尝试分配cols指针数量(而不是rows指针数量)。但是,导致您的 SEGFAULT 的问题是由于numberOfMatrices您尝试打​​开的文件不合时宜。这是通过确保您的循环始终如一地索引0 < numberOfMatrices和容纳文件编号来解决的:

    matrixPointer = readMatrix(matrixRows, matrixCols, matrix, matrixNum + 1);

添加1到传递给的 matrixNum readMatrix。这是保持编号正确的简单方法。您的代码正确写入和读取文件,但请注意您正在附加到文件中,因此您必须进一步工作以访问存储在输出文件中的每个矩阵(您应该在每个矩阵之前写入文件的数量rowscols已写入,因此您可以重新读取文件,读取 2 个int值以确定后面的矩阵的大小 - 留给您。

当它坐下时,您的显示函数将读取文件,假设文件中的第一个整数用于当前矩阵 - 情况并非如此。读取以显示的整数值是写入文件的第一个矩阵的元素,除非您正在写入和读取第一组值,否则它将与当前矩阵值不同。否则,当前矩阵值包含在文件中写入文件的所有先前矩阵的字节之后。更有用的文件格式是:

no_matricies rows cols ...... rows cols ......

其中写入的第一个整数值包含写入文件的矩阵数,然后是row,col并且.... data对于每个矩阵,这将允许访问所有矩阵并允许更新文件中的第一个整数值而无需重写整个文件。(这也留给你考虑)

您清理后的代码如下。注意:我改变了你的使用sprintf并消除了不必要的连接。我还简化了从复制matrixmatrixPointer使用的过程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');
}

注意:上面的代码中还有一些额外的注释,而不是详细说明每个建议的更改段落形式)

示例使用/输出

$ ./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

如果您还有其他问题,请仔细查看并告诉我。

于 2020-11-11T02:23:15.927 回答