如何使用 strcmp() 检测重复字符串

How to detect duplicate string using strcmp()

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

struct stud
{
    char nam[20];
    int num;
    char letter[5];
};

int main()
{
    struct stud s[5];
    int i, j;

    for(i = 0; i < 5; i++){
        printf("Enter the name of student #%d: ", i+1);
        scanf("%s", s[i].nam);
        printf("Enter the number grade of student #%d: ", i+1);
        scanf("%d", &s[i].num);
    }
    
    for (j = 0; j < i; j++) { 
            if (strcmp(s[i].nam, s[j].nam) == 0)
                printf("Error. Duplicate name detected.");
        
    }
    
    for(i = 0; i < 5; i++){
    
        if(s[i].num >= 90 )
            strcpy(s[i].letter, "A");
        else if(s[i].num >= 80)
            strcpy(s[i].letter, "B");
        else if(s[i].num >= 70)
            strcpy(s[i].letter, "C");
        else if(s[i].num >= 60)
            strcpy(s[i].letter, "D");
        else
            strcpy(s[i].letter, "F");
    }

    for(i = 0; i < 5; i++)
        printf("\n%s has a %s ", s[i].nam, s[i].letter);
    return 0;
 }

该程序让用户输入 5 个姓名和 5 个数字成绩,然后将输出该学生各自的字母成绩。我正在努力做到这一点,如果用户输入重复的名称,则会打印消息说他们不能这样做。我尝试这样做的尝试如下:

for (j = 0; j < i; j++) { 
            if (strcmp(s[i].nam, s[j].nam) == 0)
                printf("Error. Duplicate name detected.");

    }

我认为 s[j] 是前一个字符串,比较它是否等于 0(重复)并打印一条消息。这显然不起作用,所以我想知道如何解决这个问题,以便它可以正确检测重复的名称。谢谢。

我之前也发布过这个问题,但提供解释的人在我可以提供进一步的问题并要求澄清之前删除了他们的回复。因此,我再次发布这篇文章,试图就我在代码中做错的地方寻求进一步的帮助。

  1. 在检测循环开始时,i 已经是 5,所以使用 s[i]未定义的行为
  2. 在你的检测循环中,i 是不变的。您只是将一个名称与最后一个名称进行比较[当然,UB 除外]。

您需要两个 循环来比较所有名称。

此外,到处使用 5 是一个“神奇的数字”。最好使用 #define(例如 SMAX


在下面的代码中,我使用 cpp 条件来表示旧代码与新代码:

#if 0
// old code
#else
// new code
#endif

#if 1
// new code
#endif

这是更正后的代码。它带有错误和修复注释:

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

struct stud {
    char nam[20];
    int num;
    char letter[5];
};

#define SMAX    5                       // maximum number of students

int
main()
{
    struct stud s[SMAX];
    int i, j;

    for (i = 0; i < SMAX; i++) {
        printf("Enter the name of student #%d: ", i + 1);
        scanf("%s", s[i].nam);
        printf("Enter the number grade of student #%d: ", i + 1);
        scanf("%d", &s[i].num);
    }

// NOTE/BUG: i is already SMAX, so using s[i] is UB (undefined behavior)
// NOTE/BUG: i never changes
#if 0
    for (j = 0; j < i; j++) {
        if (strcmp(s[i].nam, s[j].nam) == 0)
            printf("Error. Duplicate name detected.");
    }
#else
    for (i = 0; i < (SMAX - 1); i++) {
        for (j = i + 1; j < SMAX; j++) {
            if (strcmp(s[i].nam, s[j].nam) == 0)
                printf("Error. Duplicate name detected -- %s\n",s[j].nam);
        }
    }
#endif

    for (i = 0; i < SMAX; i++) {
        if (s[i].num >= 90)
            strcpy(s[i].letter, "A");
        else if (s[i].num >= 80)
            strcpy(s[i].letter, "B");
        else if (s[i].num >= 70)
            strcpy(s[i].letter, "C");
        else if (s[i].num >= 60)
            strcpy(s[i].letter, "D");
        else
            strcpy(s[i].letter, "F");
    }

// NOTE/BUG: newline should go at the end of the printf to prevent a hanging
// last line
#if 0
    for (i = 0; i < SMAX; i++)
        printf("\n%s has a %s ", s[i].nam, s[i].letter);
#else
    for (i = 0; i < SMAX; i++)
        printf("%s has a %s\n", s[i].nam, s[i].letter);
#endif

    return 0;
}

更新:

Thanks for the tip! On a side note, how would I make it so while the user is entering the duplicate names, the error message appears and the program ends right there.For example: Enter the name of student 1: dan Enter grade: 87 Enter the name of student 2: dan Enter the grade: 78 Error. No duplicate names allowed. And then the program ends there. – User234567

很简单。我将重复检测代码放入函数中。

但是,我添加了一些增强功能,因此这可能对您的学习有所帮助 ;-)

  1. 我添加了在用户输入重复项时重新提示他们。

  2. 我讨厌 scanf ;-) 我重新编写了提示代码,将其放入两个函数中。如果输入是文件,效果会更好。这在测试期间很有用

  3. 我更改了从年级数字到年级字母的转换以使用 table。

无论如何,这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>

struct stud {
    char nam[20];
    int num;
    char letter[5];
};

struct letter {
    int num;
    const char *letter;
};

#define LET(_num,_let) \
    { .num = _num, .letter = _let }

struct letter letters[] = {
    LET(90,"A"),
    LET(80,"B"),
    LET(70,"C"),
    LET(60,"D"),
    LET(0,"F"),
    LET(0,NULL)
};

#define SMAX    5                       // maximum number of students

// chkall -- check entire array for duplicates
int
chkall(const struct stud *s,int smax)
{
    int i;
    int j;
    int dup = 0;

    for (i = 0; i < (smax - 1); i++) {
        for (j = i + 1; j < smax; j++) {
            if (strcmp(s[i].nam, s[j].nam) == 0) {
                printf("Error. Duplicate name detected -- %s\n",s[j].nam);
                dup += 1;
            }
        }
    }

    return dup;
}

// chkone -- check a given entry for duplicate (as they are added)
int
chkone(const struct stud *s,int i)
{
    int j;
    int dup = 0;

    for (j = 0; j < i; j++) {
        if (strcmp(s[i].nam, s[j].nam) == 0) {
            printf("Error. Duplicate name detected -- %s\n",s[j].nam);
            dup += 1;
        }
    }

    return dup;
}

// prompt_string -- prompt user for a string
char *
prompt_string(const char *what,int i,char *buf,size_t siz)
{
    static int tty = -1;

    // decide if our input is tty or file
    if (tty < 0) {
        struct winsize ws;
        tty = ioctl(0,TIOCGWINSZ,&ws);
        tty = (tty >= 0);
    }

    printf("Enter the %s of student #%d: ", what, i + 1);
    fflush(stdout);

    char *cp = fgets(buf,siz,stdin);

    do {
        // handle EOF
        if (cp == NULL)
            break;

        buf[strcspn(buf,"\n")] = 0;

        // echo the data if input is _not_ a tty
        if (! tty)
            printf("%s\n",buf);
    } while (0);

    return cp;
}

// prompt_number -- prompt user for a number
long long
prompt_number(const char *what,int i)
{
    char *cp;
    char buf[100];
    long long val;

    while (1) {
        cp = prompt_string(what,i,buf,sizeof(buf));

        // handle EOF
        if (cp == NULL) {
            val = -1;
            break;
        }

        // decode the number
        val = strtoll(buf,&cp,10);
        if (*cp == 0)
            break;

        printf("invalid number syntax -- '%s'\n",cp);
    }

    return val;
}

int
main(void)
{
    struct stud s[SMAX];
    int i;

    for (i = 0; i < SMAX; i++) {
        while (1) {
            prompt_string("name",i,s[i].nam,sizeof(s[i].nam));
            if (! chkone(s,i))
                break;
        }

        s[i].num = prompt_number("number grade",i);
    }

    // recheck all entries
    // this will _never_ report a duplicate because of the chkone above
    chkall(s,SMAX);

    for (i = 0; i < SMAX; i++) {
        for (struct letter *let = letters;  let->letter != NULL;  ++let) {
            if (s[i].num >= let->num) {
                strcpy(s[i].letter,let->letter);
                break;
            }
        }
    }

    for (i = 0; i < SMAX; i++)
        printf("%s has a %s\n", s[i].nam, s[i].letter);

    return 0;
}