【问题标题】:Having issues with strcmp() in C [duplicate]C中的strcmp()有问题[重复]
【发布时间】:2015-03-05 19:58:55
【问题描述】:

我已经为此工作了几个小时,它表示要测试我的理智。

任务是编写一个程序,当它读取一个名称时,它会检查给定结构的名称并查找匹配项,然后显示结构中的其他数据。尽管输入字符串是大小写,但它应该可以工作,如果没有与名称匹配的内容,它应该告诉用户。

当然,一切都编译得很好,但是当我输入一个应该命中的名称时(因为它在结构中),它看不到它。

我知道问题出在 strcmp 调用的某个地方。

任何帮助将不胜感激。

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



typedef struct solar    
{
    char name[50];
    char type[50];
    double radius;
    double mass;
    double distsun;

}solar_obj;

void main()
{
    char input_name[50];

    solar_obj solarobj[] = { { "CERES", "DWARF PLANET", 471, 9.5E20, 413.7E6    },
                            { "EARTH", "PLANET", 6380, 5.974E24, 149.6E6 },
                            { "ERIS", "DWARF PLANET", 1163, 1.7E22, 10210E6 },   
                            { "HAUMEA", "DWARF PLANET", 650, 4E21, 6484E6 },
                            { "JUPITER", "PLANET", 71500, 1.899E27, 778.4E6 },    
                            { "MAKEMAKE", "DWARF PLANET", 715, 2.2E21, 6850E6 },
                            { "MARS", "PLANET", 3400, 6.419E23, 227.9E6 },
                            { "MERCURY", "PLANET", 2440, 3.302E23, 57.9E6 },
                            { "NEPTUNE", "PLANET", 24770, 1.024E26, 4498.3E6 },    
                            { "PLUTO", "DWARF PLANET", 1184, 1.3E22, 5906.4E6},
                            { "SATURN", "PLANET", 60270, 5.685E26, 1426.7E6 },
                            { "SUN", "STAR", 696000, 1.9891E30, 0 },
                            { "URANUS", "PLANET", 25560, 8.685E25, 2870.9E6 },  
                            { "VENUS", "PLANET", 6050, 4.869E24, 108.2E6 }
                          };

    printf("Please enter the name of the solar object:");

    fgets(input_name, sizeof(input_name), stdin);

    //to make all inputed string chars into uppercase
    for (int i = 0; input_name[i] != '\0'; i++){
        input_name[i] = toupper(input_name[i]);
    }

    //search through struct for matching name then print the data
    for (int j = 0; j < 14; j++)
        {
            if (strcmp(solarobj[j].name, input_name) == 0)
                {
                printf("\nObject name is :  %s \n", solarobj[j].name);
                printf("%s is a %s \n", solarobj[j].name, solarobj[j].type);
                printf("Radius (km) : %f \n ", solarobj[j].radius);
                printf("Mass (kg) : %f\n", solarobj[j].mass);
                printf("Distance from sun (km) : %f \n", solarobj[j].distsun);
                }

            else // if a name that doesnt match anything in the struct tell the user
            {
               if (j == 13){
                  printf("No objects in our solar system have the name: %s\n", input_name);
                  break;
               }    

               continue;
            }     
        }    


    getch();
}

【问题讨论】:

  • 我想知道您是否对输入末尾的额外换行符有问题,干扰您的 strcmp
  • 我的首要建议是学习如何使用调试器。如果您使用 gcc,请说 gdb。我也猜想换行。您可以尝试使用 strncmp 代替。结构字符串中的字符
  • 另外,你的“else”并不像你想象的那样工作。无论是否匹配,您总是会收到“不匹配”错误。
  • 关于fgets() 的答案解释了这个问题。您可以改用scanf("%49s",input_name),它将读作输入一个单词(最多任何空格),而不是一行。 49 表示最多将读取 49 个字符,为终止字符“\0”留出足够的空间。
  • @halfflat scanf("%49s",input_name) 如果用户输入 "\n" 并将 "\n" 留在 stdin 中,则 input_name 将保持未初始化状态。推荐入住fgets()getline()

标签: c string strcmp


【解决方案1】:

首先,fgets()newline 保留在条目的末尾。你可以像这样摆脱它。

char *strp = strchr(input_name, '\n');  // look for newline
if (strp) *strp = '\0';                 // terminate string

接下来,您可以使用stricmp() 进行不区分大小写的比较。

if (stricmp(solarobj[j].name, input_name) == 0)

你的循环可以简化成这样

int j;
for (j = 0; j < 14; j++)
{
    if (stricmp(solarobj[j].name, input_name) == 0)
        {
        printf("\nObject name is :  %s \n", solarobj[j].name);
        printf("%s is a %s \n", solarobj[j].name, solarobj[j].type);
        printf("Radius (km) : %f \n ", solarobj[j].radius);
        printf("Mass (kg) : %f\n", solarobj[j].mass);
        printf("Distance from sun (km) : %f \n", solarobj[j].distsun);
        break;
    }     
}    
if (j == 14)
    printf("No objects in our solar system have the name: %s\n", input_name);

请注意,我在循环之外声明了 j,因此当我测试是否找到匹配项时,它的范围仍然有效。

【讨论】:

  • 请注意stricmp 是非标准的,可能不可用。
  • @KeithThompson 谢谢。
  • 非常感谢您,当然您说的一切都是正确的,我的代码现在可以正常工作了。
【解决方案2】:

函数fgets() 的文档说:

从流中读取字符并将它们作为 C 字符串存储到 str 中,直到读取 (num-1) 个字符或到达换行符或文件结尾,以先发生者为准。

换行符使 fgets 停止读取,但它被函数视为有效字符并包含在复制到 str 的字符串中。

变量 input_name 中的值以换行符 ('\n') 结尾,当然,它永远不会匹配列表中的太阳物体名称。

在开始在列表中搜索之前,您可以通过将其从字符串中删除(如果存在)轻松解决此问题:

void main() {
    char input_name[50];
    int i;

    solar_obj solarobj[] = { 
        /* the big list here */
    };

    printf("Please enter the name of the solar object:");
    fgets(input_name, sizeof(input_name), stdin);

    // make all inputed string chars into uppercase
    // stop when reach a new line or the end of the string
    for (i = 0; input_name[i] != '\n' && input_name[i] != '\0'; i++) {
        input_name[i] = toupper(input_name[i]);
    }
    // end the string here (replace the newline, if it's there)
    input_name[i] = '\0';

    //search through struct for matching name then print the data
    for (int j = 0; j < 14; j++) {
        /* the rest of the original code here */

【讨论】:

  • 您可能想在删除它之前检查它是否真的是换行符。如果输入的长度超过指定的大小,则字符串不会以换行符结尾(一行的其余部分将等待下一个 fgets 或其他输入调用)。
  • 你是对的。我改变了答案。
【解决方案3】:
the following code will perform the desired functionality
contains no no-portable function calls,
checks for input errors
compiles cleanly

#include <stdio.h>
//#include <conio.h> // <-- non portable, do not use
#include <stdlib.h>
#include <string.h>
#include <ctype.h>



struct solar   // < remove clutter from struct definition  
{
    char name[50];
    char type[50];
    double radius;
    double mass;
    double distsun;

};

// use valid main declaration
int main()
{
    char input_name[50] = {'\0'};  // initialize input field

    // use struct name, not typedef name
    // use vertical alignment of braces 
    //     rather than georgian formatting
    //     for readability
    struct solar solarobj[] = 
    { 
        { "CERES", "DWARF PLANET", 471, 9.5E20, 413.7E6 },
        { "EARTH", "PLANET", 6380, 5.974E24, 149.6E6 },
        { "ERIS", "DWARF PLANET", 1163, 1.7E22, 10210E6 },   
        { "HAUMEA", "DWARF PLANET", 650, 4E21, 6484E6 },
        { "JUPITER", "PLANET", 71500, 1.899E27, 778.4E6 },    
        { "MAKEMAKE", "DWARF PLANET", 715, 2.2E21, 6850E6 },
        { "MARS", "PLANET", 3400, 6.419E23, 227.9E6 },
        { "MERCURY", "PLANET", 2440, 3.302E23, 57.9E6 },
        { "NEPTUNE", "PLANET", 24770, 1.024E26, 4498.3E6 },    
        { "PLUTO", "DWARF PLANET", 1184, 1.3E22, 5906.4E6},
        { "SATURN", "PLANET", 60270, 5.685E26, 1426.7E6 },
        { "SUN", "STAR", 696000, 1.9891E30, 0 },
        { "URANUS", "PLANET", 25560, 8.685E25, 2870.9E6 },  
        { "VENUS", "PLANET", 6050, 4.869E24, 108.2E6 }
    };

    // calculate number of entries in table
    int tableCount = sizeof(solarobj) / sizeof(struct solar);

    printf("Please enter the name of the solar object:");

    // always check to assure input operation is successful
    if( NULL == fgets(input_name, sizeof(input_name), stdin) )
    { // then fgets failed
        perror( "fgets for planet name failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, fgets successful

    char *strp = strchr(input_name, '\n');  // look for newline
    if (strp) *strp = '\0';                 // remove newline, if present

    // change all upper case charactgers to lower case 
    for( int i=0; input_name[i]; i++ ) input_name[i] = tolower(input_name[i]);

    int found = 0; // indicate name not found

    //search through table for matching name then print the data
    for (int j = 0; j < tableCount; j++)
    {
        if (strcmp(solarobj[j].name, input_name) == 0)
        {
            printf("\nObject name is :  %s \n", solarobj[j].name);
            printf("%s is a %s \n", solarobj[j].name, solarobj[j].type);
            printf("Radius (km) : %f \n ", solarobj[j].radius);
            printf("Mass (kg) : %f\n", solarobj[j].mass);
            printf("Distance from sun (km) : %f \n", solarobj[j].distsun);
            found = 1; // indicate name found
            break;
        } // end if 
    } // end for

    if( !found ) printf("No objects in our solar system have the name: %s\n", input_name);

    // use common system function, not windows specific function
    getchar();
    return( 0 );
} // end function: main

【讨论】:

  • 标准没有描述声明int main()。您可能希望将其更改为 int main(void)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-14
  • 1970-01-01
  • 2011-12-01
  • 2014-08-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多