简体   繁体   English

如何从文本文件中读取列并保存到C中的单独数组中?

[英]How to read columns from a text file and save to separate arrays in C?

In a practice exercise to familiarize myself with pointers, I wrote a short program in C, able to read text from a file. 为了使自己熟悉指针,在练习中,我用C语言编写了一个简短程序,能够从文件中读取文本。 I would like to stick to ANSI C. 我想坚持使用ANSIC。

The program does its job perfectly, however I want to proceed to read columns from a text file and save to separate arrays. 该程序可以很好地完成其工作,但是我想继续从文本文件中读取列并将其保存到单独的数组中。 Similar questions have been asked, with replies using strtok , or fgets or sscanf , but when should I use one instead of the other? 有人问过类似的问题,使用strtokfgetssscanf进行答复,但是我什么时候应该使用一个而不是另一个?

Here is my commented code: 这是我的注释代码:

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

char *read_file(char *FILE_INPUT);     /*function to read file*/

int main(int argc, char **argv) {
    char *string; // Pointer to a char 

    string = read_file("file.txt");
    if (string) {
        // Writes the string pointed to by string to the stream pointed to by stdout, and appends a new-line character to the output.
        puts(string);
        // Causes space pointed to by string to be deallocated
        free(string);
    }
    return 0;
}

//Returns a pointer to a char,
char *read_file(char *FILE_INPUT) {
    char *buffer = NULL;
    int string_size, read_size;
    FILE *input_stream = fopen(FILE_INPUT, "r");

    //Check if file exists
    if (input_stream == NULL) {
        perror (FILE_INPUT);
    }
    else if (input_stream) {
        // Seek the last byte of the file. Offset is 0 for a text file.
        fseek(input_stream, 0, SEEK_END);
        // Finds out the position of file pointer in the file with respect to starting of the file
        // We get an idea of string_size since ftell returns the last value of the file pos
        string_size = ftell(input_stream);
        // sets the file position indicator for the stream to the start of the file
        rewind(input_stream);

        // Allocate a string that can hold it all
        // malloc returns a pointer to a char, +1 to hold the NULL character
        // (char*) is the cast return type, this is extra, used for humans
        buffer = (char*)malloc(sizeof(char) * (string_size + 1));

        // Read it all in one operation, returns the number of elements successfully read,
        // Reads into buffer, up to string_size whose size is specified by sizeof(char), from the input_stream !
        read_size = fgets(buffer, sizeof(char), string_size, input_stream);

        // fread doesn't set it so put a \0 in the last position
        // and buffer is now officially a string
        buffer[string_size] = '\0';

        //string_size determined by ftell should be equal to read_size from fread
        if (string_size != read_size) {
            // Something went wrong, throw away the memory and set
            // the buffer to NULL
            free(buffer);
            buffer = NULL;
        }

        // Always remember to close the file.
        fclose(input_stream);
    }

    return buffer;
}

How can I read all columns from a text file of this format, into an array? 如何将这种格式的文本文件中的所有列读入数组? Number of columns is fixed, but number of rows can vary. 列数是固定的,但是行数可以变化。

C 08902019 1020 50 Test1
A 08902666 1040 30 Test2
B 08902768 1060 80 Test3
.
B 08902768 1060 800 Test3000
.
.

On further research, I found that fread is used to allow a program to read and write large blocks of data in a single step, so reading columns separately may not be what fread is intended to do. 在进一步的研究中,我发现fread用于允许程序在单个步骤中读取和写入大数据块,因此单独读取列可能不是fread打算执行的操作。 Thus my program implementation for this kind of job is wrong. 因此,我针对此类工作的程序实现是错误的。

Should I use getc , strtok , sscanf or getline to read such a text file? 我应该使用getcstrtoksscanfgetline读取此类文本文件吗? I am trying to stick to good programming principles and allocate memory dynamically. 我试图遵循良好的编程原则并动态分配内存。


EDIT: 编辑:

By correct I am mean (but not limited to) using good c programming techniques and dynamic memory allocation. 正确地说,我是指(但不限于)使用良好的c编程技术和动态内存分配。

My first thought was to replace fread with fgets . 我首先想到的是,以取代freadfgets Update, I am getting somewhere thanks to your help. 更新,感谢您的帮助,我得到了帮助。

    // Allocate a string that can hold it all
    // malloc returns a pointer to a char, +1 to hold the NULL    character
    // (char*) is the cast return type, this is extra, used for humans
    buffer = (char*)malloc(sizeof(char) * (string_size + 1));

    while (fgets(buffer, sizeof(char) * (string_size + 1), input_stream), input_stream)) {
        printf("%s", buffer);     
    }

for the above text file prints: 对于以上文本文件的打印:

C 08902019 1020 50 Test1

A 08902666 1040 30 Test2

B 08902768 1060 80 Test3

B 08902768 1060 800 Test3000

I also managed to remove the newline character from fgets() input using: 我还设法使用以下命令从fgets()输入中删除了换行符:

strtok(buffer, "\n"); 

Similar examples here , here and here 这里这里这里有类似的例子

How can I proceed to save the columns to separate arrays? 如何继续将列保存到单独的数组?

"Best Practices" is somewhat subjective, but "fully validated, logical and readable" should always be the goal. “最佳做法”在某种程度上是主观的,但是“始终经过充分验证,合乎逻辑且可读性强”才是目标。

For reading a fixed number of fields (in your case choosing cols 1, 2, 5 as string values of unknown length) and cols 3, 4 as simple int values), you can read an unknown number of rows from a file simply by allocating storage for some reasonably anticipated number of rows of data, keeping track of how many rows are filled, and then reallocating storage, as required, when you reach the limit of the storage you have allocated. 要读取固定数量的字段(在您的情况下,将cols 1, 2, 5作为未知长度的字符串值)和cols 3, 4作为简单的int值,只需分配以下内容即可从文件中读取未知数量的行:存储一些合理预期的数据行数,跟踪已填充的行数,然后在达到分配的存储限制时根据需要重新分配存储。

An efficient way of handling the reallocation is to reallocate by some reasonable number of additional blocks of memory when reallocation is required (rather than making calls to realloc for every additional row of data). 的处理重新分配的有效方式是通过额外存储器块的一些合理的数量,需要重新分配时重新分配(而不是使调用realloc用于数据的每个附加的行)。 You can either add a fixed number of new blocks, multiply what you have by 3/2 or 2 or some other sane scheme that meets your needs. 您可以添加固定数量的新块,将现有块数乘以3/22或满足您需要的其他一些理智的方案。 I generally just double the storage each time the allocation limit is reached. 通常,每次达到分配限制时,我只会将存储空间增加一倍。

Since you have a fixed number of fields of unknown size, you can make things easy by simply separating the five-fields with sscanf and validating that 5 conversions took place by checking the sscanf return. 由于您有固定数量的未知大小的字段,因此可以通过简单地用sscanf分隔五个字段并通过检查sscanf返回值来验证是否进行了5次转换来简化操作。 If you were reading an unknown number of fields, then you would just use the same reallocation scheme to handle the column-wise expansion discussed above for reading an unknown number of rows. 如果您正在读取未知数量的字段,则只需使用相同的重新分配方案来处理上面讨论的用于读取未知数量行的按列扩展。

(there is no requirement that any row have the same number of fields in that case, but you can force a check by setting a variable containing the number of fields read with the first row, and then validating that all subsequent rows have that same number...) (在这种情况下,不要求任何行具有相同数量的字段,但是您可以通过设置一个变量来强制检查,该变量包含从第一行读取的字段数量,然后验证所有后续行都具有相同的数量...)

As discussed in the comments, reading a line of data with a line-oriented input function like fgets or POSIX getline and then parsing the data by either tokenizing with strtok , or in this case with a fixed number of fields simply parsing with sscanf is a solid approach. 正如评论中所讨论的那样,使用诸如fgets或POSIX getline的面向行的输入函数读取一行数据,然后通过使用strtok标记化或在这种情况下使用固定数量的字段来简单地使用sscanf解析来解析数据是一种扎实的方法。 It provides the benefit of allowing independent validation of (1) the read of data from the file; 它具有以下优点:允许独立验证(1)从文件中读取数据; and (2) the parse of data into the needed values. (2)将数据解析为所需的值。 (while less flexible, for some data sets, you can do this in a single step with fscanf , but that also injects the scanf problems for user input of what remains unread in the input buffer depending on the conversion-specifiers used...) (虽然灵活性较差,但对于某些数据集,您可以使用fscanf一步完成此操作,但这还会为用户输入注入scanf问题,这取决于所使用的转换说明符 ,从而导致输入缓冲区中尚未读取的内容...)

The easiest way to approach storage of your 5-fields is to declare a simple struct . 存储5字段的最简单方法是声明一个简单的struct Since the number of characters for each of the character fields is unknown, the struct members for each of these fields will be a character pointer, and the remaining fields int , eg 由于每个字符字段的字符数是未知的,因此每个字段的结构成员将是字符指针,其余字段为int ,例如

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

#define ARRSZ   2   /* use 8 or more, set to 2 here to force realloc */
#define MAXC 1024

typedef struct {
    char *col1, *col2, *col5;
    int col3, col4;
} mydata_t;

Now you can start your allocation for handling an unknown number of these by allocating for some reasonably anticipated amount (I would generally use 8 or 16 with a doubling scheme as that will grow reasonably fast), but we have chosen 2 here with #define ARRSZ 2 to make sure we force one reallocation when handling your 3-line data file. 现在,您可以通过分配一些合理预期的数量来开始处理未知数量的分配(我一般会使用816的倍增方案,因为它将很快增长),但是我们在这里选择了2 ,使用#define ARRSZ 2 ,以确保在处理3行数据文件时我们强制一次重新分配。 Note also we are setting a maximum number of characters per-line of #define MAXC 1024 for your data ( don't skimp on buffer size ) 另请注意,我们为您的数据设置了每行 #define MAXC 1024最大字符数不要 #define MAXC 1024 缓冲区大小

To get started, all we need to do is declare a buffer to hold each line, and a few variables to track the currently allocated number of structs, a line counter (to output accurate error messages) and a counter for the number of rows of data we have filled. 首先,我们需要做的是声明一个缓冲区来容纳每一行,并声明一些变量来跟踪当前分配的结构数,一个行计数器(用于输出准确的错误消息)和一个用于存储行数的计数器。我们填写的数据。 Then when (rows_filled == allocated_array_size) you realloc , eg 然后,当(rows_filled == allocated_array_size)realloc ,如

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

    char buf[MAXC];
    size_t arrsz = ARRSZ, line = 0, row = 0;
    mydata_t *data = NULL;
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    /* allocate an 'arrsz' initial number of struct */
    if (!(data = malloc (arrsz * sizeof *data))) {
        perror ("malloc-data");
        return 1;
    }

    while (fgets (buf, MAXC, fp)) {         /* read each line from file */
        char c1[MAXC], c2[MAXC], c5[MAXC];  /* temp strings for c1,2,5 */
        int c3, c4;                         /* temp ints for c3,4 */
        size_t len = strlen (buf);          /* length for validation */

        line++;     /* increment line count */

        /* validate line fit in buffer */
        if (len && buf[len-1] != '\n' && len == MAXC - 1) {
            fprintf (stderr, "error: line %zu exceeds MAXC chars.\n", line);
            return 1;
        }

        if (row == arrsz) { /* check if all pointers used */
            void *tmp = realloc (data, arrsz * 2 * sizeof *data);
            if (!tmp) {     /* validate realloc succeeded */
                perror ("realloc-data");
                break;      /* break, don't exit, data still valid */
            }
            data = tmp;     /* assign realloc'ed block to data */
            arrsz *= 2;     /* update arrsz to reflect new allocation */
        }

( note: when calling realloc , you never realloc the pointer itself , eg data = realloc (data, new_size); If realloc fails (and it does), it returns NULL which would overwrite your original pointer causing a memory leak. Always realloc with a temporary pointer, validate, then assign the new block of memory to your original pointer) 注:当调用realloc ,你永远不realloc的指针本身 ,例如, data = realloc (data, new_size);如果realloc失败(和它),它返回NULL这将覆盖原始的指针导致内存泄漏的始终。 realloc用临时指针,进行验证,然后将新的内存块分配给您的原始指针)

What remains is just splitting the line into our values, handling any errors in line format, adding our field values to our array of struct, increment our row/line counts and repeating until we run out of data to read, eg 剩下的只是将行拆分为我们的值,处理行格式中的任何错误,将字段值添加到结构数组中,增加行/行数,然后重复进行直到我们用完要读取的数据为止,例如

        /* parse buf into fields, handle error on invalid format of line */
        if (sscanf (buf, "%1023s %1023s %d %d %1023s", 
                    c1, c2, &c3, &c4, c5) != 5) {
            fprintf (stderr, "error: invalid format line %zu\n", line);
            continue;   /* get next line */
        }

        /* allocate copy strings, assign allocated blocks to pointers */
        if (!(data[row].col1 = mystrdup (c1))) { /* validate copy of c1 */
            fprintf (stderr, "error: malloc-c1 line %zu\n", line);
            break;      /* same reason to break not exit */
        }
        if (!(data[row].col2 = mystrdup (c2))) { /* validate copy of c2 */
            fprintf (stderr, "error: malloc-c1 line %zu\n", line);
            break;      /* same reason to break not exit */
        }
        data[row].col3 = c3;    /* assign integer values */
        data[row].col4 = c4;
        if (!(data[row].col5 = mystrdup (c5))) { /* validate copy of c5 */
            fprintf (stderr, "error: malloc-c1 line %zu\n", line);
            break;      /* same reason to break not exit */
        }
        row++;      /* increment number of row pointers used */
    }
    if (fp != stdin)    /* close file if not stdin */
        fclose (fp);

    puts ("values stored in struct\n");
    for (size_t i = 0; i < row; i++)
        printf ("%-4s %-10s %4d %4d %s\n", data[i].col1, data[i].col2, 
                data[i].col3, data[i].col4, data[i].col5);

    freemydata (data, row);

    return 0;
}

And we are done (except for the memory use/error check) 至此我们完成了(除了内存使用/错误检查)

Note about there are two helper functions to allocate for each string and copy each string to its allocated block of memory and assigning the starting address for that block to our pointer in our struct. 请注意,有两个帮助器函数可为每个字符串分配并将每个字符串复制到其已分配的内存块,并将该块的起始地址分配给结构中的指针。 mystrdup() You can use strdup() if you have it, I simply included the function to show you how to manually handle the malloc and copy. mystrdup()如果有,可以使用strdup() ,我只是简单地包含了向您展示如何手动处理malloc和复制的malloc Note: how the copy is done with memcpy instead of strcpy -- Why? 注意:如何使用memcpy而非strcpy完成复制-为什么? You already scanned forward in the string to find '\\0' when you found the length with strlen -- no need to have strcpy repeat that process again -- just use memcpy . 当您发现带有strlen的长度时,您已经向前扫描了字符串以查找'\\0' strlen无需strcpy再次重复该过程-只需使用memcpy

/* simple implementation of strdup - in the event you don't have it */
char *mystrdup (const char *s)
{
    if (!s)     /* validate s not NULL */
        return NULL;

    size_t len = strlen (s);            /* get length */
    char *sdup = malloc (len + 1);      /* allocate length + 1 */

    if (!sdup)          /* validate */
        return NULL;

    return memcpy (sdup, s, len + 1);   /* pointer to copied string */ 
}

Last helper function is freemydata() which just calls free() on each allocated block to insure you free all the memory you have allocated. 最后一个辅助函数是freemydata() ,它仅在每个分配的块上调用free() ,以确保释放所有已分配的内存。 It also keeps you code tidy. 它还使您的代码保持整洁。 (you can do the same for the realloc block to move that to it's own function as well) (您也可以对realloc块执行相同的操作,以将其移动到它自己的函数中)

/* simple function to free all data when done */
void freemydata (mydata_t *data, size_t n)
{
    for (size_t i = 0; i < n; i++) {    /* free allocated strings */
        free (data[i].col1);
        free (data[i].col2);
        free (data[i].col5);
    }
    free (data);    /* free structs */
}

Putting all the pieces together would give you: 将所有部分放在一起将为您提供:

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

#define ARRSZ   2   /* use 8 or more, set to 2 here to force realloc */
#define MAXC 1024

typedef struct {
    char *col1, *col2, *col5;
    int col3, col4;
} mydata_t;

/* simple implementation of strdup - in the event you don't have it */
char *mystrdup (const char *s)
{
    if (!s)     /* validate s not NULL */
        return NULL;

    size_t len = strlen (s);            /* get length */
    char *sdup = malloc (len + 1);      /* allocate length + 1 */

    if (!sdup)          /* validate */
        return NULL;

    return memcpy (sdup, s, len + 1);   /* pointer to copied string */ 
}

/* simple function to free all data when done */
void freemydata (mydata_t *data, size_t n)
{
    for (size_t i = 0; i < n; i++) {    /* free allocated strings */
        free (data[i].col1);
        free (data[i].col2);
        free (data[i].col5);
    }
    free (data);    /* free structs */
}

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

    char buf[MAXC];
    size_t arrsz = ARRSZ, line = 0, row = 0;
    mydata_t *data = NULL;
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    /* allocate an 'arrsz' initial number of struct */
    if (!(data = malloc (arrsz * sizeof *data))) {
        perror ("malloc-data");
        return 1;
    }

    while (fgets (buf, MAXC, fp)) {         /* read each line from file */
        char c1[MAXC], c2[MAXC], c5[MAXC];  /* temp strings for c1,2,5 */
        int c3, c4;                         /* temp ints for c3,4 */
        size_t len = strlen (buf);          /* length for validation */

        line++;     /* increment line count */

        /* validate line fit in buffer */
        if (len && buf[len-1] != '\n' && len == MAXC - 1) {
            fprintf (stderr, "error: line %zu exceeds MAXC chars.\n", line);
            return 1;
        }

        if (row == arrsz) { /* check if all pointers used */
            void *tmp = realloc (data, arrsz * 2 * sizeof *data);
            if (!tmp) {     /* validate realloc succeeded */
                perror ("realloc-data");
                break;      /* break, don't exit, data still valid */
            }
            data = tmp;     /* assign realloc'ed block to data */
            arrsz *= 2;     /* update arrsz to reflect new allocation */
        }

        /* parse buf into fields, handle error on invalid format of line */
        if (sscanf (buf, "%1023s %1023s %d %d %1023s", 
                    c1, c2, &c3, &c4, c5) != 5) {
            fprintf (stderr, "error: invalid format line %zu\n", line);
            continue;   /* get next line */
        }

        /* allocate copy strings, assign allocated blocks to pointers */
        if (!(data[row].col1 = mystrdup (c1))) { /* validate copy of c1 */
            fprintf (stderr, "error: malloc-c1 line %zu\n", line);
            break;      /* same reason to break not exit */
        }
        if (!(data[row].col2 = mystrdup (c2))) { /* validate copy of c2 */
            fprintf (stderr, "error: malloc-c1 line %zu\n", line);
            break;      /* same reason to break not exit */
        }
        data[row].col3 = c3;    /* assign integer values */
        data[row].col4 = c4;
        if (!(data[row].col5 = mystrdup (c5))) { /* validate copy of c5 */
            fprintf (stderr, "error: malloc-c1 line %zu\n", line);
            break;      /* same reason to break not exit */
        }
        row++;      /* increment number of row pointers used */
    }
    if (fp != stdin)    /* close file if not stdin */
        fclose (fp);

    puts ("values stored in struct\n");
    for (size_t i = 0; i < row; i++)
        printf ("%-4s %-10s %4d %4d %s\n", data[i].col1, data[i].col2, 
                data[i].col3, data[i].col4, data[i].col5);

    freemydata (data, row);

    return 0;
}

Now test. 现在测试。

Example Input File 输入文件示例

$ cat dat/fivefields.txt
C 08902019 1020 50 Test1
A 08902666 1040 30 Test2
B 08902768 1060 80 Test3

Example Use/Output 使用/输出示例

$ ./bin/fgets_fields <dat/fivefields.txt
values stored in struct

C    08902019   1020   50 Test1
A    08902666   1040   30 Test2
B    08902768   1060   80 Test3

Memory Use/Error Check 内存使用/错误检查

In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. 在您编写的任何可以动态分配内存的代码中,对于任何分配的内存块,您都有2个责任 :(1) 始终保留指向该内存块起始地址的指针,因此,(2)在没有内存块时可以将其释放需要更长的时间。

It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated. 必须使用一个内存错误检查程序来确保您不尝试访问内存或不要在已分配的块的边界之外/之外进行写入,不要尝试以未初始化的值读取或基于条件跳转,最后确定您可以释放已分配的所有内存。

For Linux valgrind is the normal choice. 对于Linux, valgrind是通常的选择。 There are similar memory checkers for every platform. 每个平台都有类似的内存检查器。 They are all simple to use, just run your program through it. 它们都很容易使用,只需通过它运行程序即可。

$ valgrind ./bin/fgets_fields <dat/fivefields.txt
==1721== Memcheck, a memory error detector
==1721== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==1721== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==1721== Command: ./bin/fgets_fields
==1721==
values stored in struct

C    08902019   1020   50 Test1
A    08902666   1040   30 Test2
B    08902768   1060   80 Test3
==1721==
==1721== HEAP SUMMARY:
==1721==     in use at exit: 0 bytes in 0 blocks
==1721==   total heap usage: 11 allocs, 11 frees, 243 bytes allocated
==1721==
==1721== All heap blocks were freed -- no leaks are possible
==1721==
==1721== For counts of detected and suppressed errors, rerun with: -v
==1721== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Always confirm that you have freed all memory you have allocated and that there are no memory errors. 始终确认已释放已分配的所有内存,并且没有内存错误。

Look things over and let me know if you have further questions. 仔细检查一下,如果您还有其他问题,请告诉我。

I want to proceed to read only certain columns of this text file. 我想继续阅读此文本文件的某些列。

You can do this with any input function: getc , fgets , sscanf , getline ... but you must first define exactly what you mean by certain columns . 您可以使用任何输入函数来执行此操作: getcfgetssscanfgetline ...,但是您必须首先准确定义特定列的含义。

  • columns can be defined as separated by a specific character such as , , ; 列可以定义由特定字符作为分隔如,; or TAB, in which case strtok() is definitely not the right choice because it treats all sequences of separating characters as a single separator: hence a,,b would be seen as having only 2 columns. 或TAB,在这种情况下strtok()绝对不是正确的选择,因为它将分隔字符的所有序列都视为一个分隔符:因此, a,,b将被视为只有2列。
  • if they are instead separated by whitespace, any sequence of spaces or tabs, strtok , strpbrk or strspn / strcspn might come in handy. 如果用空格将它们分隔开,则任何空格或制表符序列, strtokstrpbrkstrspn / strcspn可以派上用场。

In any case, you can read the file line by line with fgets but you might have a problem with very long lines. 在任何情况下,您都可以使用fgets逐行读取文件,但是很长的行可能会出现问题。 getline is a solution, but it might not be available on all systems. getline是一种解决方案,但可能并非在所有系统上都可用。

If you know what is column separator and how many columns you have you use getline with column separator and then with line separator. 如果您知道什么是列分隔符以及有多少列,则可以将getline与列分隔符一起使用,然后与行分隔符一起使用。

Here is getline : 这是getline

http://man7.org/linux/man-pages/man3/getline.3.html http://man7.org/linux/man-pages/man3/getline.3.html

It is very good because it allocates space for you, no need to know how many bytes is your column or line. 很好,因为它为您分配了空间,无需知道您的列或行有多少字节。

Or you just use getline as in code example in link to read whole line then you "parse" and extract columns as you wish.... 或者,您仅使用getline作为链接中的代码示例,以读取整行,然后根据需要“解析”并提取列。

If you paste exactly how you want to run program with input you show I can try write fast C program for good answer. 如果您确切地粘贴要如何使用输入来运行程序,那么您将显示出我可以尝试编写快速的C程序以获得良好的答案。 Now it is just comment-style answer with too many words for comment :-( 现在,它只是评论样式的答案,带有太多要评论的词:-(

Or is it somehow you cannot use library? 还是无法使用图书馆?

Although while waiting for better question I will note that you can use awk to read columns from text file but probably this is not what you want? 尽管在等待更好的问题时,我会注意到您可以使用awk从文本文件中读取列,但这可能不是您想要的吗? Because what are you trying to do really? 因为您实际上想做什么?

根据数据和胆量,您可以使用scanf或使用yacc / lex创建的解析器。

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

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