我正在尝试编写将读取文本文件并将其存储到结构中的代码,以便可以将该结构用于程序。

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);
}


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

最佳答案

确切地说出您要执行的操作有点困难,但是如果我理解正确,则希望读取已发布的数据文件,忽略以'#'开头的行,将其余的行读取为synonym[X].ausdruck,如果该行包含(stuff),将'stuff'读入synonym[X].anmerkung。如果这不是您要尝试的操作,请澄清一下,我们很乐意为您提供进一步的帮助。 (注意:在C中,变量传统上是小写的,我在下面使用小写)

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

fgets用于读取每一行。一个简单的辅助函数str_rmcrlf从读取的每个字符串的末尾修剪newline并返回其长度。不以'#'开头的每一行都复制到synonym[idx].ausdruckstrchr用于检查'('的每一行。如果找到,则将(...)的内容解析为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字符,从而导致部分读取或短读。您可以检查并处理指示的位置(或通过增加长度到128来简单地为每行提供足够的存储空间)。



将每一行拆分为单词

好的,注释现在可以帮助您阐明要完成的工作。在介绍实现之前,让我们先看一下C。 C语言比其他任何语言(汇编语言除外)更精确。 C语言中没有足够接近的语法。

尽管可能有很多方法可以找到解决方案,但就每一行代码而言,每一行中的每个字符都可以-是正确的-或错误的。您必须了解为什么需要每个字符及其作用。对于每个函数,无论是标准库中的函数,还是您编写的函数,您都必须知道该函数采用哪些参数,该函数对每个参数执行什么操作以及每个函数返回什么。

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

学习C时,遇到一些您不了解的内容-查一下。将手册页的主要权限用于所使用的标准库。使用信誉良好的教程。在这里提问。但是要小心,在所谓的编程站点上张贴了很多代码,这完全是错误的。

所有编译器都为您提供了帮助您正确实现的工具。绝对最基本,最重要的是编译代码时编译器发出的警告。利用这一点。总是,总是在启用警告的情况下进行编译(例如-Wall -Wextra),直到代码没有警告地编译才接受代码(有一些例外,但它们非常非常罕见,在您遇到的任何情况下都不会遇到。不远的将来)

话虽这么说,该代码的适当的编译字符串将类似于:

gcc -Wall -Wextra -O3 -o bin/fgets_struct_words fgets_struct_words.c


(将优化-O3替换为gcc上的-g以启用调试符号)

下面的代码使用相同的结构数组,但是在每个结构中有一个二维char数组,用作字符串数组。非常重要的是,将struct数组和每个成员初始化为zero/nul。这样可以确保所有字符串都将以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);
}


输出量

$ ./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附加的单词,您只需要知道ausdruck属于哪个索引。不需要整个单独的2D阵列。例如,您可以通过将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 - 1,否则将其设置为n(即0)。关键是要防止如果行以aindex开头(这将表示无效的数组索引),则将anmerkung设置为负数。

关于c - 将文件读入结构,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34111117/

10-11 21:46