【问题标题】:Having trouble comparing strings in file to an array of strings inputted by user in C将文件中的字符串与用户在 C 中输入的字符串数组进行比较时遇到问题
【发布时间】:2012-03-27 01:06:04
【问题描述】:

我试图研究这个问题,但找不到任何可以帮助我的东西。我一直在尝试使用fprint 进行调试,但仍然无法弄清楚。

我是一名中级程序员,如果我能在这里得到一些帮助,我会很高兴。这是我的代码:

int i = 0;
const int arraySize = 10;
char buf[256];
char str[256];
char buffer[256];
char *beerNames[arraySize] = { };

FILE *names;
FILE *percent;
i = 0;
int numBeers = 0;
printf("Please enter a name or (nothing to stop): ");
gets(buf);
while (strcmp(buf, "") != 0) {
    beerNames[i] = strdup(buf);
    i++;
    numBeers++;

    if (numBeers == arraySize)
        break;

    printf("Please enter a name or (nothing to stop): ");
    gets(buf);
}

// now open files and look for matches of names:        //      
names = fopen("Beer_Names.txt", "r");
percent = fopen("Beer_Percentage.txt", "r");

while (fgets(str, sizeof(str) / sizeof(str[0]), names) != NULL) {
    fgets(buffer, sizeof(buffer) / sizeof(buffer[0]), percent);
    for (i = 0; i < numBeers; i++) {
        if (strcmp(str, beerNames[i]) == 0) {
            printf("Beer: %s Percentage: %s\n", str, beerNames[i]);
            break;
        }
    }
}

fclose(names);
fclose(percent);

所以,我遇到的问题是,当我尝试 strcmp() 时,它没有正确比较,而是返回 -11。我也试过打印出strcmp() 值,当它等于0时它最终会跳过匹配。

我的 Beer_Names.txt(已缩短)如下所示:

Anchor Porter
Anchor Steam
Anheuser Busch Natural Light 
Anheuser Busch Natural Ice
Aspen Edge
Big Sky I.P.A. 
Big Sky Moose Drool Brown Ale 
Big Sky Powder Hound (seasonal) 
Big Sky Scape Goat Pale Ale 
Big Sky Summer Honey Ale (seasonal) 
Blatz Beer 
Blatz Light
Blue Moon

我的 Beer_Percentage.txt(缩短)如下所示:

5.6
4.9
4.2
5.9
4.1
6.2
5.1
6.2
4.7
14.7
4.8
0
5.4

这不是家庭作业,我只是在做一个个人项目,我想在 C 方面做得更好。

【问题讨论】:

    标签: c arrays string compare strcmp


    【解决方案1】:

    您的问题是 gets() 不会将换行符作为字符串的一部分返回,而 fgets() 会。

    所以当用户输入的值“Anchor Porter”用gets读取时,你的字符串看起来像这样"Anchor Porter\0",但是当你用fgets从文件中读取它时,它最终会像这样"Anchor Porter\n\0",不会比较相等。

    【讨论】:

    • gets() 也已被弃用,因为它无法检查缓冲区溢出。
    【解决方案2】:
    gets(buf);
    

    我知道gets(3) 很方便,我知道这是一个玩具,但请不要使用gets(3)。用gets(3) 编写安全代码是不可能的,而且未来的 C 库甚至可能不包含这个函数是合理的。 (是的,我知道它是标准化的,但我们希望未来的版本会省略它;POSIX.1-2008 已将其删除。)合理的编译器会警告您有关它的使用。请改用fgets(3)

    while (fgets(str, sizeof(str) / sizeof(str[0]), names) != NULL) {
    

    sizeof(char) 定义为1。这不太可能改变,你也不太可能改变数组的类型。这通常没什么大不了的,但是您不能像您可能怀疑的那样经常使用这样的构造——您可以在这种情况下使用它,只是因为str[] 被声明在这一行的封闭范围内。如果 str 作为参数传递,sizeof(str) 运算符将返回数据指针的大小,不是数组的大小。不要太习惯这种结构——它不会总是像你期望的那样工作。

    names = fopen("Beer_Names.txt", "r");
    percent = fopen("Beer_Percentage.txt", "r");
    
    while (fgets(str, sizeof(str) / sizeof(str[0]), names) != NULL) {
        fgets(buffer, sizeof(buffer) / sizeof(buffer[0]), percent);
    

    请花时间检查fopen(3) 是否成功。这是一个好习惯,如果你提供了一个好的错误信息,它也可以为你节省未来的时间。将fopen() 行替换为如下内容:

    names = fopen("Beer_Names.txt", "r");
    percent = fopen("Beer_Percentage.txt", "r");
    
    if (!names) {
        perror("failed to open Beer_Names.txt");
        exit(1);
    }
    if (!percent) {
        perror("failed to open Beer_Percentage.txt");
        exit(1);
    }
    

    您可以将其包装到一个执行 fopen() 的函数中,检查返回值,然后打印错误消息并退出或返回 FILE* 对象。

    现在,将您带到这里的错误:Robert 指出 fgets(3)gets(3) 以不同的方式处理终止的输入换行符。 (还有一个尽快摆脱gets(3) 的理由。)

    【讨论】:

    • 非常感谢您的建议,我会确保从现在开始这样做!
    猜你喜欢
    • 2023-03-10
    • 1970-01-01
    • 2014-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    • 1970-01-01
    相关资源
    最近更新 更多