函数 fscanf 忽略 .txt 文件中的 space 分隔符
Function fscanf ignoring space separator in .txt file
我正在尝试在 C
中扫描以下格式的文本文件:
key01 value01
key02 value02
key03 value03
我想获取键和值字符串并将它们分配给我创建的结构:
struct Mapping
{
char key[sizeof(char) * 5];
char value[sizeof(char) * 7];
} MapElement;
我的代码如下:
void initialize_server_map(struct Mapping serverMap[])
{
char* fileName = "server1.txt";
FILE *fp = fopen(fileName, "r");
char *lineKey = (char*)malloc(sizeof(char) * 5);
char *lineValue = (char*)malloc(sizeof(char) * 7);
int i = 0;
while (fscanf(fp, "%s %s", lineKey, lineValue) != EOF) {
struct Mapping mapping;
memcpy(mapping.key, lineKey, sizeof(char) * 5);
memcpy(mapping.value, lineValue, sizeof(char) * 7);
printf("key: %s value: %s\n", mapping.key, mapping.value);
serverMap[i] = mapping;
i++;
}
fclose(fp);
}
int main(void)
{
int size = 4;
struct Mapping serverMap[size];
initialize_server_map(serverMap);
}
我的输出如下:
key: key01value01 value: value01
key: key02value02 value: value02
key: key03value03 value: value03
key: key04value04 value: value04
当然,我想要这样的输出:
key: key01 value: value01
key: key02 value: value02
key: key03 value: value03
key: key04 value: value04
我确定它与我分配内存的方式有关。有人可以帮我解决这个问题吗?另外,有没有更有效的方法来做到这一点?
由于数组访问越界,您遇到了未定义的行为。
为了存储 "key01"
,您需要一个大小至少为 6
的数组 -- 5
用于字符,一个用于终止空字符。
同样,你需要一个至少8
大小的数组来存储"value01"
.
您正在声明大小分别为 5
和 7
的数组。因此,在
中使用时,您正在越界修改数组
while (fscanf(fp, "%s %s", lineKey, lineValue) != EOF) {
好吧,至少您忘记了 space 用于在字符串中尾随 '\0'。所以如果你有 5 个字符的字符串,你应该分配 6 个字符。
但总的来说,整个方法是相当脆弱的。如果输入数据中的键长度超过 5 个字符怎么办?传统方法是为 scanf
(例如几百字节)使用 "big enough" 缓冲区,使用格式中的长度限制器限制 scanf
中可能的字符串长度(例如“%20s”而不是“ %s") 然后通过 strdup
.
分配 rquired space
所以整个块看起来像:
struct Mapping {
char* key;
char* value;
};
...
char lineKey[51];
char lineValue[51];
while (fscanf(fp, "%50s %50s", lineKey, lineValue) != EOF) {
struct Mapping* mp = (struct Mapping*)malloc(sizeof(struct Mapping));
assert(mp);
mp->key = strdup(lineKey);
mp->value = strdup(lineValue);
...
}
我正在尝试在 C
中扫描以下格式的文本文件:
key01 value01
key02 value02
key03 value03
我想获取键和值字符串并将它们分配给我创建的结构:
struct Mapping
{
char key[sizeof(char) * 5];
char value[sizeof(char) * 7];
} MapElement;
我的代码如下:
void initialize_server_map(struct Mapping serverMap[])
{
char* fileName = "server1.txt";
FILE *fp = fopen(fileName, "r");
char *lineKey = (char*)malloc(sizeof(char) * 5);
char *lineValue = (char*)malloc(sizeof(char) * 7);
int i = 0;
while (fscanf(fp, "%s %s", lineKey, lineValue) != EOF) {
struct Mapping mapping;
memcpy(mapping.key, lineKey, sizeof(char) * 5);
memcpy(mapping.value, lineValue, sizeof(char) * 7);
printf("key: %s value: %s\n", mapping.key, mapping.value);
serverMap[i] = mapping;
i++;
}
fclose(fp);
}
int main(void)
{
int size = 4;
struct Mapping serverMap[size];
initialize_server_map(serverMap);
}
我的输出如下:
key: key01value01 value: value01
key: key02value02 value: value02
key: key03value03 value: value03
key: key04value04 value: value04
当然,我想要这样的输出:
key: key01 value: value01
key: key02 value: value02
key: key03 value: value03
key: key04 value: value04
我确定它与我分配内存的方式有关。有人可以帮我解决这个问题吗?另外,有没有更有效的方法来做到这一点?
由于数组访问越界,您遇到了未定义的行为。
为了存储 "key01"
,您需要一个大小至少为 6
的数组 -- 5
用于字符,一个用于终止空字符。
同样,你需要一个至少8
大小的数组来存储"value01"
.
您正在声明大小分别为 5
和 7
的数组。因此,在
while (fscanf(fp, "%s %s", lineKey, lineValue) != EOF) {
好吧,至少您忘记了 space 用于在字符串中尾随 '\0'。所以如果你有 5 个字符的字符串,你应该分配 6 个字符。
但总的来说,整个方法是相当脆弱的。如果输入数据中的键长度超过 5 个字符怎么办?传统方法是为 scanf
(例如几百字节)使用 "big enough" 缓冲区,使用格式中的长度限制器限制 scanf
中可能的字符串长度(例如“%20s”而不是“ %s") 然后通过 strdup
.
所以整个块看起来像:
struct Mapping {
char* key;
char* value;
};
...
char lineKey[51];
char lineValue[51];
while (fscanf(fp, "%50s %50s", lineKey, lineValue) != EOF) {
struct Mapping* mp = (struct Mapping*)malloc(sizeof(struct Mapping));
assert(mp);
mp->key = strdup(lineKey);
mp->value = strdup(lineValue);
...
}