C 获取文本文件的每个元素直到“:”并存储在结构变量上

C 获取文本文件的每个元素直到“:”并存储在结构变量上,c,arrays,file,struct,C,Arrays,File,Struct,我需要帮助:/ 在textfile中,我有如下内容: 我的名字:15 3 我想读取每个元素直到“:”并将其存储在结构的变量名中,然后读取下一个元素并将15和3存储在另一个变量中 typedef struct STRUCT_PLAYER{char name[20]; int sucess; int numQuest; int wrongs;} PLAYER

我需要帮助:/

在textfile中,我有如下内容: 我的名字:15 3

我想读取每个元素直到“:”并将其存储在结构的变量名中,然后读取下一个元素并将15和3存储在另一个变量中

typedef struct STRUCT_PLAYER{char name[20];
                        int sucess;
                        int numQuest;
                        int wrongs;} PLAYER;


int readTop(PLAYER playTop[]){
    char *classify = "classificacao.txt";
    FILE *fl;
    fl = fopen(classify, "r");

    char c;
    int n=0;

    if(cl==NULL){
        printf("Error reading the file %s\n", classify);
        exit(1);
    }
    else{
        while(c!=EOF){
            while(c!=':'){
                c=getc(fl);
                if(c!=':') playTop[n].name=c;
            }
            if(c==':')fscanf(fl, "  %d  %d\n", &playTop[n].numQuest, &playTop[n].wrongs);

            n++;

        }

    }
return n;
这是我的代码,但在这一行,它似乎是一个错误

ifc!=':'playerTOP[n].nome=c

错误:分配给数组类型为的表达式

但是我不明白它是什么

数组名不是一个可修改的左值。您正在分配给它。违反规则。这就是编译器抱怨的原因。即使它是可修改的,您的类型也不兼容。将字符分配给字符[]

更合乎逻辑的做法是这样做

playerTOP[n].nome[some_index]=c;
必须将这些字符存储在struct.com的nome成员数组中,该数组是char数组而不是char

也做int c,然后做检查c=EOF.

数组名称不是可修改的左值。您正在分配给它。违反规则。这就是编译器抱怨的原因。即使它是可修改的,您的类型也不兼容。将字符分配给字符[]

更合乎逻辑的做法是这样做

playerTOP[n].nome[some_index]=c;
必须将这些字符存储在struct.com的nome成员数组中,该数组是char数组而不是char

也做int c,然后做检查c=EOF.

c是char,playTop->name是char[],因此您正在分配不兼容的类型。也

coderredoc

数组名称不是可修改的左值

初始化结构时,请执行以下操作:

int n=0;
playTop[n].name[0] = 0;

...

while(c!=':'){
    char cs[] = { getc(fl), 0 };
    if(c!=':')
        strcat(playTop[n].name, cs);
}
此cs是一个仅包含一个字母和strcat附录的C字符串 playTop[n].name的字符串,从而保存名称

编辑

里卡多的评论


多谢各位。但是我不明白为什么你在char cs[]={getcfl,0}上加一个零

这就是我在评论中所说的。在C语言中,字符串必须是 “\0”-已终止

C字符串是一个字节序列。此序列必须以值0结束。 序列中的每个值都表示一个基于 编码,例如 字符“a”是97,“b”是98,以此类推。字符“\0”具有 值为0,字符决定字符串的结尾。 这就是为什么您经常听到C字符串以“\0”结尾的原因

在C语言中,使用字符数组char string[],char string[SOME VALUE]来 保存一个字符串。对于长度为n的字符串,需要一个维数为n+1的数组,因为 终止字符“\0”还需要一个空格

在处理字符串时,您必须始终考虑正确的类型, 您使用的是数组还是指针。指针 到char并不一定意味着您正在处理一个C字符串

我们来看看

char str1[] = "Hallo";
char str2[] = { 'H', 'a', 'l', 'l', 'o', 0 };
两个声明都做同样的事情,它们初始化了数组str1和str1 具有6个元素的str2。str1[5]和str2[5]将是相同的:0或'\0' 在它的字符表示法中

字符串文字是用引号括起来的文本,Hello是字符串 字面意义的链接器将序列放在进程内存的某个地方 “H”、“a”、“l”、“l”、“o”、0在内存中,通常为只读内存注释0 最后。即使您没有显式地编写“\0”,它也会 一个

字符序列末尾的“\0”使序列成为 C字符串,而不是变量的类型。如果结尾没有“\0”,则它不是C字符串

char cs[] = { getc(fl), 0};
是一个缩写

char cs[2];
cs[0] = getc(fl);
cs[1] = '\0';
通过完成最后的赋值,我确保cs持有一个C字符串。最 在string.h标准库中定义的函数需要C字符串,因此 必须以“\0”结尾

载人航天飞机

最后一件事:

使用数组保存字符串并不坏,问题是 字符串的最大长度为维度或数组-1。就你而言 名称不能超过19个字符,否则将有一个缓冲区 溢出,您将对未分配给的内存进行写操作 名称,您将有未定义的行为,任何事情都可能发生

当您知道字符串的最大长度不会超过某个值时 假设是15,那么可以使用char name[20]。如果没有保证 如果是最大长度,则必须使用 malloc/realloc以及更高版本,您必须释放该内存

另外,解析行的更好方法是使用fgets获取while 行,然后对其进行分析:

typedef struct STRUCT_PLAYER{char *name;
                        int sucess;
                        int numQuest;
                        int wrongs;} PLAYER;


int readTop(PLAYER playTop[]){
    ...
    char line[1024];
    fgets(line, sizeof line, fl);

    int colon_index = strchr(line, ':');

    // color_index is the index where : is in the line,
    // the length of the name is colon_index - 1
    // because you have to save \0 as well, you need to
    // allocate one more space for the c-string
    //   name length  + 1 ==> (colon_index - 1) + 1
    // which equeals to colon_index
    playTop[n].name = malloc(colon_index);

    // copy the name from line into name. strncpy
    // copies at most `colon_index - 1` characters, if
    // \0 is not among them, it won't be appended at the end
    // you have to do that
    strncpy(playTop[n].name, line, colon_index - 1);

    // making sure that name becomes a c-string
    playTop[n].name[colon_index] = 0;

    // sscanf is like fscan, only it takes the content from
    // a string and not from a FILE object.
    // line + colon_index + 1 ensures that sscanf reads only
    // after the colon
    sscanf(line + colon_index + 1, "...", ...);
}
这样做可以确保名称可以有任意长度。注意 所有这些函数都可能失败:例如,如果 内存不足,如果不使用冒号,strhr可能返回NULL 在行中发现该行格式错误或为空。线路本身可能是 长度超过1024字节。为了简单起见,我省略了所有这些检查

如果您已经理解了我的代码,那么您可以通过检查 上面提到的错误。仔细阅读函数的文档 此处使用。

c是char,playTop->name是char[],因此您正在分配不兼容的类型。也

coderredoc

数组名称不是可修改的左值

初始化结构时,请执行以下操作:

int n=0;
playTop[n].name[0] = 0;

...

while(c!=':'){
    char cs[] = { getc(fl), 0 };
    if(c!=':')
        strcat(playTop[n].name, cs);
}
此cs是一个仅包含一个字母和strcat附录的C字符串 playTop[n].name的字符串,从而保存名称

编辑

里卡多的评论


多谢各位。但是我不明白为什么你在char cs[]={getcfl,0}上加一个零

这就是我在评论中所说的。在C语言中,字符串必须是 “\0”-已终止

C字符串是一个字节序列。此序列必须以值0结束。 序列中的每个值都表示一个基于 编码,例如 字符“a”是97,“b”是98,以此类推。字符“\0”具有 值为0,字符决定字符串的结尾。 这就是为什么您经常听到C字符串以“\0”结尾的原因

在C语言中,使用字符数组char string[],char string[SOME VALUE]来 保存一个字符串。对于长度为n的字符串,需要一个维数为n+1的数组,因为 终止字符“\0”还需要一个空格

在处理字符串时,您必须始终考虑正确的类型, 您使用的是数组还是指针。指针 到char并不一定意味着您正在处理一个C字符串

我们来看看

char str1[] = "Hallo";
char str2[] = { 'H', 'a', 'l', 'l', 'o', 0 };
两个声明都做同样的事情,它们初始化了数组str1和str1 具有6个元素的str2。str1[5]和str2[5]将是相同的:0或'\0' 在它的字符表示法中

字符串文字是用引号括起来的文本,Hello是字符串 字面意义的链接器将序列放在进程内存的某个地方 “H”、“a”、“l”、“l”、“o”、0在内存中,通常为只读内存注释0 最后。即使您没有显式地编写“\0”,它也会 一个

字符序列末尾的“\0”使序列成为 C字符串,而不是变量的类型。如果结尾没有“\0”,则它不是C字符串

char cs[] = { getc(fl), 0};
是一个缩写

char cs[2];
cs[0] = getc(fl);
cs[1] = '\0';
通过完成最后的赋值,我确保cs持有一个C字符串。最 在string.h标准库中定义的函数需要C字符串,因此 必须以“\0”结尾

载人航天飞机

最后一件事:

使用数组保存字符串并不坏,问题是 字符串的最大长度为维度或数组-1。就你而言 名称不能超过19个字符,否则将有一个缓冲区 溢出,您将对未分配给的内存进行写操作 名称,您将有未定义的行为,任何事情都可能发生

当您知道字符串的最大长度不会超过某个值时 假设是15,那么可以使用char name[20]。如果没有保证 如果是最大长度,则必须使用 malloc/realloc以及更高版本,您必须释放该内存

另外,解析行的更好方法是使用fgets获取while 行,然后对其进行分析:

typedef struct STRUCT_PLAYER{char *name;
                        int sucess;
                        int numQuest;
                        int wrongs;} PLAYER;


int readTop(PLAYER playTop[]){
    ...
    char line[1024];
    fgets(line, sizeof line, fl);

    int colon_index = strchr(line, ':');

    // color_index is the index where : is in the line,
    // the length of the name is colon_index - 1
    // because you have to save \0 as well, you need to
    // allocate one more space for the c-string
    //   name length  + 1 ==> (colon_index - 1) + 1
    // which equeals to colon_index
    playTop[n].name = malloc(colon_index);

    // copy the name from line into name. strncpy
    // copies at most `colon_index - 1` characters, if
    // \0 is not among them, it won't be appended at the end
    // you have to do that
    strncpy(playTop[n].name, line, colon_index - 1);

    // making sure that name becomes a c-string
    playTop[n].name[colon_index] = 0;

    // sscanf is like fscan, only it takes the content from
    // a string and not from a FILE object.
    // line + colon_index + 1 ensures that sscanf reads only
    // after the colon
    sscanf(line + colon_index + 1, "...", ...);
}
这样做可以确保名称可以有任意长度。注意 所有这些函数都可能失败:例如,如果 内存不足,如果不使用冒号,strhr可能返回NULL 在行中发现该行格式错误或为空。线路本身可能是 长度超过1024字节。为了简单起见,我省略了所有这些检查

如果您已经理解了我的代码,那么您可以通过检查 上面提到的错误。仔细阅读函数的文档
此处使用。

名称是一个字符数组,由于要逐字符复制,因此需要使用playTop[n]。名称[x]=c;由于名称是一个字符指针,当您尝试为其分配字符时,编译器对其没有意义。

名称是一个字符数组,并且由于您要逐个字符复制,因此需要使用playTop[n]。名称[x]=c;因为名称是一个字符指针,所以当您尝试为其分配字符时,编译器对它没有意义。

整个过程充满了错误:

while(c!=EOF){
        while(c!=':'){
            c=getc(fl);
            if(c!=':') playTop[n].name=c;
        }
        if(c==':')fscanf(fl, "  %d  %d\n", &playTop[n].numQuest, &playTop[n].wrongs);
可以很容易地减少,并应减少到干净:

while( 3 == fscanf( fl, " %19[^:]: %d %d", 
      playTop[n].name,   
      &playtop[n].numQuest, 
      &playTop[n].wrongs ) )
{
    n++;
}
整个过程充满了bug:

while(c!=EOF){
        while(c!=':'){
            c=getc(fl);
            if(c!=':') playTop[n].name=c;
        }
        if(c==':')fscanf(fl, "  %d  %d\n", &playTop[n].numQuest, &playTop[n].wrongs);
可以很容易地减少,并应减少到干净:

while( 3 == fscanf( fl, " %19[^:]: %d %d", 
      playTop[n].name,   
      &playtop[n].numQuest, 
      &playTop[n].wrongs ) )
{
    n++;
}

哇=EOF。。。。不,不是用字符类型的c。发布的代码不能编译!它缺少所需的include语句,缺少一个主函数,函数:readTop缺少最后一个右大括号“}”。请发布一个关于:ifcl==NULL的{.cl变量未在发布的代码中定义。具体检查的是什么?关于:fl=fopenclassify,r;1始终检查!=NULL返回值以确保操作成功。如果不成功,则调用perror以输出所附文本以及系统认为操作失败的原因。为了便于阅读,请可理解性和理解性:1遵循公理:每行只有一条语句,每行最多一条变量声明
陈述。2使用有意义的变量名。像:c、n、cl、fl这样的名字是没有意义的,即使在当前的上下文中也是如此。注意:一个文件指针,例如从fopen返回的指针,通常命名为:fp,如果有多个filewhilec,则稍加添加=EOF。。。。不,不是用字符类型的c。发布的代码不能编译!它缺少所需的include语句,缺少一个主函数,函数:readTop缺少最后一个右大括号“}”。请发布一个关于:ifcl==NULL的{.cl变量未在发布的代码中定义。具体检查的是什么?关于:fl=fopenclassify,r;1始终检查!=NULL返回值以确保操作成功。如果不成功,则调用perror以输出所附文本以及系统认为操作失败的原因。为了便于阅读,请可理解性和理解性:1遵循公理:每行只有一条语句,每条语句最多有一个变量声明。2使用有意义的变量名。像:c、n、cl、fl这样的名称,即使在当前上下文中也是没有意义的。注意:文件指针,例如从fopen返回的指针,通常被命名为:fp,如果有多个变量,则会略微增加ne文件谢谢。你是对的,我忘了。名称是字符串而不是元素。谢谢。你是对的,我忘了。名称是字符串而不是元素。谢谢你的回答。我刚到C,这是我的错误。名称是字符串,我试图将字符串与字符元素相等。有了这个,我想我可以解决问题。谢谢你记住,t这仅仅是因为你有一个char*或char[],你不一定有字符串!C字符串必须以'\0'结尾,只有当它是时,你才有C字符串。谢谢你。但是我不明白为什么你在char cs[]={getcfl,0}?不应该是一个\0?而且可能是做char cs[]={C=getcfl,0}因为c在中间loop@Ricardo不,这是因为创建了一个有效的c字符串。我对我的答案进行了编辑,在这里我解决了这个问题,还有一点谢谢你的回答。我刚到c,这是我的错误。名称是一个字符串,我试图将字符串与char元素相等。有了这个,我想我可以解决。谢谢你记住,j只是因为你有一个char*或char[],你不一定有字符串!C字符串必须以“\0”结尾,只有当它是时,你才有C字符串。谢谢。但我不明白为什么你在char cs[]={getcfl,0}?不应该是一个\0?而且可能是做char cs[]={C=getcfl,0}因为c在中间loop@Ricardo不,这是因为创建了一个有效的c字符串。我对我的答案进行了编辑,在这里我解决了这个问题,还有更多的问题