strcmp() считает, что строки не равны... но так ли это?

По неизвестной причине результат запуска моей программы на C довольно неожиданный. Я думаю, что это должна быть какая-то ошибка новичка, однако я не могу понять, где она.

#include <stdio.h>
#include <string.h>
int main()
{
char string1[50];
char string2[50];
int compare;

puts("Enter two strings: ");
fgets(string1, strlen(string1)+1, stdin);
fgets(string2, strlen(string2)+1, stdin);

compare=strcmp(string1, string2); /* usage of extra variable makes the code more readable but wastes more memory */

printf("%d: ",compare);

if (compare<0) puts("First string is lesser");
else if (compare>0) puts ("First string is bigger");
     else puts("Strings are equal");


return 0;
  }

И на тестировании:

Enter two strings: 
heheisntthisalongstring
heheisntthisalongstring
1: First string is bigger


------------------
(program exited with code: 0)
Press return to continue

Разве эти строки не должны быть равны?


person hardpenguin    schedule 24.08.2012    source источник
comment
Ваши вызовы fgets() не работают, длина, которую вы передаете, неверна. Неинициализированный char[] имеет случайную длину. Попрактикуйтесь в использовании отладчика, чтобы увидеть такие проблемы.   -  person Hans Passant    schedule 24.08.2012
comment
Большое спасибо. Я буду учиться использовать отладчик сегодня.   -  person hardpenguin    schedule 24.08.2012
comment
Только дополнительный вопрос. После инициализации массивов в 0, если я использую strlen(), программа завершится, не дав мне возможности ввести строки. Изменение strlen() на sizeof решает проблему, но почему происходит выше?   -  person hardpenguin    schedule 24.08.2012
comment
@hardpenguin fgets(s, num, stream) читает символы до тех пор, пока не будет прочитано (num-1) символов или не будет достигнута новая строка или конец файла, в зависимости от того, что наступит раньше. При инициализации ваших строк со всеми 0 strlen возвращает 0, а fgets не имеет символов для чтения.   -  person halex    schedule 24.08.2012


Ответы (4)


fgets(string1, strlen(string1)+1, stdin);
fgets(string2, strlen(string2)+1, stdin);

Это неправильно. string1 и string2 не инициализируются, а strlen просто подсчитывает количество байтов, пока не достигнет \0. В этом случае strlen может вернуть любое (случайное неотрицательное) число.

Используйте sizeof вместо strlen здесь.

person Kiril Kirov    schedule 24.08.2012
comment
Спасибо большое! Я буду иметь это в виду. - person hardpenguin; 24.08.2012

Здесь

 char string1[50]; 
 char string2[50]; 

вы не инициализируете их, поэтому ваши первоначальные вызовы strlen ненадежны, поскольку они ищут первый нулевой символ, который они находят после начала массива. Это может быть где угодно, и результаты вызова могут быть или не быть истинным отражением размера - вы просто не можете полагаться на результаты.

person mathematician1975    schedule 24.08.2012

string1 не установлен в памяти на 0, поэтому значение strlen(string1) не даст ожидаемого значения (50). strlen будет считать символ, пока он не достигнет \0. Таким образом, это также может привести к сбою (неопределенное поведение).

Лучше memset как string1, так и string2, как показано ниже.

char string1[50] = {0}; 
char string2[50] = {0};

а также используйте оператор sizeof, чтобы получить значение 50.

fgets(string1, sizeof(string1), stdin); 
fgets(string2, sizeof(string2), stdin);

или же сразу перейти к scanf

scanf("%s", string1);
scanf("%s", string2);
person rashok    schedule 24.08.2012
comment
Memset Zero в массиве не приведет к ожидаемому значению 50, когда для него вызывается strlen - person mathematician1975; 24.08.2012
comment
strlen(string1) даст ноль, если мы передаем memsetted string1. Вот что я предложил использовать sizeof вместо strlen. Лучше всего перед использованием установить memset в 0 для всего буфера. - person rashok; 24.08.2012
comment
установка всего буфера очень плохо повлияет на производительность. - person Abhineet; 24.08.2012
comment
@raja ashok Я согласен, просто ваш ответ предполагает, что установка памяти на ноль даст значение 50. - person mathematician1975; 24.08.2012
comment
Большое спасибо, не могли бы вы также ответить на этот вопрос: Просто дополнительный вопрос. После инициализации массивов в 0, если я использую strlen(), программа завершится, не дав мне возможности ввести строки. Изменение strlen() на sizeof решает проблему, но почему происходит выше? - person hardpenguin; 24.08.2012
comment
@hardpenguin, sizeof() основан на компиляторе. Компилятор вычисляет размер в этот момент и превращает его в константу. strlen() вычисляет длину строки от того места, где находится ваш указатель, до следующего нулевого значения. Вот почему в этом случае strlen не работает (потому что вы устанавливаете все в ноль). - person Youssef G.; 24.08.2012
comment
@ЮссефГ. Большое спасибо. - person hardpenguin; 24.08.2012

Здесь взгляните на this-strlen

Хотя код, который вы используете, не очень хорош, вы все равно можете получить ожидаемый ответ, используя strncmp, указав 3-му параметру strlen общей строковой переменной. Просто для удовольствия. Всегда инициализируйте свои переменные, иначе они могут привести к сбою вашего приложения. Вы можете увидеть примеры здесь — strncmp

person Abhineet    schedule 24.08.2012
comment
Никакая инициализация и использование strncmp с одной и той же переменной strlen не может привести к сбою вашего приложения. Просто чтобы было ясно, я не одобряю этот код :-) - person Abhineet; 24.08.2012