【问题标题】:Matrix (2d array) and its values is not written into txt file correctly矩阵(二维数组)及其值未正确写入 txt 文件
【发布时间】:2021-02-23 00:11:38
【问题描述】:

在我的程序中,我使用户能够决定其矩阵的维度,然后在矩阵中输入每个单元格的值。然后将该矩阵作为二进制数据保存到 .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 矩阵一样小时,它可以正常工作...

谢谢!

【问题讨论】:

  • matrixPointer = malloc(sizeof(int*)*cols); 您需要 rows 而不是 cols 指针数。您还需要matrixPointer[i] = malloc(sizeof(int*)*cols); 中的int 而不是int*(对于colsint 的数量而不是cols 的指针数量)
  • 我应用了更改,但是现在如果我尝试制作 3x4 矩阵,我会遇到分段错误?
  • 我需要一分钟来完成其余的工作,这些都是立即脱颖而出的。 orderedMatricesInfo[numberOfMatrices-1][0][0] = rows; 看起来很可疑。请提供A Minimal, Complete, and Verifiable Example (MCVE)。 (我可以复制和编译而无需创建函数原型和添加标题等。)
  • 嗯怎么了?我应该注意到 3d 数组负责存储每个数组的行数和列数。创建矩阵时,numberOfMatrices 变量递增,然后将行数存储在 [1][0][0] 中,将矩阵的列数存储在 [1][0][1] 中.
  • 这就是为什么我说给我一分钟时间来完成其余的代码。改成rows后要改循环,必须循环for (int i =0; i &lt; rows; ++i)

标签: c matrix multidimensional-array io txt


【解决方案1】:

您的代码仍然缺少信息,但您的initMatrix() 函数存在大量小问题。您使用cols,其中rows 应该用于分配指针。您无法验证任何分配或用户输入。这是未定义行为的秘诀。此外,您不提供代码来确定 numberOfMatrices 是什么,或者如何声明 orderedMatricesInfo。注意到这些警告后,您可以使用以下方法修复 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) 只会泄漏内存。 return 没有分配给任何指针,因此您丢失了分配块的起始地址,无法释放它。

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

如果您有任何问题,请告诉我,并提供A Minimal, Complete, and Verifiable Example (MCVE) 以获得进一步的帮助。

关于错误的进一步更新

您的代码的其余部分具有相同的rowscols 问题,您尝试分配cols 指针数量(而不是rows 指针数量)。但是,导致您的 SEGFAULT 的问题是由于numberOfMatrices 和您尝试打开的文件是一个接一个。通过确保您的循环始终如一地索引 0 &lt; numberOfMatrices 并使用以下文件编号来解决此问题:

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

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

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

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

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

您清理后的代码如下。注意:我更改了您对sprintf 的使用并消除了不必要的串联。我还使用memcpy() 简化了从matrixmatrixPointer 的复制:

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

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

使用/输出示例

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

检查一下,如果您还有其他问题,请告诉我。

【讨论】:

  • 将其复制到我的代码中后,我仍然遇到分段错误...?
  • 分段错误与代码的其他部分有关。如果您发布其余部分,那么我可以看到numberOfMatrices 是如何声明和初始化的(假设int0)然后orderedMatricesInfo 是什么(假设某个维度的3D 数组)。然后我可以验证你的其余代码。
  • fwrite(matrix[i], sizeof(int), rows, file); in saveMatrix() 有相同的 rows / cols 问题。你写cols 每行int 的数量。
  • 我明白了。我刚刚编辑了代码,所以它有 numberOfMatrices 变量和所有
  • 我已经确定 displayMatrices 函数是问题所在以及导致分段错误的原因......但是我不明白为什么
猜你喜欢
  • 1970-01-01
  • 2021-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-06
  • 1970-01-01
  • 2014-04-06
相关资源
最近更新 更多