C:读取文件并将其存储到数据结构中

时间:2015-04-06 02:34:14

标签: c

所以我有一个带有以下信息的.txt文档(它可以是多行,但在这种情况下它是3行)

Jane Smith    123 lala land    123-222-1231
Bob Fall    123 blue jay st    812-923-1111
Sally White    1 rose ave.    +1-231-2318

我想创建一个'阅读'读取文件的功能,然后写入'将其写入数据结构的函数。

到目前为止,我有这个:

void read()
{
    FILE *file;
    file = fopen("fileName", "r");
    write(file);
}

void write(FILE *file)
 {

 }

我想知道如何将每一行存储到数据结构中,因为C不支持向量。我希望能够创建一个可以打印的打印功能:

  1 //line #1 info here
  2 //etc
  3 //etc

3 个答案:

答案 0 :(得分:2)

首先使用openfopen功能打开文档文件。

例如:fp=fopen (filename,"r");

然后使用fgets逐行阅读。

例如:while(fgets(array,BUFSIZ,fp) != NULL)

读取每一行后,使用sscanf函数存储结构中的数据。

例如:sscanf(array," %d %s“,& var [i] .id,var [i] .name);`

文件中的数据将加载到结构中。

答案 1 :(得分:0)

#include<stdio.h>
#include<string.h>
#define MAXLENGTH 200 
typedef struct node{
    char query[MAXLENGTH];
}DATA;

typedef struct stack{
    DATA data[MAXLENGTH];
    int top;
}Stack;

void write(FILE *file,Stack* st)
{   
    while(!feof(file)){  //Check EOF
        st->top++; 
        fgets(st->data[st->top].query,MAXLENGTH,file); //Scan data line by line and put into data structure
        //printf("%s",st->data[st->top].query); 
    }
}

void read(Stack* st)
{
    FILE *file;
    file = fopen("h.txt", "r");
    write(file,st);
}

int main(){
    int i;
    Stack st;
    st.top = -1;

    read(&st);

    for(i = 0; i<= st.top; i++){  //DISPLAY DATA
        printf("%s\n",st.data[i].query); 
    } 
    fflush(stdin);getchar();
    return 0;
}

答案 2 :(得分:0)

由于您正在尝试解析包含空格的字符串,而空格又与其他字段隔开更多空格(例如nameaddress),您无法读取该行然后用sscanf解析该字符串。这根本不可能。对于scanf/sscanf,字符串的匹配在第一个whitespace上终止(除非给出width说明符),使得它无法解析包含空格的不同长度的字符串。 E.g:

Jane Smith    123 lala land    123-222-1231

尝试解析%s只读Jane而不是更多。除非保证有固定宽度的列,否则sscanf在这种情况下不起作用。

使问题复杂化,不仅字符串包含空格,而且分隔符由多个空格组成。所以不幸的是,这种情况下你必须使用指针来解析字符串。怎么样?从已知信息开始。

唯一可以实现这一点的是推测电话号码不包含空白。因此,使用strrchr(或在字符串末尾设置指针并备份),您只需在电话号码开头之前找到空格即可。在此空格之前设置end pointer (ep),将原始指针前移1并将电话号码复制到结构中。

ep开始,向后工作,直到找到第一个非空格字符(地址字段的结尾)并在那里设置null-terminating字符。

下一个已知点是字符串的开头。从那里开始,找到第一个double-space。 (假设名称,地址和电话字段都被分隔至少2个空格)。你知道双空格的第一个是名字字段的结尾,在那里设置了一个null-terminating字符。 (您可以通过简单地读取字符串的开头来读取/复制名称到结构)

最后,继续前进,直到找到下一个非空格字符。这是地址的开头。将地址复制到结构中,您就完成了。 (每行的重复过程)。

有时你没有明智的分隔符,你必须退回到简单地用指针踩过字符串并逐步处理它。这是其中一个案例。如果您有任何疑问,请查看以下内容并告知我们:

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

#define EMAX 128

typedef struct entry {
    char name[32];
    char address[32];
    char phone[16];
} entry;

size_t readtxtfile (char *fn, entry *array);
void prn_entries (entry *array);

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

    /* validate number of arguments */
    if (argc < 2 ) {
        fprintf (stderr, "error: insufficient input, usage: %s <filename1>\n", argv[0]);
        return 1;
    }

    /* initialize all variables */
    size_t index = 0;
    entry contacts[EMAX] = {{{0}, {0}, {0}}};

    /* read file into an array of entries,
    number of entries, returned to index */
    index = readtxtfile (argv[1], contacts);

    /* simple print function */
    if (index > 0)
    {
        printf ("\nNumber of entries in contacts : %zu\n\n", index);
        prn_entries (contacts);
    }
    else
        fprintf (stderr, "error: no entries read from file '%s'\n.", argv[1]);

    return 0;
}

size_t readtxtfile (char *fn, entry *array)
{
    if (!fn) return 0;              /* validate filename provided       */

    char *ln = NULL;                /* NULL forces getline to allocate  */
    size_t n = 0;                   /* max chars to read (0 - no limit) */
    ssize_t nchr = 0;               /* number of chars actually read    */
    size_t idx = 0;                 /* couner for number of entries     */
    FILE *fp = NULL;                /* file pointer to open file fn     */

    /* open / validate file */
    if (!(fp = fopen (fn, "r"))) {
        fprintf (stderr, "%s() error: file open failed '%s'.", __func__, fn);
        return 0;
    }

    /* read each line from file */
    while ((nchr = getline (&ln, &n, fp)) != -1)
    {
        /* strip newline or carriage rtn    */
        while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r'))
            ln[--nchr] = 0;

        /* create a copy of ln to preserve start address */
        char *lcpy = strdup (ln);
        if (!lcpy) {
            fprintf (stderr, "%s() error: memory allocation failed.\n", __func__);
            continue;
        }

        char *p = strrchr (lcpy, ' ');                  /* find last space in line      */
        char *ep = p - 1;                               /* set end pointer 1 before     */

        p++;                                            /* advance to next char         */
        strncpy (array[idx].phone, p, strlen (p));      /* copy p to phone              */

        while (ep > lcpy && *ep == ' ') ep--;           /* find first space after addr  */
        *(++ep) = 0;                                    /* null-terminat at that space  */

        p = lcpy;           /* start at beginning of string and find first double-space */
        while (*(p + 1) && !(*(p + 1) == ' ' && *p == ' ')) p++;

        *p = 0;                     /* null-terminate at first space    */

        while (*(++p) == ' ');      /* find first char in addr          */

        strncpy (array[idx].address, p, strlen (p));    /* copy p to address            */
        strncpy (array[idx].name, lcpy, strlen (lcpy)); /* copy lcpy to name            */

        free (lcpy);                /* free memory allocated by strdup  */
        lcpy = NULL;                /* reset pointer NULL               */

        idx++;                      /* increment entry index            */
        if (idx == EMAX)            /* check if EMAX reached & return   */
        {
            fprintf (stderr, "%s() warning: maximun number of entries read\n", __func__);
            break;
        }
    }

    if (ln) free (ln);              /* free memory allocated by getline */
    if (fp) fclose (fp);            /* close open file descriptor       */

    return idx;
}

/* print an array of character pointers. */
void prn_entries (entry *array)
{
    register size_t n = 0;
    while (strlen (array[n].name) > 0)
    {
        printf (" (%2zu.)  %-32s %-32s %s\n", n, array[n].name, array[n].address, array[n].phone);
        n++;
    }
}

<强>输出

$ ./bin/read_entries dat/nmaddph.txt

Number of entries in contacts : 3

 ( 0.)  Jane Smith                       123 lala land                    123-222-1231
 ( 1.)  Bob Fall                         123 blue jay st                  812-923-1111
 ( 2.)  Sally White                      1 rose ave.                      +1-231-2318

注意:使用getline或者在动态为字符串分配空间的任何时候,您需要在使用不保留原始字符的函数更改该内存块之前进行复制字符串的开头(如strtok或者您使用字符串变量手动迭代字符串)。 getline为您分配ln的内存(如果最初设置为NULL),因此getline负责释放它。如果更改字符串的起始地址,或者使部分字符串无法访问,则当getline尝试reallocfree该内存块时,将发生内存错误。制作副本将为您节省很多麻烦。

在上面的示例中,制作了由ln分配的getline的副本。根据需要分配字符指针以保留lcpy的起始地址。如果您将迭代字符串前进lcpy(例如lcpy++;),而不是使用第二个指针,则原始起始地址将丢失。当您(或退出程序)尝试释放lcpy时,可能会发生一系列错误(或分段错误)。