2009-06-22 7 views
0

Je n'arrive pas à comparer les chaînes en C (avec lesquelles je suis relativement nouveau). J'ai une socket sur cette application serveur en attente d'accepter les données d'un client. Dans cette partie particulière de mon programme, je veux être en mesure d'exécuter une requête MySQL basée sur les données reçues du client. Je veux être capable de savoir quand les données reçues ont la valeur de "newuser" pour lancer une procédure d'enregistrement simple. Strcmp renvoie une valeur 1 positive où je crois que je devrais obtenir un 0 parce que les valeurs devraient être égales.Comparaison de chaînes dans C - strcmp

Code Source:

//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"); 
    } 

Sortie:

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

J'ai un sentiment que je ne suis pas manipuler la mémoire tampon entrant copie correctement ou de manière erronée le tampon.

+1

Vous ne consignez pas la valeur fromUser, seulement sa longueur. – Tom

Répondre

6

strncpy exemplaires au plus - dans ce cas - sizeof octets de contrôle. Si l'octet nul n'est pas dans cette plage, il n'est pas copié. Vous êtes probablement trouvé le mot « newuser » dans le cadre d'une peine plus longue, comme « newuser bla bla » de sorte que vous devez placer que vous NUL

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

ou utiliser strlcpy, le cas échéant.

+0

+1 pour mentionner strlcpy – Tom

2

Je crois que le problème ici (l'un des problèmes ici) est que fromUser (en raison de la façon dont il est créé) n'est pas terminé par null.

2

Vous manquez '\ 0' à la fin de fromuser:

... 
strncpy(fromUser,buf, sizeof check); 
fromUser[strlen(check)] = '\0'; 
+0

Ce ne serait pas sizeof (vérifier) ​​- 1? – DeadHead

-1

Remplacer par:

char check[] = "newuser\0"; 
+1

Les guillemets doubles produisent une chaîne terminée par zéro, n'est-ce pas? – cube

+1

Les littéraux "" sont implicitement terminés par NUL. Ajouter un autre NUL explicitement n'aide pas ici. – laalto

1

Deux changements nécessaires:

char fromUser[sizeof check] = {'\0'}; //Make all null characters 
strncpy(fromUser,buf, sizeof check -1); //Last character is for null character. 
0

Ce code semble hors:

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; 
} 
3

Voici l'exemple de code que vous avez donné à votre question (avec le code de débogage enlevé):

//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"); 
    } 

Ce code est erroné; vous copiez potentiellement plus d'octets de buf [] que ce qui a été reçu. Cela vous amènera à comparer avec la poubelle (qui pourrait par hasard correspondre à votre chaîne "newuser"). Et comme d'autres personnes l'ont dit, vous avez un deuxième bug dû au fait que NUL ne termine pas l'une de vos chaînes.

Dans ce cas, j'utiliserais memcmp(). C'est comme strcmp() mais il faut un paramètre de longueur plutôt que d'attendre des chaînes terminées par 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. Non directement lié, mais recv() peut échouer en renvoyant -1 avec errno==EINTR. Ce n'est pas une condition d'erreur, il vous suffit d'essayer à nouveau. Normalement, cela arrive si rarement que les gens s'en tirent sans le vérifier, jusqu'à ce qu'ils intègrent un autre code qui utilise des signaux et soudainement leur code échoue de manière aléatoire.

Dans une select() application à base, vous devez également être prises à la définition de vos non-blocage, puis vérifier les errno==EAGAIN, et revenir à la select() dans ce cas. Cela peut arriver si la pile TCP/IP reçoit un paquet corrompu - elle pense qu'il a un paquet, donc select() vous dira que c'est lisible, c'est seulement quand vous essayez de le lire que la pile TCP/IP fait le calcul de checksum et se rend compte jeter les données. Il bloquera alors (mauvais), ou s'il est défini sur non bloquant, il renverra -1 avec errno==EAGAIN.

Questions connexes