将文件读入struct

时间:2015-12-05 21:29:51

标签: c arrays file struct

我试图编写一个代码来读取文本文件并将其存储到结构中,这样我就可以将该结构用于该程序。

struct Synonym{
    char Ausdruck[100];
    char Anmerkung[60];
};
typedef struct Synonym Synonym;

这是我的结构,我试图安装一个看起来像这样的文件

# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
Kernfission;Fission;Kernspaltung;Atomspaltung;
Wiederaufnahme;Fortfuehrung;
wegfahren;wegfliegen;abfliegen;aufbrechen;abfahren;abduesen (ugs.);davonfahren;fortfahren;abreisen;
Training;Kurs;Workshop;Weiterbildung;Seminar;Kursus;Bildungsmassnahme;Lehrgang;
Zerlegung;Demontage;Entlassung;Abbau;

应删除#之后的行。 Ausdruck中的每个单词以及()之后的单词都应保存在Anmerkung中。 问题是我需要像每一行一样也是结构原因之后在整个程序中我需要能够从中为刽子手游戏选择一行和两个单词。

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

struct Eintrag{
    char Ausdruck[100][20];
    char Anmerkung[100][20];
};
typedef struct Eintrag Eintrag;

int zeilencount(){
    int count_lines = 0;
    char chr;
    FILE *datei = fopen("wort.txt","r");

    if (datei == NULL) {
        printf( "Fehlgeschlagen\n");
    }
    chr = getc(datei);
    while (chr != EOF)
    {

       //Count whenever new line is encountered
        if (chr == '\n')
        {
           count_lines = count_lines + 1;
        }
         if (chr == '#'){
            count_lines = count_lines - 1;
        }


        //take next character from file.
        chr = getc(datei);
    }
    fclose(datei);

    count_lines ++;

    return count_lines;

}

int main(){
    int i,w,z,k;// loopindex
    //fopen
    int anzahlzeile = zeilencount();
    Eintrag eintrag[anzahlzeile];
    FILE *datei = fopen("wort.txt","r");

    if (datei == NULL) {
        printf( "Fehlgeschlagen\n");
    }
    for(i=0; i<anzahlzeile; i++){
        for(w=0; w<10; w++){
            for(z=0; z<20;z++){
                fscanf(datei,"%c", &eintrag[i].Ausdruck[w][z]);
                if(eintrag[i].Ausdruck[w][z]=='#'){
                fscanf(datei, "%*[^\n]");
                i=0;
                break;
                }
                if(eintrag[i].Ausdruck[w][z]==';')
                break;

                if(eintrag[i].Ausdruck[w][z]== '('){
                    for(k=0;k<20;k++) {
                        fscanf(datei,"%c", &eintrag[i].Anmerkung[w][k]);
                        if (eintrag[i].Anmerkung[w][k] == ')') {
                            break;
                        }
                        }

                if (eintrag[i].Ausdruck[w][z] == '\n')break;


                }

            }
        }
    }   
    for(i=0; i<anzahlzeile; i++){
        printf("zeile %i", i+1);
        for(w=0; w<10; w++){

    printf("ausdruck = %c\n",eintrag[i].Ausdruck[w]);
    printf("anmerkung = %c\n",eintrag[i].Anmerkung[w]);

        }
    }
    //fclose
    fclose(datei);
}

这是我到目前为止写的。我不知道它是否正确。

1 个答案:

答案 0 :(得分:1)

要确切地告诉您要尝试做什么有点困难,但如果我理解正确,您想要阅读已发布的数据文件,请忽略以'#'开头的行,将剩余的行读入{ {1}},如果该行包含synonym[X].ausdruck,请将(stuff)读入'stuff'。如果这不是您的尝试,请澄清,我很乐意进一步提供帮助。 (注意:在C中,变量传统上是小写的,我在下面使用小写)

要实现上述内容,您只需要一个结构数组。除了声明15 synonym[X].anmerkung之外,您Zeile似乎没有任何其他目的(如果不是这样,请进一步解释)。要读取和解析每一行,synonym的每个成员只需要2个大小足够的字符数组。下面,我们创建了一个大小为synonym {256}的synonym的静态数组。 (你可以根据需要动态分配和MAXS来处理未知数量的行,但是出于示例目的,我们将使用一个简单的静态声明)

realloc用于读取每一行。一个简单的辅助函数fgets从每个字符串读取的末尾修剪str_rmcrlf并返回其长度。不以newline开头的每一行都会复制到'#'synonym[idx].ausdruck用于检查strchr的每一行。如果找到,'('的内容将被解析为(...)。如果转化成功,则会将sbuf复制到sbuf

尝试一下,如果您的要求与描述的不同,请告诉我。

synonym[idx].anmerkung

<强>输出

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

#define MAXS 256
#define MAXC 128
#define MAXW 64

typedef struct {
    char ausdruck[MAXC];
    char anmerkung[MAXW];
} synonym;

ssize_t str_rmcrlf (char *str);

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

    char buf[MAXC] = {0};
    synonym synonym[MAXS] = {{{0},{0}}};
    size_t i, idx = 0;
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    /* read each line in file until MAXS synonym elements filled */
    while (idx < MAXS && fgets (buf, MAXC, fp))
    {
        if (*buf == '#') continue;          /* skip beginning with '#'  */

        char sbuf[MAXW] = {0};
        char *p = NULL;
        ssize_t len = 0;

        if ((len = str_rmcrlf (buf)) == -1) /* strip crlf, get length   */
            continue;                       /* continue on error        */

        /* (you should check for short-read here) */

        strcpy (synonym[idx].ausdruck, buf);    /* copy buf to ausdruck */

        /* parse buf in anmerkung */
        if ((p = strchr (buf, '('))) {          /* check buf for '('    */
            if (sscanf (p, "(%[^)\n]", sbuf))           /* read "(...)" */
                strcpy (synonym[idx].anmerkung, sbuf);  /* copy "..."   */
        }

        idx++;
    }

    for (i = 0; i < idx; i++) {
        printf ("\n  synonym[%3zu].ausdruck  : %s\n", i, synonym[i].ausdruck);
        if (*(synonym[i].anmerkung))
            printf ("  synonym[%3zu].anmerkung : (%s)\n", i, 
                    synonym[i].anmerkung);
        else
            printf ("  synonym[%3zu].anmerkung :\n", i);
    }

    return 0;
}

/** stip trailing newlines and carraige returns by overwriting with
 *  null-terminating char. str is modified in place. The new length
 *  is retured on success, -1 otherwise.
 */
ssize_t str_rmcrlf (char *str)
{
    if (!str) return -1;
    if (!*str) return 0;

    char *p = str;
    for (; *p; p++) {}
    p--;

    for (; p >= str && (*p == '\n' || *p == '\r'); p--) *p = 0;

    p++;

    return (ssize_t)(p - str);
}

注意:您必须提供足够的空间来容纳整条线。您上面的数据将超过允许的$ ./bin/fgets_struct dat/synonym.txt $ ./bin/fgets_struct dat/synonym.txt synonym[ 0].ausdruck : Kernfission;Fission;Kernspaltung;Atomspaltung; synonym[ 0].anmerkung : synonym[ 1].ausdruck : Wiederaufnahme;Fortfuehrung; synonym[ 1].anmerkung : synonym[ 2].ausdruck : wegfahren;wegfliegen;abfliegen;aufbrechen;abfahren;abduesen (ugs.);davonfahren;fortfahren;abreisen; synonym[ 2].anmerkung : (ugs.) synonym[ 3].ausdruck : Training;Kurs;Workshop;Weiterbildung;Seminar;Kursus;Bildungsmassnahme;Lehrgang; synonym[ 3].anmerkung : synonym[ 4].ausdruck : Zerlegung;Demontage;Entlassung;Abbau; synonym[ 4].anmerkung : 个字符,从而导致部分或短读。您可以检查并处理指示的位置(或者只是通过将长度增加到100来为每条线提供足够的存储空间。)

将每行拆分为单词

好的,评论现在有助于阐明你想要完成的事情。在我们看一下实现之前,让我们先看看C。 C,比任何其他语言(汇编除外)更多的是精确语言。 C中没有足够接近的语法。

虽然可能有很多方法可以达到解决方案,但就每行代码而言,每行中的每个字符都是 - 它是正确的 - 或者它是。你必须理解为什么每个角色都需要它以及它的作用。对于每个函数,无论是标准库中的函数还是您编写的函数,您都必须知道函数采用的参数,函数对每个参数的作用以及每个函数返回的内容。

C为您提供组成程序的内存的逐个地址访问权限,您可以根据需要使用和管理该内存。没有足够的接近或它与C的联系。这就是它的力量和学习曲线的来源。您必须以这种详细程度和准确性来学习C语言。它需要工作,就像学习任何新语言一样,但是一旦你掌握了基础知识,天空就是极限。

在学习C时,当你遇到一些你不理解的东西时 - 查一查。使用您正在使用的标准库的手册页的主要权限。使用信誉良好的教程。在这里提问。但要小心,在所谓的编程网站上发布的代码很多都是错误的。

所有编译器都为您提供了帮助您正确完成工作的工具。绝对最基本也是最重要的是编译代码时编译器发出的警告。利用这一点。始终,始终使用警告启用进行编译(例如128)并且在没有警告的情况下编译之前不接受您的代码(有一些例外,但它们非常非常罕见,而不是你将在不久的将来随时遇到的事情)

话虽这么说,这段代码的正确编译字符串看起来像是:

-Wall -Wextra

(用gcc上的gcc -Wall -Wextra -O3 -o bin/fgets_struct_words fgets_struct_words.c 替换优化-O3以启用调试符号)

下面的代码使用相同的结构数组,但在每个结构中都有一个字符的2D数组,用作字符串数组。非常重要的是,struct数组和每个成员都初始化为-g。这可以确保所有字符串都是 nul-terminated 。每个结构中的字符串数已添加为zero/nul。这为您提供了一个方便的,每个结构,每行的单词数。 synonym[X].n用于将每一行划分为每个strtok;的标记(字词)。

代码只是读取每一行,跳过以(开头的行,对行进行标记,然后将每个单词存储在'#'中。如果单词以synonym[X].ausdruck[n]开头,则会将其放在'('中。通过两个示例解释详细程度,如果您有疑问,请告诉我们:

synonym[X].anmerkung[n]

<强>输出

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

#define MAXS 256
#define MAXC 128
#define MAXW 64
#define MAXL 32

typedef struct {
    char ausdruck[MAXW][MAXL];
    char anmerkung[MAXW];
    size_t n;
} synonym;

ssize_t str_rmcrlf (char *str);

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

    char buf[MAXC] = {0};
    synonym synonym[MAXS] = {{{{0}},{0},0}};
    size_t i, j, idx = 0;
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    /* read each line in file until MAXS synonym elements filled */
    while (idx < MAXS && fgets (buf, MAXC, fp))
    {
        if (*buf == '#') continue;          /* skip beginning with '#'  */

        char sbuf[MAXW] = {0};
        char *p = NULL;
        ssize_t n = 0, len = 0;

        if ((len = str_rmcrlf (buf)) == -1) /* strip crlf, get length   */
            continue;                       /* continue on error        */

        /* copy each word in buf to ausdruck[n] or anmerkung[n] */
        for (p = strtok (buf, " ;"); p; p = strtok (NULL, " ;\n")) {
            if (*p == '(') {    /* copy word in () to anmerkung */
                if (sscanf (p, "(%[^)\n]", sbuf))           /* read "(...)" */
                    strcpy (synonym[idx].anmerkung, sbuf);  /* copy "..."   */
            }
            else /* copy word to array */
                strcpy (synonym[idx].ausdruck[n++], p);

        }
        synonym[idx++].n = n; /* set n, increment idx */
    }

    for (i = 0; i < idx; i++) 
    {
        putchar ('\n');

        for (j = 0; j < synonym[i].n; j++)
            printf ("  synonym[%3zu].ausdruck[%2zu]  : %s\n",
                    i, j, synonym[i].ausdruck[j]);

        if (*(synonym[i].anmerkung))
            printf ("\n  synonym[%3zu].anmerkung : (%s)\n", i, 
                    synonym[i].anmerkung);
        else
            printf ("\n  synonym[%3zu].anmerkung :\n", i);
    }

    return 0;
}

/** stip trailing newlines and carraige returns by overwriting with
 *  null-terminating char. str is modified in place. The new length
 *  is retured on success, -1 otherwise.
 */
ssize_t str_rmcrlf (char *str)
{
    if (!str) return -1;
    if (!*str) return 0;

    char *p = str;
    for (; *p; p++) {}
    p--;

    for (; p >= str && (*p == '\n' || *p == '\r'); p--) *p = 0;

    p++;

    return (ssize_t)(p - str);
}

捕获anmerkung的索引

为了捕获附加$ ./bin/fgets_struct_words dat/synonym.txt synonym[ 0].ausdruck[ 0] : Kernfission synonym[ 0].ausdruck[ 1] : Fission synonym[ 0].ausdruck[ 2] : Kernspaltung synonym[ 0].ausdruck[ 3] : Atomspaltung synonym[ 0].anmerkung : synonym[ 1].ausdruck[ 0] : Wiederaufnahme synonym[ 1].ausdruck[ 1] : Fortfuehrung synonym[ 1].anmerkung : synonym[ 2].ausdruck[ 0] : wegfahren synonym[ 2].ausdruck[ 1] : wegfliegen synonym[ 2].ausdruck[ 2] : abfliegen synonym[ 2].ausdruck[ 3] : aufbrechen synonym[ 2].ausdruck[ 4] : abfahren synonym[ 2].ausdruck[ 5] : abduesen synonym[ 2].ausdruck[ 6] : davonfahren synonym[ 2].ausdruck[ 7] : fortfahren synonym[ 2].ausdruck[ 8] : abreisen synonym[ 2].anmerkung : (ugs.) synonym[ 3].ausdruck[ 0] : Training synonym[ 3].ausdruck[ 1] : Kurs synonym[ 3].ausdruck[ 2] : Workshop synonym[ 3].ausdruck[ 3] : Weiterbildung synonym[ 3].ausdruck[ 4] : Seminar synonym[ 3].ausdruck[ 5] : Kursus synonym[ 3].ausdruck[ 6] : Bildungsmassnahme synonym[ 3].ausdruck[ 7] : Lehrgang synonym[ 3].anmerkung : synonym[ 4].ausdruck[ 0] : Zerlegung synonym[ 4].ausdruck[ 1] : Demontage synonym[ 4].ausdruck[ 2] : Entlassung synonym[ 4].ausdruck[ 3] : Abbau synonym[ 4].anmerkung : 的单词,您只需要知道它所属的anmerkung中的哪个索引。不需要整个单独的2D阵列。例如,您可以通过将ausdruck添加到aindex结构来捕获索引:

synonym

然后,捕获它所需的代码的唯一更改是一个新行(并将typedef struct { char ausdruck[MAXW][MAXL]; char anmerkung[MAXW]; size_t aindex; size_t n; } synonym; 包裹在if中:

{}
上下文中显示的

适合:

                synonym[idx].aindex = n > 0 ? n - 1 : n;/* set aindex   */

现在每当你填充 if (*p == '(') { /* copy word in () to anmerkung */ if (sscanf (p, "(%[^)\n]", sbuf)) { /* read "(...)" */ strcpy (synonym[idx].anmerkung, sbuf); /* copy "..." */ synonym[idx].aindex = n > 0 ? n - 1 : n;/* set aindex */ } } 时,你也会保存前面单词的索引。您可以使用以下命令更改输出以验证索引:

anmerkung

<强>输出

    if (*(synonym[i].anmerkung))
        printf ("\n  synonym[%3zu].anmerkung : (%s) index: %zu\n", i, 
                synonym[i].anmerkung, synonym[i].aindex);

另一个注意事项。你看到代码:

<snip>
  synonym[  2].ausdruck[ 0]  : wegfahren
  synonym[  2].ausdruck[ 1]  : wegfliegen
  synonym[  2].ausdruck[ 2]  : abfliegen
  synonym[  2].ausdruck[ 3]  : aufbrechen
  synonym[  2].ausdruck[ 4]  : abfahren
  synonym[  2].ausdruck[ 5]  : abduesen
  synonym[  2].ausdruck[ 6]  : davonfahren
  synonym[  2].ausdruck[ 7]  : fortfahren
  synonym[  2].ausdruck[ 8]  : abreisen

  synonym[  2].anmerkung : (ugs.) index: 5
<snip>

它使用synonym[idx].aindex = n > 0 ? n - 1 : n; 运算符设置ternary的值,而不是盲目地将值设置为synonym[idx].aindex。 (就像我们用它来打开命令行上给出的文件或默认情况下n - 1一样)

什么是stdin运营商?它基本上是一个内联使用的简写ternary。它显示为:if,then,else(但没有(test) ? (if true code) : (if false code))。所以再看一下这条线。您会看到()是否将值设置为n > 0,否则设置为n - 1n)。如果行以0开头(这将代表无效的数组索引),则重点是防止设置aindex否定。