strcmp возвращает неправильное значение - PullRequest
0 голосов
/ 14 февраля 2019

Может кто-нибудь объяснить мне, почему strcmp возвращает то же значение, даже если пароли верны / неверны?Я определил действительный пароль чуть ниже, включив раздел, и проверил его с введенным в конце моей программы.

Вот мой код:

#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <termios.h>

#define TIME 10
#define MAXPASSWORD 12
#define PASSWORD "pass123"

void sigalrm_handler() {
    printf("\nERR: Time is up...\n");
}

int getch() {
    struct termios oldtc, newtc;
    int ch;
    tcgetattr(STDIN_FILENO, &oldtc);
    newtc = oldtc;
    newtc.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newtc);
    ch=getchar();
    tcsetattr(STDIN_FILENO, TCSANOW, &oldtc);
    return ch;
}

int main(int argc, char * argv[]) {
    char password[MAXPASSWORD] = {0};
    printf("Enter correct password. You have %d seconds: ", TIME);
    signal(SIGALRM, sigalrm_handler);
    alarm(TIME);
    fflush(stdout);

    for(int i=0; i<MAXPASSWORD; i++)
    {
      password[i] = getch();
      if (password[i] == '\n')
        break;
      printf("*");
    }

    if (strcmp(password, PASSWORD) == 0) {
        printf("\nValid password\n");
    } else {
        printf("\nInvalid password\n");
    }
}

Ответы [ 3 ]

0 голосов
/ 14 февраля 2019

Проблема в том, что у вас \n сохранено во входном буфере, поэтому pass123 и pass123\n не будут совпадать.

Таким образом, null завершит ввод, если вы найдете \n, как показано ниже.

  if (password[i] == '\n')
  {
     password[i] = '\0';
     break;
  }
0 голосов
/ 14 февраля 2019

Вы заявили, что strcmp() означает, что две строки равны, когда вы знаете, что они не ...

Проблемы с \n, упомянутые в других ответах, неЕсли вы действительно видите, как strcmp() возвращает неправильное указание, возникает вопрос, почему?

В C string определяется как символьный массив с символом null.Поэтому, если, например, если у вас есть следующее:

char password[MAXPASSWORD] = {0};//where MAXPASSWORD == 12

|p|a|s|s|1|2|3|\0|\0|\0|\0|\0| // `PASSWORD ` - legal string
|s|o|m|e|p|a|s|s|1|2|3|4|\n|  // 'password' 

даже после замены символа \n, этот массив слишком длинный на один символ:

|s|o|m|e|p|a|s|s|1|2|3|4|\0|  // 'password' - too long by 1 character
                        ^     // end of legal definition of `password`

Если password массив содержит слишком много символов, даже в этом случае после замены последнего char \n на NULL в расположении за пределами допустимого определения строки код становится предметом неопределенное поведение .

Строковые функции предназначены для работы исключительно с strings.Когда представлен ненулевой символьный массив, в данном случае strcmp(), поскольку он ищет терминатор nul, чтобы узнать, где находится конец строки, нельзя ожидать, что он будет вести себя с предсказуемостью.(В этом случае расположение символа nul может стать причиной неопределенного поведения.)

Чтобы этого не произошло, даже если пользователь смог ввести слишком много символов в password, всегдазавершается с помощью следующего выражения:

password[MAXPASSWORD-1] = 0;  //for a properly initialized array, (as your code indicates)
                              //this guarantees termination occurs 
                              //within legal memory area of defined variable. 

При этом не будет неопределенного поведения, и если строки различаются, strcmp() будет указывать на это.

0 голосов
/ 14 февраля 2019

Вы забыли заменить \n на NUL

...
for(int i=0; i<MAXPASSWORD; i++)
{
  password[i] = getch();
  if (password[i] == '\n')
  {
    password[i] = 0;   // <<<< add this line
    break;
  }
  printf("*");
}
...

Существует еще одна проблема: подумайте, что произойдет, если пользователь введет более 11 символов, прежде чем нажать Введите .Я позволю вам узнать себя в качестве упражнения.

...