如何从C中的文本文件填充矩阵(结构)?

时间:2015-10-29 19:32:30

标签: c matrix

我试图创建一个程序来读取文本文件并填充结构中的矩阵,但我遇到了一些问题。

#include <stdio.h>

#define MAX 100

typedef struct {
    int matrixgrafh[MAX][MAX];
} matrix;

int LoadMatrix(matrix* m);

main()
{
    int j,k;
    matrix m;

    LoadMatrix(&m);
    for(j = 0;j < 20;j++)
    {
        for(k = 0;k < 20;k++)
        {
            printf("%d",m.matrixgrafh[j][k]);
        }
    }
}

int LoadMatrix(matrix* m)
{
    FILE *stuff;
    int j,k;
    char c;

    if((stuff=fopen("matrix.txt","r"))==NULL)
    {
        printf("File missing...");
        exit(1);
    }
    while (!feof(stuff))
    {
         do
         {
            c = fgetc(stuff);
            if (c == '1' || c == '0' && c != '\n' && !feof(stuff))
            //corrected c == '1' && c == '0' to c == '1' || c == '0'
            {
                for(j = 0;j < 20;j++)
                {
                    for(k = 0;k < 20;k++)
                    {
                        m->matrixgrafh[j][k] = c;
                    }
                }
            }
         } while (!feof(stuff));
    }
    return m->matrixgrafh;
}

想法是从文本文件中读取矩阵,如下所示:

1 1 1

1 0 1

0 0 1

以相同的方式填充矩阵。

问题是矩阵没有正确填充,它显示494949494949 ... 我期望循环遍历矩阵,它包含与文本文件相同的值。

2 个答案:

答案 0 :(得分:1)

您应首先查看问题Why is “while ( !feof (file) )” always wrong?虽然不会直接导致您的问题,但您会希望避免这种方法从文件中读取文本,因为它会产生陷阱。

接下来,当您从文件中读取数据行时,通常最好一次读取一行。虽然使用面向字符的输入一次读取一个字符没有任何问题,但是由于需要检查每个字符,找到每个数字的开头时,读取数字时的代码会显着更长,暂时缓冲以空字符结尾的字符串中的数字,然后将缓冲的数字转换为数字(即使使用'0'和'1',它们仍然必须从字符转换为数字)

也就是说,面向行的输入的主要工具是fgetsgetline(每个都有优点和缺点)。对于像这样的简单任务,fgets绰绰有余。所以你读了一行,然后是什么?您必须将行分隔为包含每个数字的数字的字符串,然后将字符串转换为数字。 C库具有专门为此任务创建的工具。查看strtol(字符串到长),strtoul(无符号长),strtof(浮点)等。

每个strtoX函数都有一个指向要转换的字符串的指针,以及第二个指针(endptr),它填充字符串中下一个字符的地址它刚刚转换后的数字。 (整数函数也将base作为参数,允许转换为基数10,16等。)

为什么endptr如此重要?它允许您在线上工作,包含未知数量的数字,按顺序转换每个数字,直到达到行尾。 strtoX函数提供了良好的错误检测和报告功能,使您可以从文件中读取读取的行,并在到达结束时停止(以及报告失败的转换)

面向行的输入与fgets一起放在strtol(在您的情况下)将允许您读取文件中的每一行并转换每个数字将文件存入结构中数组中的数字。

我不知道你是否可以添加到你的结构中,但是你会遇到使用结构来保存你的数组的麻烦,同样存储rows和{的数量也是有意义的。 {1}}也从文件中读取。当将结构传递给函数,打印等时,这会使生活变得更加容易。例如:

cols

就是你所需要的一切。

现在让我们将它们放在一个工作示例中。我已将typedef struct { int matrixgrafh[MAX][MAX]; size_t rows; size_t cols; } matrix; 调用放在一个函数中,以防止strtol中的逻辑混乱,并进行错误检查等。我还将现有代码保留在函数中,但已注释,以便您可以看到差异:

LoadMatrix

如果您有任何疑问,请查看并告知我们。使用的输入,编译字符串和您应该期望的输出如下:

<强>输入

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

#define MAX 100
#define MAXLN 256

typedef struct {
    int matrixgrafh[MAX][MAX];
    size_t rows;
    size_t cols;
} matrix;

int LoadMatrix (matrix * m);
long xstrtol (char *p, char **ep, int base);

int main (void)
{
    size_t j, k;
    matrix m;

    if (LoadMatrix (&m) == -1) {
        fprintf (stderr, "error: LoadMatrix failed.\n");
        return 1;
    }

    printf ("\nThe %zux%zu matrix read from file is:\n\n", m.rows, m.cols);    
    for (j = 0; j < m.rows; j++) {
        char *pad = " [ "; \
        for (k = 0; k < m.cols; k++) {
            printf ("%s%2d", pad, m.matrixgrafh[j][k]);
            pad = ", ";
        }
        printf (" ]\n");
    }
    putchar ('\n');

    return 0;
}

int LoadMatrix (matrix *m)
{
    FILE *stuff;
    char line[MAXLN] = {0};     /* line buffer */
    char *p, *ep;     /* pointers for strtol   */
    size_t row = 0;   /* simple row counter    */
    // char c;

    if ((stuff = fopen ("matrix.txt", "r")) == NULL) {
        printf ("File missing..."); /* should be fprintf */
        exit (1);
    }

    while (fgets (line, MAXLN, stuff)) /* read each line in file */
    {
        size_t col = 0;    /* initialize variables for each row */
        p = ep = line;
        errno = 0;

        /* skip to first digit in line */
        while (*p && *p != '-' && (*p < '0' || *p > '9')) p++;

        while (errno == 0)
        {   /* read each number in row */
            m->matrixgrafh[row][col++] = (int)xstrtol (p, &ep, 10);

            if (col == MAX) { /* check col against MAX */
                fprintf (stderr, "LoadMatrix() error: MAX columns reached.\n");
                break;
            }

            /* skip to next number */
            while (*ep && *ep != '-' && (*ep < '0' || *ep > '9')) ep++;
            if (*ep) p = ep;
            else break;
        }

        if (row == 0) m->cols = col;    /* set the number of colums in each row */
        if (col != m->cols) {           /* validate each row against first      */
            fprintf (stderr, "LoadMatrix() error: invalid number of columns, row '%zu'.\n",
                    row);
            fclose (stuff);
            return -1;
        }
        row++;

        if (row == MAX) { /* check col against MAX */
            fprintf (stderr, "LoadMatrix() error: MAX rows reached.\n");
            break;
        }
    }

    fclose (stuff);

    m->rows = row;

    return 0;

    /* see why 'while (!feof (file))' is always wrong */
    // while (!feof (stuff)) {
    //     do {
    //         c = fgetc (stuff);
    //         if (c == '1' || c == '0' && c != '\n' && !feof (stuff))
    //             //corrected c == '1' && c == '0' to c == '1' || c == '0'
    //         {
    //             for (j = 0; j < 20; j++) {
    //                 for (k = 0; k < 20; k++) {
    //                     m->matrixgrafh[j][k] = c;
    //                 }
    //             }
    //         }
    //     } while (!feof (stuff));
    // }
    // return m->matrixgrafh;
}

/** a simple strtol implementation with error checking.
 *  any failed conversion will cause program exit. Adjust
 *  response to failed conversion as required.
 */
long xstrtol (char *p, char **ep, int base)
{
    errno = 0;

    long tmp = strtol (p, ep, base);

    /* Check for various possible errors */
    if ((errno == ERANGE && (tmp == LONG_MIN || tmp == LONG_MAX)) ||
        (errno != 0 && tmp == 0)) {
        perror ("strtol");
        exit (EXIT_FAILURE);
    }

    if (*ep == p) {
        fprintf (stderr, "No digits were found\n");
        exit (EXIT_FAILURE);
    }

    return tmp;
}

<强>编译

$ cat matrix.txt
1 1 1
1 0 1
0 0 1

<强>输出

gcc -Wall -Wextra -o bin/matrix_struct matrix_struct.c

答案 1 :(得分:0)

关键问题是:

  • 每个条目显示为49而不是1,因为49是字符“1”的ASCII值,并且程序未从ASCII值转换为整数。在网上搜索ASCII表以获得更多上下文。
  • 对于从matrix.txt读取的每个字符,您将使用该字符的值填充20x20矩阵。因此,真正重要的唯一价值是从0读取的最终1matrix.txt。 (在这种情况下,每个第一点为149。)