C 如何逐字阅读仅以“分隔”的单词:&引用;从缓冲区?

C 如何逐字阅读仅以“分隔”的单词:&引用;从缓冲区?,c,buffer,C,Buffer,我正在制作一个语言转换器,希望逐字读取缓冲区,并将它们存储在键值结构中 缓冲区包含这样一个文件: hola:hello que:what 等等。我已经试过了所有的方法,但我一直都有错误,比如分段错误:11或者只是一遍又一遍地读同一行 struct key_value{ char *key; char *value; }; struct key\u value*kv=malloc(sizeof(struct key\u value)*计数); chark[20]//钥匙 charv[20]/

我正在制作一个语言转换器,希望逐字读取缓冲区,并将它们存储在键值结构中

缓冲区包含这样一个文件:

hola:hello
que:what
等等。我已经试过了所有的方法,但我一直都有错误,比如分段错误:11或者只是一遍又一遍地读同一行

struct key_value{
char *key;
char *value;
};

struct key\u value*kv=malloc(sizeof(struct key\u value)*计数);
chark[20]//钥匙
charv[20]//价值
int x=0;
对于(i=0;i键=k;
(kv+i)->值=v;
}
对于(i=0;i键,(kv+i)->值);
}
自由(缓冲);
免费(千伏);
我希望输出是
key:hola,value:hello-key:que,value:what
, 但是实际的输出只是一遍又一遍地
key:hola,value:hello


哪种方法是正确的?

您的代码存在多个问题,其中包括

  • 在每次循环迭代中,从缓冲区的开始读取。因此,每个迭代提取相同的键和值是很自然的

  • 更一般地说,read循环迭代变量似乎与读取的数据没有关系。它似乎是一个每字节的迭代,但您似乎想要一个每行的迭代。您可能需要查看
    scanf
    %n
    指令,以帮助跟踪缓冲区中的进度

  • 将每个键/值对扫描到相同的本地
    k
    v
    变量中,然后将这些变量的指针分配到结构中。结果指针都是相同的,当函数返回时它们将变得无效。我建议为其成员提供
    struct
    key_-value`数组,而不是指针,并将数据复制到其中

  • 您的
    sscanf
    格式对键和值的读取长度最多为21个字符,但提供的目标数组不够长。您需要将它们标注为至少22个字符,以容纳21个字符和一个字符串终止符

  • 您的
    sscanf()
    格式和用法不支持识别格式错误的输入,尤其是过长的键或值。您需要检查返回值,并且可能需要将尾部换行符与
    %c
    字段相匹配(格式中的文字换行符并不是您认为的意思)

使用
strtok\u r
strtok
或甚至
strchr
而不是
sscanf()
标记(整个缓冲区)可能会更容易


另外,样式说明:您的表达式形式
(kv+i)->key
是有效的,但是编写
kv[i]更为惯用。key

我编写了一段简单的代码,可以帮助您解决问题。我使用函数
fgets
读取名为“file.txt”的文件,并使用函数
strchr
对第一次出现的分隔符
:'
进行个性化处理

代码如下:

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

#define MAX_LINE_SIZE       256
#define MAX_DECODED_LINE    1024

struct decod {
    char key[MAX_LINE_SIZE];
    char value[MAX_DECODED_LINE];
};

static struct decod decod[1024];

int main(void)
{
    FILE * fptr = NULL;

    char fbuf[MAX_LINE_SIZE];
    char * value;
    int cnt=0,i;

    if ( !(fptr=fopen("file.txt","r")) )
    {
        perror("");
        return errno;
    }

    while( fgets(fbuf,MAX_LINE_SIZE,fptr)) {
        // Eliminate UNIX/DOS line terminator
        value=strrchr(fbuf,'\n');
        if (value) *value=0;
        value=strrchr(fbuf,'\r');
        if (value) *value=0;

        //Find first occurrence of the separator ':'
        value=strchr(fbuf,':');
        if (value) {
            // Truncates fbuf string to first word
            // and (++) points second word
            *value++=0;
        }

        if (cnt<MAX_DECODED_LINE) {
            strcpy(decod[cnt].key,fbuf);
            if (value!=NULL) {
                strcpy(decod[cnt].value,value);
            } else {
                decod[cnt].value[0]=0;
            }
            cnt++;
        } else {
            fprintf(stderr,
                 "Cannot read more than %d lines\n", MAX_DECODED_LINE);
            break;
        }
    }

    if (fptr)
        fclose(fptr);

    for(i=0;i<cnt;i++) {
        printf("key:%s\tvalue:%s\n",decod[i].key,decod[i].value);
    }

    return 0;
}
#包括
#包括
#包括
#定义最大行大小256
#定义最大解码行1024
结构装饰{
字符键[最大行大小];
字符值[最大解码行];
};
静态结构装饰[1024];
内部主(空)
{
文件*fptr=NULL;
字符fbuf[最大行大小];
字符*值;
int cnt=0,i;
如果(!(fptr=fopen(“file.txt”,“r”))
{
佩罗尔(“”);
返回errno;
}
而(FGET(fbuf,最大线尺寸,fptr)){
//消除UNIX/DOS行终止符
值=strrchr(fbuf,'\n');
如果(值)*值=0;
值=strrchr(fbuf,'\r');
如果(值)*值=0;
//查找第一个出现的分隔符“:”
值=strchr(fbuf,,:');
如果(值){
//将fbuf字符串截断为第一个单词
//和(++)指向第二个单词
*值+++=0;
}

如果(cnt我写了这段代码,我认为它能完成任务!这比我认为公认的答案更简单!它使用的内存与所需的内存一样多,没有更多

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


struct key_value{
    char key[22];
    char value[22];
};

void parse_str(char* str, struct key_value** kv_arr, int* num){

    int  n    = 0;
    int  read = -1;
    char k[22];
    char v[22];
    int current_pos = 0;
    int consumed    = 0;

    /*counting number of key-value pairs*/
    while (1){
        if(current_pos > strlen(str)){
            break;
        }
        read = sscanf(str + current_pos, "%21[^:]:%21[^\n]\n%n", k, v, &consumed);
        current_pos += consumed;

        if(read == 2){
            ++n;
        }
    }
    printf("n = %d\n", n);
    *kv_arr = malloc(sizeof(struct key_value) * n);



    /*filling key_value array*/
    int i       = 0;
    read        = -1;
    current_pos = 0;
    consumed    = 0;
    while (1){
        if(current_pos > strlen(str)){
            break;
        }
        read = sscanf(str + current_pos, "%21[^:]:%21[^\n]\n%n", k, v, &consumed);
        current_pos += consumed;

        if(read == 2){
            struct key_value* kv = &((*kv_arr)[i]);
            strncpy(kv->key, k, 22);
            strncpy(kv->value, v, 22);
            ++i;
        }
    }

    *num = n;
}


int main(){

    char* str = "hola:hello\n"
                "que:what\n";

    int n;
    struct key_value* kv_arr;

    parse_str(str, &kv_arr, &n);

    for (int i = 0; i < n; ++i) {
        printf("%s  <--->  %s\n", kv_arr[i].key, kv_arr[i].value);
    }


    free(kv_arr);
    return 0;
}
#包括
#包括
#包括
结构键值{
字符键[22];
字符值[22];
};
void parse_str(char*str,结构键值**kv\u arr,int*num){
int n=0;
int read=-1;
chark[22];
charv[22];
int current_pos=0;
int=0;
/*计算键值对的数目*/
而(1){
如果(当前位置>strlen(str)){
打破
}
read=sscanf(str+current_pos,“%21[^:::%21[^\n]\n%n”,k,v,&consumered);
当前_pos+=消耗量;
如果(读==2){
++n;
}
}
printf(“n=%d\n”,n);
*kv_arr=malloc(sizeof(结构键值)*n);
/*填充键值数组*/
int i=0;
read=-1;
当前位置=0;
消耗=0;
而(1){
如果(当前位置>strlen(str)){
打破
}
read=sscanf(str+current_pos,“%21[^:::%21[^\n]\n%n”,k,v,&consumered);
当前_pos+=消耗量;
如果(读==2){
结构键值*kv=&(*kv_arr)[i]);
strncpy(kv->key,k,22);
strncpy(kv->value,v,22);
++一,;
}
}
*num=n;
}
int main(){
char*str=“hola:你好\n”
“que:什么\n”;
int n;
结构键值*kv\u arr;
解析_str(str,&kv_arr,&n);
对于(int i=0;i
输出:

n = 2
hola  <--->  hello
que  <--->  what
n=2
你好
什么
进程已完成,退出代码为0


注意
sscanf
const char*
上操作,而不是来自文件的输入流,因此它将存储有关它所使用的内容的任何信息
n = 2
hola  <--->  hello
que  <--->  what