简体   繁体   English

从C中的文件读取2D数组

[英]Reading a 2D array from a file in C

I'm attempting to create a program to read a 2D array from a file and then print it out. 我正在尝试创建一个程序来从文件中读取2D数组,然后将其打印出来。

The file is set out so that the first line has the number of rows and then the number of columns. 设置文件的位置,使第一行具有行数,然后具有列数。 After that the array is plotted. 之后,绘制阵列。 An example is as follows: 示例如下:

3 5
10.4 15.1 18.5 13.3 20.8
76.5 55.3 94.0 48.5 60.3
2.4 4.6 3.5 4.6 8.9

My problem is that i only know how to read the first element of each line using fgets and sscanf so the following numbers are ignored. 我的问题是我只知道如何使用fgets和sscanf读取每一行的第一个元素,因此以下数字将被忽略。

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[]){

FILE* f = fopen("plottestdata", "r");
char size[20];
int height, width,ii=0,cc,jj,kk;
float array[100][100];
char horiz[500];

if(fgets(size, 20, f)!= NULL){

    sscanf(size,"%d %d", &height, &width);
    printf("%d %d\n",height, width);
}
while(fgets(horiz, 500, f)!=NULL)
{

    if(ii<height)
    {
        for(cc=0;cc<width;cc++)
        {
        sscanf(horiz, "%f", &array[ii][cc]);
        }
    ii++;
    }
}
for(jj=0;jj<width;jj++)
    {
        for(kk=0;kk<height;kk++)
        {
        printf("%f ", array[jj][kk]);
        }
    }
fclose(f);
return 0;
}

This gives me an output of the first element of each line repeated multiple times and I understand why but am unsure how to fix it. 这给了我每行第一元素重复多次的输出,我理解为什么但不确定如何解决它。 The file it is reading from is actually a 20x20 array although set out in the same format as the example. 尽管读取的文件格式与示例相同,但实际上是20x20的数组。

Also, i have left out my error checking for the sake of trying to shortening a long question. 另外,为了简化简短的问题,我省略了错误检查。

I could not resist tweaking and simplifying your code, it was so close, to avoid the use of fgets and use fscanf to read the values directly. 为了避免使用fgets并使用fscanf直接读取值,我是如此抗拒调整和简化您的代码,它是如此接近。 Plus basic error checking. 加上基本的错误检查。

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

#define MWIDTH  100
#define MHEIGHT 100

int main(void){

    FILE* f;
    int height, width, ii, jj;
    float array[MHEIGHT][MWIDTH];

    if((f = fopen("plottestdata.txt", "r")) == NULL)
        exit(1);

    if(fscanf(f, "%d%d", &height, &width) != 2)
        exit(1);
    if (height < 1 || height > MHEIGHT || width < 1 || width > MWIDTH)
        exit(1);

    for(jj=0; jj<height; jj++)
        for(ii=0; ii<width; ii++)
            if(fscanf(f, "%f", &array[jj][ii]) != 1)
                exit(1);
    fclose(f);

    for(jj=0; jj<height; jj++){
        for(ii=0; ii<width; ii++)
            printf ("%10.1f", array[jj][ii]);
        printf("\n");
    }
    return 0;
}

Program output: 程序输出:

  10.4      15.1      18.5      13.3      20.8
  76.5      55.3      94.0      48.5      60.3
   2.4       4.6       3.5       4.6       8.9
#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[]){
    FILE* f = fopen("plottestdata", "r");
    char size[20];
    int height, width,ii=0,cc,jj,kk;
    char horiz[500];

    if(fgets(size, 500, f)!= NULL){

    sscanf(size,"%d %d", &height, &width);
    printf("%d %d\n",height, width);
    }
    float array[height][width];
    while(fgets(horiz, 500, f)!=NULL)
    {

    if(ii<height)
    {
         sscanf(horiz, "%f %f %f %f %f", &array[ii][0],&array[ii][1],
                    &array[ii][2],
                    &array[ii][3],
                    &array[ii][4]);       
              ii++;
        }
    }
    for(ii=0;ii<height;ii++)
    {
        for(kk=0;kk<width;kk++)
        {
            printf("%.2f ", array[ii][kk]);
        }
        printf("\n");
    }
    fclose(f);
    return 0;
}

Instead of reading from a file with a hardcoded file name, why not read from stdin ? 为什么不从stdin中读取,而不是从具有硬编码文件名的文件中读取? You can use fgets(size, sizeof size, stdin) to read the first line with the dimensions. 您可以使用fgets(size, sizeof size, stdin)读取具有尺寸的第一行。

Then use scanf(" %f", &array[ii][cc) to read in values one by one. 然后使用scanf(" %f", &array[ii][cc)逐一读取值。

Be sure to test whether scanf returns 1 and add some error handling if not. 确保测试scanf是否返回1,如果没有,则添加一些错误处理。

As you have already found out, you need to scan the next value where you left off after scanning the previous one. 如您所知,您需要在扫描上一个值后扫描下一个中断的值。 Unfortunately, sscanf does not have the properties of a stream; 不幸的是, sscanf不具有流的属性。 it doesn't memorise its last position and always starts afresh if you pass the same string. 它不记住它的最后位置,并且如果您传递相同的字符串,则总是重新开始。

Fortunalely, there are many other ways to achieve sequential scanning. 幸运的是,还有许多其他方法可以实现顺序扫描。

Tokenisation You could tokenise your line forst and then parse each token as floating-point number. 标记化您可以将forst标记化,然后将每个标记解析为浮点数。 strtok from string.h> and strtod from <stdlib.h> will do that job for you. 来自string.h> strtok和来自<stdlib.h> strtod将为您完成这项工作。

        char *token = strtok(horiz, " \t\n");

        for (cc = 0; cc < width; cc++) {
            if (token) {                
                array[ii][cc] = strtod(token, NULL);
                token = strtok(NULL, " \t\n");
            } else {
                array[ii][cc] = 0.0;
            }
        }

Keep track of the tail I strtod has one other characteristic: It tells you exactly where parsing stopped when you supply a pointer to a char pointer. 跟踪I strtod 的尾部还有另一个特征:当您提供一个指向char指针的指针时,它可以准确告诉您解析在哪里停止。 strtod also skips leading white space. strtod也跳过领先的空格。 You can use these two facts to parse floats separated by white space. 您可以使用这两个事实来解析由空格分隔的浮点数。

        char *p = horiz;

        for (cc = 0; cc < width; cc++) {
            char *tail;

            array[ii][cc] = strtod(p, &tail);
            p = tail;
        }

Keep track of the tail II sscanf has a special format that tells you how many characters have been parsed at a certain point in an integer. 跟踪尾部II sscanf具有一种特殊的格式,该格式可以告诉您在某个整数点已解析了多少个字符。 The above could be written with sscanf : 上面可以用sscanf编写:

       char *p = horiz;

        for (cc = 0; cc < width; cc++) {
            int len;

            sscanf(p, "%f%n", &array[ii][cc], &len);
            p += len;
        }

All these work for your example, but none of them does proper error checking. 所有这些都适用于您的示例,但是没有一个可以进行正确的错误检查。 The first example at least makes a half-hearted attempt to catch the case where a line has fewer tokens than the matrix has columns. 第一个示例至少做出了三心二意的尝试,以抓住一行令牌少于矩阵包含列的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM