为什么以下 C 代码的输出中有额外的字符?

Why are there extra characters in the output of the following C code?

提问人:Matej 提问时间:12/4/2021 最后编辑:chqrlieMatej 更新时间:12/4/2021 访问量:142

问:

我有文件statistics.txt以下数据在哪里:

Mark = 100
Andy = 200

然后,我写了这段代码:

FILE *file_statistics_reading = fopen("statistics.txt", "r");

char line[1024];
int n = 0;
char player[10];

while (fgets(line, sizeof(line), file_statistics_reading) != NULL) {
    n = 0;
    for (int i = 0; i < 10; i++) {
        if ((line[i] > 'A') && (line[i] < 'z')) {
            player[n] = line[i];
            n = n + 1;
        }
    }
    printf("%s", player);
}

fclose(file_statistics_reading);

我想从文本文件中提取球员的名字并打印出来,但输出如下所示:

Mark╠╠╠╠╠╠╠╠╠╠╠╠╠
Andy╠╠╠╠╠╠╠╠╠╠╠╠╠

有什么解决办法吗?

数组 C 字符串 IO 字符

评论

4赞 kaylum 12/4/2021
您需要 NUL 终止数组以使其成为有效的字符串。 在 .当然,您还应该增加尺寸以确保它始终适合 NUL。player[n] = '\0';printfplayer
0赞 Matej 12/4/2021
@kaylum 谢谢!
2赞 Steve Summit 12/4/2021
C 语言中的字符串不仅仅是字符数组,它们还是以 null 结尾的字符数组。当您让编译器通过在源代码中提及字符串来为您构造字符串时,它会负责为您附加 null 字符。当您让大多数 C 函数为您创建字符串(like 或 with )时,它们会为您追加 null 字符。但是,当您自己构建一个字符串时,一次一个字符,就像您在这里所做的那样,您有责任自己添加 null 字符。fgetsscanf%s

答:

0赞 chqrlie 12/4/2021 #1

代码中存在多个问题:

  • 您忘记在 中的名称后设置一个 null 终止符,这解释了输出中的随机字节。 是一个自动数组:其内容在创建时是不确定的。playerplayer
  • 您应该将一个字节长。player
  • 字母测试不正确:并且将导致循环停止,因为您使用 and 而不是 and'A''z'><>=<=
  • 根据字符集的不同,将打印一些非字母字节,例如 、 、 、 和 ASCII。您应该使用 from .[\]^_`isalpha()<ctype.h>
  • 如果行中出现多个单词,则前 10 个字节中的字母将作为所有行的单个 blob。用换行符分隔输出。
  • 您不检查行尾,因此即使读取行尾以外的内容不确定,也会测试 10 个字节。

这是一个修改后的版本:

#include <ctype.h>
#include <stdio.h>

void print_players(void) {
    char line[1024];
    FILE *file_statistics_reading = fopen("statistics.txt", "r");
    
    if (file_statistics_reading == NULL) {
        perror("cannot open statistics.txt");
        return;
    }
    while (fgets(line, sizeof(line), file_statistics_reading) != NULL) {
        char player[11];
        size_t n = 0;
        for (size_t i = 0; n < sizeof(player) - 1 && line[i] != '\0'; i++) {
            if (isalpha((unsigned char)line[i]) {
                player[n++] = line[i];
            }
        }
        player[n] = '\0';
        printf("%s\n", player);
    }
    fclose(file_statistics_reading);
}

以下是打印该行第一个单词的替代方法:

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

void print_players(void) {
    char line[1024];
    FILE *file_statistics_reading = fopen("statistics.txt", "r");
    const char *letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
    if (file_statistics_reading == NULL) {
        perror("cannot open statistics.txt");
        return;
    }
    while (fgets(line, sizeof(line), file_statistics_reading) != NULL) {
        int start = strcspn(line, letters);       // skip non letters
        int len = strspn(line + start, letters);  // count letters in word
        printf("%.*s\n", len, line + start);
    }
    fclose(file_statistics_reading);
}