简体   繁体   English

为什么我的strcmp实际上没有检测到2个单词之间的最小值?

[英]Why doesn't my strcmp actually detect the smallest between 2 words?

I'm trying to write a program that finds the "greatest" and "smallest" between a set of words inputted by the user. 我正在尝试编写一个程序,该程序在用户输入的一组单词之间找到“最大”和“最小”。 The program should stop listening for words assign as the user inputs a 4 letters long word and I can suppose that there aren't any words longer than 20 letters. 程序应该停止监听分配给用户的单词,因为用户输入的单词长度为4个字母,我可以假设没有任何单词超过20个字母。

Here's how it should work: 它的工作方式如下:

    Enter word: dog
    Enter word: zebra
    Enter word: rabbit
    Enter word: catfish
    Enter word: walrus
    Enter word: cat
    Enter word: fish
    Smallest word: cat
    Largest word: zebra

I tried debugging the code and I noticed that my function only runs the first "if" twice (until zebra is inputted) and then stops working. 我尝试调试代码,发现我的函数只运行第一个“ if”两次(直到输入斑马线),然后停止工作。 I don't really get why, every word there is smaller than zebra so it should always run. 我真的不明白为什么,每个词都比斑马小,所以它应该总是运行。 Also I don't get why the second "if" doesn't run. 而且我不明白为什么第二个“如果”不运行。 Here's my code: 这是我的代码:

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

    #define N 20

    int read_line(char smallest[], char largest[]);

    int main(){
      char smallest[N], largest[N];
      int check = 0;

      while(check != 4){
        check = read_line(smallest, largest);
      }

      printf("Smallest word: %s\n", smallest);
      printf("Largest word: %s\n", largest);

      return 0;
    }

    int read_line(char smallest[], char largest[]){
      char input[N];

      printf("Enter word: ");
      scanf("%s", input);

      if(strcmp(smallest, input) < 0){
        printf("Smallest is: %s was: %s\n", input, smallest);
        strcpy(smallest, input);
      }
      if(strcmp(largest, input) > 0){
        printf("Largest is: %s was: %s\n", input, largest);
        strcpy(largest, input);
      }

      return strlen(input);
    }

As others have pointed out there might be a problem initialization. 正如其他人指出的那样,初始化可能会出现问题。 Since the array is not initialized you don't know what's there that's why a comment was saying it is generating an undefined behaviour. 由于数组未初始化,因此您不知道其中存在什么,这就是为什么评论说它正在生成未定义的行为的原因。 In my case I run your original code inputting twice and even after zebra it continued. 就我而言,我运行您的原始代码输入两次,甚至在zebra之后仍继续。 Anyway is always better to initialize. 无论如何总是最好进行初始化。

Just put a scanf outside the loop and initialize both values to the first input: 只需将scanf放在循环外,然后将两个值初始化为第一个输入:


EDIT I did not pay attention to strcmp usage because the main problem seemed to be the initalization. 编辑我没有注意strcmp用法,因为主要的问题似乎是初始化。

From your code and comment it is clear that you are also messing with strcmp . 从代码和注释中可以很明显地看出来,您还弄乱了strcmp You should have read the documentation : 您应该已经阅读了文档

int strcmp(const char *s1, const char *s2); Upon completion, strcmp() shall return an integer greater than, equal to, or less than 0 , if the string pointed to by s1 is greater than, equal to, or less than the string pointed to by s2 , respectively. 完成后,如果s1指向的字符串分别大于,等于或小于s2指向的字符串,则strcmp()应返回一个大于,等于或小于0的整数。

So strcmp(smallest, input) ) returns a value < 0 if smallest is less (before in the dictionary pages to be clear) than input . 因此strcmp(smallest, input) )如果smallest (在要清除的字典页面之前)小于inputstrcmp(smallest, input) )返回值< 0 You should change to if(strcmp(smallest, input) > 0) meaning smallest is greater than input or to if(strcmp(input, smallest) < 0) 您应该更改为if(strcmp(smallest, input) > 0)表示smallest大于input或者更改为if(strcmp(input, smallest) < 0)

strcmp(largest, input) returns > 0 if largest is bigger than input . 如果largest大于input strcmp(largest, input)返回> 0 Your condition strcmp(largest, input) > 0 is wrong. 您的条件strcmp(largest, input) > 0是错误的。 You want the opposite: you can invert the comparison: strcmp(largest, input) < 0 or invert the inputs: strcmp(input, largest) > 0 . 您希望得到相反的结果:您可以反转比较: strcmp(largest, input) < 0或反转输入: strcmp(input, largest) > 0


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

#define N 21

int read_line(char smallest[], char largest[]);

int main(){
  char smallest[N];
  char largest[N];
  int check = 0;
  char firstInput[N];

  printf("Enter word: ");
  scanf("%s", firstInput);
  printf("Smallest and largest initialized to: %s\n", firstInput);
  strcpy(smallest, firstInput);
  strcpy(largest, firstInput);
  while(check != 4){
    check = read_line(smallest, largest);
  }

  printf("Smallest word: %s\n", smallest);
  printf("Largest word: %s\n", largest);

  return 0;
}

int read_line(char smallest[], char largest[]){
  char input[N];

  printf("Enter word: ");
  scanf("%s", input);

  if(strcmp(smallest, input) < 0){
    printf("Smallest is: %s was: %s\n", input, smallest);
    strcpy(smallest, input);
  }
  if(strcmp(largest, input) > 0){
    printf("Largest is: %s was: %s\n", input, largest);
    strcpy(largest, input);
  }

  return strlen(input);
}

In my opinion this is the clearer initialization (and more correct) since it uses user's input and does not rely on any condition. 在我看来,这是更清晰的初始化(并且更正确),因为它使用用户的输入并且不依赖任何条件。 However the code is less compact than other possible initializations since you are repeating some part of the code. 但是,由于重复了部分代码,因此代码比其他可能的初始化要紧凑。


EDIT alternative initializations 编辑替代初始化

There are other initialization methods. 还有其他初始化方法。 One is to initialize for example to the lowest letter: 一种是例如初始化为最低字母:

char smallest[N];
for (int i=0; i<N-1; i++)
{
  smallest[i] = 'z' ;
}
smallest[N-1] = '\0';
char biggest[N];
for (int i=0; i<N-1; i++)
{
  biggest[i] = 'a' ;
}
biggest[N-1] = '\0';

In your original code this will print something like zzzzz.... and aaaa.... 在您的原始代码中,它将打印类似zzzzz....aaaa....

Another alternative is to initialize them to the numerical min and max values of the range of char types (typically -128 and 127 ): 另一种选择是将它们初始化为char类型范围的数字最小值和最大值(通常为-128127 ):

#include<math.h>
...
char smallest[N] ;
char biggest[N] ;
for (int i=0; i<N-1; i++)
{
  smallest[i] = (char) (pow(2,sizeof(char)*8)/2 - 1);
}
smallest[N-1] = '\0';
for (int i=0; i<N-1; i++)
{
  biggest[i] = (char) -1*(pow(2,sizeof(char)*8)/2);
}
biggest[N-1] = '\0';

However in case in your first print will print thrash (better not to print at all ). 但是,以防万一,在您的第一张照片中会打印出乱码(最好根本不打印)。


EDIT FOR scanf alternatives 编辑scanf替代品

When a user is inputting anything, especially a string, it is a good behaviour to test if that input conforms to what you are expecting. 当用户输入任何内容(尤其是字符串)时,测试该输入是否符合您的期望是一个好习惯。 In C this becomes even more important since inputting a string longer than the length (actually length-1 ) of the array in which the string will be stored will cause Segmentation fault error and the program crashes. 在C语言中,这变得更加重要,因为输入的字符串长于将存储该字符串的数组的长度(实际上是length-1 ),将导致Segmentation fault错误,并且程序崩溃。

There is a simple way to avoid this: instead of scanf("%s", firstInput); 有一个简单的方法可以避免这种情况:代替scanf("%s", firstInput); do, in your specific case, scanf("%20s", firstInput); 在您的特定情况下,执行scanf("%20s", firstInput); ie the length of your input array minus 1 ( N-1 ). 即输入数组的长度减去1( N-1 )。 The problem with this approach is that you cannot use a dynamic value: for example: 这种方法的问题是您不能使用动态值:例如:

#define M 20

scanf("%Ms", firstInput); 

does not work. 不起作用。

According to this post you could: 根据这篇文章,您可以:

#define MAX_STRING_LENGTH 20
#define STRINGIFY(x) STRINGIFY2(x)
#define STRINGIFY2(x) #x

{
  ...
  char word[MAX_STRING_LENGTH+1];     
  scanf(file, "%" STRINGIFY(MAX_STRING_LENGTH) "s", word);
  ...
}

or follow the approach of this post : 或按照这篇文章的方法:

int scanner(const char *data, char *buffer, size_t buflen)
{
    char format[32];
    if (buflen == 0)
        return 0;
    snprintf(format, sizeof(format), "%%%ds", (int)(buflen-1));
    return sscanf(data, format, buffer);
}

NOTE 注意

If you mix words with and without capital letters, the ordering might not work anymore: Zookeeper (fantastic animal) comes before antilope . 如果您混合使用大写字母和不使用大写字母的单词,则排序可能不再起作用: Zookeeper (奇异动物)先于antilope

Ok, there are multiple flaws in your program: 好的,您的程序中存在多个缺陷:

  • First of all, as other answers pointed out, you should #define N as 21, not 20, so as to leave room for the null character. 首先,正如其他答案所指出的那样,您应该将N#定义为21而不是20,以便为空字符留出空间。

  • Secondly, you should initialize your strings. 其次,您应该初始化您的字符串。

  • And, most importantly, you have messed the order of your strcmp arguments. 而且,最重要的是,您弄乱了strcmp参数的顺序。 You should either pass first input and then the string you want to compare to, or change the inequality signs. 您应该先传递输入然后传递要比较的字符串,或者更改不等号。

  • Finally, you should initialize largest as "" so that the first character equals zero and so the string is smaller than all possible strings. 最后,您应该将Largest初始化为“”,以使第一个字符等于零,并且该字符串小于所有可能的字符串。 And you should initialize smallest to the largest possible string (eg "\\xFF", although that will not work if the input string starts with the non-ASCII character '\\xFF'). 并且您应该将最小初始化为最大可能的字符串(例如,“ \\ xFF”,尽管如果输入字符串以非ASCII字符“ \\ xFF”开头,这将不起作用)。 Then, when you enter the first string, it will be copied over both buffers. 然后,当您输入第一个字符串时,它将被复制到两个缓冲区中。 However, you'd better set a variable to check for the first input string given, and add a condition to copy it to both largest and smallest. 但是,最好设置一个变量以检查给定的第一个输入字符串,并添加一个条件以将其复制到最大和最小两个字符串中。 This is slightly more complex, but works with all strings. 这稍微复杂一点,但适用于所有字符串。

Here is your updated code: 这是您更新的代码:

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

#define N 21

int read_line(char smallest[], char largest[]);

int not_first = 0;

int main(){
  char smallest[N], largest[N];
  int check = 0;

  while(check != 4){
    check = read_line(smallest, largest);
  }

  printf("Smallest word: %s\n", smallest);
  printf("Largest word: %s\n", largest);

  return 0;
}

int read_line(char smallest[], char largest[]){
  char input[N];

  printf("Enter word: ");
  scanf("%s", input);

  if(strcmp(input, smallest) < 0 || !not_first){
    printf("Smallest is: %s was: %s\n", input, (not_first)? smallest : "(none)");
    strcpy(smallest, input);
  }
  if(strcmp(input, largest) > 0 || !not_first){
    printf("Largest is: %s was: %s\n", input, (not_first)? largest : "(none)");
    strcpy(largest, input);
  }
  not_first = 1;

  return strlen(input);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM