Почему мой strcmp не обнаруживает наименьшее из двух слов? - PullRequest
0 голосов
/ 27 января 2019

Я пытаюсь написать программу, которая находит «наибольшее» и «наименьшее» между набором слов, введенных пользователем.Программа должна прекратить прослушивать слова, назначенные, когда пользователь вводит слово длиной 4 буквы, и я могу предположить, что нет слов, длина которых превышает 20 букв.

Вот как это должно работать:

    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

Я попытался отладить код и заметил, что моя функция запускает только первое «если» дважды (до тех пор, пока не введен зебра), а затем перестает работать,Я не понимаю, почему, каждое слово там меньше, чем зебра, поэтому оно всегда должно выполняться.Также я не понимаю, почему второе «если» не запускается.Вот мой код:

    #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);
    }

Ответы [ 2 ]

0 голосов
/ 27 января 2019

Хорошо, в вашей программе есть несколько недостатков:

  • Прежде всего, как указывалось в других ответах, вы должны # определить N как 21, а не 20, чтобы оставитькомната для нулевого символа.

  • Во-вторых, вы должны инициализировать свои строки.

  • И, самое главное, вы перепутали порядок вашегоАргументы strcmp.Вы должны либо передать первый ввод, а затем строку, с которой хотите сравнить, или изменить знаки неравенства.

  • Наконец, вы должны инициализировать самое большое как «», чтобы первый символ равнялся нулю.и поэтому строка меньше всех возможных строк.И вы должны инициализировать от наименьшей до максимально возможной строки (например, «\ xFF», хотя это не сработает, если входная строка начинается с не-ASCII символа «\ xFF»).Затем, когда вы вводите первую строку, она будет скопирована в оба буфера.Однако вам лучше установить переменную для проверки первой заданной входной строки и добавить условие, чтобы скопировать ее как в наибольшую, так и в наименьшую.Это немного сложнее, но работает со всеми строками.

Вот ваш обновленный код:

#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);
}
0 голосов
/ 27 января 2019

Как уже отмечали другие, может быть проблема с инициализацией.Поскольку массив не инициализирован, вы не знаете, что там, поэтому в комментарии было сказано, что он генерирует неопределенное поведение.В моем случае я дважды запускаю ввод исходного кода, и даже после zebra это продолжается.В любом случае всегда лучше инициализировать.

Просто поместите scanf вне цикла и инициализируйте оба значения для первого ввода:


РЕДАКТИРОВАТЬ Я не сделалобратите внимание на использование strcmp, потому что главной проблемой, как представляется, является инициализация.

Из вашего кода и комментариев ясно, что вы также путаетесь с strcmp.Вы должны были прочитать документацию :

int strcmp(const char *s1, const char *s2); По завершении strcmp() вернет целое число, большее, равное или меньшее 0, еслистрока, на которую указывает s1, больше, равна или меньше строки, на которую указывает s2, соответственно.

Таким образом, strcmp(smallest, input) ) возвращает значение < 0, если smallest меньше (прежде чем на страницах словаря будет понятно) чем input.Вы должны изменить значение на if(strcmp(smallest, input) > 0), означающее, что smallest больше input или if(strcmp(input, smallest) < 0)

strcmp(largest, input) возвращает > 0, если largest больше input.Ваше состояние strcmp(largest, input) > 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);
}

На мой взгляд, это более четкая инициализация (и более правильная), поскольку онаиспользует ввод пользователя и не зависит ни от каких условий.Однако код менее компактен, чем другие возможные инициализации, поскольку вы повторяете некоторую часть кода.


РЕДАКТИРОВАТЬ альтернативные инициализации

Существуют и другие методы инициализации.Например, нужно инициализировать строчную букву:

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';

. В исходном коде это напечатает что-то вроде zzzzz.... и aaaa....

Другой вариант - инициализировать их какчисловые минимальные и максимальные значения диапазона char типов (обычно -128 и 127):

#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';

Однако, в случае, если в вашем первом отпечатке будет напечатан трэш (лучше не печатать вообще).


РЕДАКТИРОВАТЬ ДЛЯ альтернатив Scanf

Когда пользователь вводит что-либо, особенно строку, рекомендуется проверить, соответствует ли этот вводчто вы ожидаетеВ Си это становится еще более важным, так как ввод строки, длина которой превышает длину (на самом деле length-1) массива, в котором будет храниться строка, приведет к ошибке Segmentation fault и аварийному завершению программы.

Существуетпростой способ избежать этого: вместо scanf("%s", firstInput); сделайте, в вашем конкретном случае, scanf("%20s", firstInput);, т.е. длину вашего входного массива минус 1 (N-1).Проблема с этим подходом состоит в том, что вы не можете использовать динамическое значение: например:

#define M 20

scanf("%Ms", firstInput); 

не работает.

Согласно этому сообщению вы могли бы:

#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);
  ...
}

или следуйте подходу к этой записи :

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

Если вы смешаетеслова с заглавными буквами и без них, порядок может больше не работать: Zookeeper (фантастическое животное) предшествует antilope.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...