Сравнение строк в C - strcmp - PullRequest
0 голосов
/ 22 июня 2009

У меня проблемы со сравнением строк в C (с которыми я довольно новичок). У меня есть сокет на этом серверном приложении, ожидающем приема данных от клиента. В этой конкретной части моей программы я хочу иметь возможность выполнять запрос MySQL на основе данных, полученных от клиента. Я хочу знать, когда полученные данные имеют значение «newuser», чтобы начать простую процедуру регистрации. Strcmp возвращает положительное значение 1, где я считаю, что я должен получить 0, потому что значения должны быть равны.

Исходный код:

//setup socket
//loop and select structure to handle multiple connections

if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
// got error or connection closed by client
    if (nbytes == 0) {
        // connection closed
        printf("selectserver: socket %d hung up\n", i);
    } else {
        perror("recv");
    }
    close(i); // bye!
    FD_CLR(i, &master); // remove from master set
} else {

    char check[] = "newuser";
    char fromUser[sizeof check];

    strncpy(fromUser,buf, sizeof check);
    printf("length of fromUser: %d\n", sizeof fromUser);
    printf("length of check: %d\n", sizeof check);
    printf("message from user: %s\n", fromUser);
    printf("check = %s \n", check);
    int diff = strcmp(fromUser, check);
    printf("compare fromUser to check: %d\n", diff);
    if ( strcmp(fromUser, check) == 0) {
        printf("aha! new user");
    }

Выход:

length of fromUser: 8
length of check: 8
newuser from user: newuser
check = newuser 
compare fromUser to check:

У меня такое ощущение, что я неправильно обрабатываю входящий буфер или ошибочно копирую буфер.

Ответы [ 7 ]

6 голосов
/ 22 июня 2009

strncpy копий максимум - в данном случае - sizeof проверочных байтов. Если нулевой байт не находится в этом диапазоне, он не копируется. Вы, вероятно, получаете слово «newuser» как часть более длинного предложения, например, «newuser бла-бла», поэтому вам нужно указать это значение самостоятельно

strncpy(fromUser, buf, sizeof check);
fromUser[sizeof check - 1] = '\0';

или используйте strlcpy, если доступно.

3 голосов
/ 22 июня 2009

Вот пример кода, который вы дали в своем вопросе (с удаленным кодом отладки):

//setup socket
//loop and select structure to handle multiple connections

if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
    [... exception handling here ...]
} else {
    char check[] = "newuser";
    char fromUser[sizeof check];

    strncpy(fromUser,buf, sizeof check);
    if ( strcmp(fromUser, check) == 0) {
        printf("aha! new user");
    }

Этот код неверен; вы потенциально копируете больше байтов из buf [], чем было получено. Это приведет к тому, что вы будете сравнивать с мусором (который может случайно совпадать с вашей строкой "newuser"). И, как говорили другие люди, у вас есть вторая ошибка из-за того, что NUL не завершает одну из ваших строк.

В этом случае я бы использовал memcmp (). Это похоже на strcmp (), но оно принимает параметр длины, а не ожидает строки, заканчивающиеся NUL.

//setup socket
//loop and select structure to handle multiple connections

if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
    [... exception handling here ...]
} else {
    static const char check[] = "newuser";
    const size_t check_len = sizeof(check) - 1; // exclude the NUL terminator
    if (nbytes >= check_len && memcmp(buf, check, check_len) == 0) {
        printf("aha! new user");
    }

P.S. Не имеет прямого отношения, но recv () может завершиться ошибкой, вернув -1 с errno==EINTR. Это не ошибка, вам просто нужно повторить попытку. Обычно это случается так редко, что люди уходят без проверки, пока они не интегрируются с другим кодом, который использует сигналы, и внезапно их код случайно выходит из строя.

В приложении на основе select() вы также должны установить неблокируемые сокеты, а затем проверить наличие errno==EAGAIN и вернуться к select() в этом случае. Это может произойти, если стек TCP / IP получает поврежденный пакет - он думает, что у него есть пакет, поэтому select() сообщит вам, что он доступен для чтения, только при попытке прочитать его стек TCP / IP выполняет вычисление контрольной суммы и выполняет он должен выбросить данные. Затем он будет либо блокировать (плохо), либо, если он установлен как неблокирующий, он вернет -1 с errno==EAGAIN.

2 голосов
/ 22 июня 2009

Вы пропустили символ '\ 0' в конце fromUser:

...
strncpy(fromUser,buf, sizeof check);
fromUser[strlen(check)] = '\0';
2 голосов
/ 22 июня 2009

Я считаю, что проблема здесь (одна из проблем здесь) в том, что fromUser (из-за способа его создания) не завершается нулем.

1 голос
/ 22 июня 2009

Требуются два изменения:

char fromUser[sizeof check] = {'\0'}; //Make all null characters
strncpy(fromUser,buf, sizeof check -1); //Last character is for null character.
0 голосов
/ 22 июня 2009

Этот код выключен:

if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) 
{
 // your stuff
} 
else {
const char *pCheck = "newuser";
char *fromUser = new char[nbytes];
strncpy(fromUser, buff, nbytes);
fromUser[nbytes] = '\0';
if(strcmp(fromUser,check)==0)
 // blah

delete [] fromUser;
}
0 голосов
/ 22 июня 2009

Заменить на:

char check[] = "newuser\0";
...