2016-07-10 3 views
2

J'ai une fonction très simple de convertir une chaîne 3 char représentant une chaîne de bits à un nombre décimal:Déconcerté par strcmp

int bin3_to_dec(char *bin) { 
    int result; 

    result=0; 
    printf("string: %s\n", bin); 
    printf("c0: %c\n", bin[0]); 
    printf("c1: %c\n", bin[1]); 
    printf("c2: %c\n", bin[2]); 

    if ((strcmp(&bin[0], "1") == 0)) 
    result += 4; 
    if ((strcmp(&bin[1], "1") == 0)) 
    result += 2; 
    if ((strcmp(&bin[2], "1") == 0)) 
    result += 1; 
    printf("result: %d\n", result); 
    return result; 
} 

Quand je lance le programme et les aliments pour cette fonction, la chaîne 111 il faut calculer 7 . au contraire, il émet ceci:

string: 111 
c0: 1 
c1: 1 
c2: 1 
result: 1 

Pourquoi est-il pas calculer la valeur correcte? Pourquoi seule la troisième condition passe-t-elle avec succès?

+0

if (bin [0] == '1') –

+1

bin = "111", puis & bin [0] points " 111 "et –

+0

bin = & bin [0] = bin + 0 =" 111 "dans ce cas –

Répondre

5

Votre chaîne bin égale "111" se compose vraiment de quatre caractères - c'est-à-dire '1', '1', '1', '\ 0' où le 4ème caractère a la valeur zéro qui termine (ie termine) le chaîne.

Alors &bin[0] est la chaîne "111"

et &bin[1] est la chaîne "11"

et &bin[2] est la chaîne "1"

Alors, que votre code est en train de faire est le même que:

if ((strcmp("111", "1") == 0)) 
    result += 4; 
    if ((strcmp("11", "1") == 0)) 
    result += 2; 
    if ((strcmp("1", "1") == 0)) 
    result += 1; 

Seul le dernier com pare les résultats sont vrais, donc result devient 1

2

& bin [0] est en réalité un pointeur sur un tableau de caractères commençant par 0th index qui est 111. Donc, votre première comparaison échoue. De même pour la seconde. Mais dans votre troisième comparaison, & bin [2] est un pointeur vers un tableau de caractères commençant à partir du 2ème index qui est 1 et donc ajoute 1 au résultat. Donc, pour que votre code fonctionne:

vous pouvez vérifier if(bin[0] == '1') // Ici vous comparez le caractère à bin [0] et il est égal à 1 et donc ici la condition est remplie.

+0

Aha ... pourquoi calcule-t-elle 1 alors même si ce n'est pas 0? – ErwinM

+0

Il passe l'adresse du premier caractère ('& bin [0]'), donc en effet c'est une chaîne. –

+0

@CodyGray ah je vois .. thx – ErwinM

1
if (bin[0] == '1') result += 4; 
if (bin[1] == '1') result += 2; 
if (bin[2] == '1') result += 1; 

s'il vous plaît noter que Ben & [0] est le même que bin

bin [0] est le premier élément

& bin [0] est un pointeur vers le premier élément comme bin

+2

Cette réponse serait meilleure si elle expliquait pourquoi le code original était erroné et/ou ce que fait votre code pour résoudre le problème. –

+0

j'ai écrit que les commentaires sous la question –

+1

Ne répondez pas dans les commentaires! – Olaf

1

C ne détecte pas la fin d'une chaîne jusqu'à ce qu'elle rencontre une valeur nulle (ie \ 0). Lorsque vous passez "111" dans votre fonction, vous passez réellement un pointeur sur un bloc de mémoire qui ressemble à ceci: "111 \ 0". Ainsi, lorsque vous passez l'adresse de bin [0] dans strcmp(), strcmp fonctionne sur la chaîne complète "111". Lorsque vous passez l'adresse de bin [1] dans strcmp(), strcmp fonctionne sur la chaîne "11". Ce n'est que lorsque vous passez l'adresse de bin [2] dans strcmp() que vous obtenez le comportement que vous attendiez, car dans ce cas, le prochain caractère en mémoire est null.

1

Avez-vous essayé d'imprimer &bin[1] (par exemple) sous forme de chaîne, au lieu des caractères individuels? Parce que c'est comme ça que strcmp() va les voir.

En vous faites cela, strcmp(&bin[0], "1") est clairement toujours non nulle, parce que &bin[0] est la chaîne d'entrée pleine et (dans notre exemple) "111" est pas du tout comme "1". Les chaînes s'exécutent jusqu'au caractère null-terminator.

Vous pouvez utiliser des comparaisons de caractères directs (bin[0] == '1'), copier le caractère à une chaîne à zéro terminal propre, ou (destructivement) travaillent de droite à gauche et insérer le caractère nul ('\0') après le caractère qui vous intéresse . Mais vous ne pouvez pas comparer le milieu d'une chaîne comme un seul caractère.

+1

Où voyez-vous 'strlen' dans le code ?? – Olaf

+0

@Olaf, bonne prise - faute de frappe. –

+1

Ceci est un endroit où 'strncmp()' pourrait être utilisé pour comparer une sous-chaîne de longueur fixe au milieu d'une chaîne plus grande, mais cela semble être trop comparé à la simple comparaison de caractères simples lorsque la sous-chaîne est de longueur 1 , comme il serait ici pour cette question. (Mais, en général, 'strncmp (& src [off1], & dst [off2], len)' peut comparer deux sous-chaînes de caractères jusqu'à 'len' tout à fait heureusement.) –

-1

Comme mentionné par d'autres, vous confondez ces chaînes. Les trois d'entre eux sont des chaînes, cependant, chaîne en Java est un tableau de caractères. Donc quand vous voulez dire la chaîne "1" en utilisant & bin [0], vous comparez réellement "111". Pourquoi? Le pointeur vers un tableau de caractères crée une chaîne avec les caractères de ce tableau commençant là où votre pointeur apparaît et continue jusqu'à la fin. Donc quand vous pointez sur la première lettre, vous obtenez "111", quand vous pointez sur la deuxième lettre, vous obtenez "11" et quand vous pointez sur le dernier caractère, vous obtenez "1", c'est pourquoi votre somme est 1 Vous pouvez essayer de passer comme argument la chaîne "1111", vous pouvez voir que votre résultat est 0 au lieu de 1.

-1

Votre code semble quelque peu confondu autour d'un appel de fonction de strcmp(), ce qui n'est pas nécessaire et serait systématiquement renvoie une valeur non nulle pour toute comparaison entre la chaîne littérale "1" et toute "sous-chaîne" pointée dans votre code (&bin[0], &bin[1]), à l'exception de la chaîne de caractères imprimable &bin[2], si également "1". Faisons un tour.

Comme vous l'avez correctement écrit dans votre prototype de fonction , le pointeur sur le premier élément du tableau de caractères est passé par valeur à votre fonction appelée et copié comme argument. C'est le "mécanisme" pour la partie de la mémoire peuplée par le tableau pointé, pour devenir visible par la fonction appelée, si sa "limite supérieure" est connue.
Il existe deux moyens d'avoir sa connue borne supérieure:

  1. Passe la taille du tableau char comme argument supplémentaire à la fonction, ou
  2. Null de terminaison de réseau char dans le appelant la fonction, de sorte que le appelé la fonction peut interpréter comme une chaîne, qui est votre choix. La fonction appelée peut utiliser strlen() pour déterminer la longueur de la chaîne (taille) ou la parcourir, incrémenter le compteur jusqu'à ce qu'un caractère nul soit atteint et lire la taille du compteur.

Si la fonction d'appel reçoit déjà le tableau comme une chaîne à zéro terminal de '0' et '1' caractères, le second semble plus pratique.

Permettant jusqu'à autant de caractères comme le permet la capacité de stockage du type de données de retour de la fonction appelée (dans ce cas int) précise le problème et simplifie le code. La fonction d'appel doit empêcher le débordement.

La fonction appelée doit seulement comparer la valeur ASCII de chaque membre du groupe avec'1' et convertir en cas d'égalité. Pour cette strcmp n'est pas nécessaire.

S'il vous plaît voir les commentaires dans ce code de démonstration, en fonction de votre message:

#include <stdio.h> 
#include <string.h> 
#define BPB 8 //bits per byte 

int bin_to_dec(char *bin)   //called function 
{ 
    int result=0; 
    int l = (int)strlen(bin); 
    for (int i = 0; i < l; i++){ 
     printf("c%d: %c\n", i, bin[i]); 
     if(bin[i] == '1')    //compare value of the i-th element 
      result += 1<<(l - i - 1); //convert to power-of-two and add to the result 
     } 
    return result; 
} 

int main(int argc, char *argv[])  //calling function 
{ 
    size_t siz = BPB*sizeof (int); //size for each char to represent one bit 
    char s[siz + 1];    //characters, each representing one bit + terminating '\0' 

    if((argc < 2)||(argc > 2))  //fail-safe check for correct count of arguments 
     return 1; 
    size_t len = strlen(argv[1]) ; //get length of the input string 
    if (len > siz)    //check against too long input which would cause overflow 
     return 2; 
    strncpy(s, argv[1], len); 
    s[len] = '\0';     //appending the terminating null-character 
    for(int i = 0; i < (int)len; i++) 
     if((s[i] < '0')||(s[i] > '1')) //fool-proof check against 'off-limit' input 
      return 3; 

    printf("decimal: %d\n", bin_to_dec(s)); 
    return 0; 
} 
+0

Le DVer s'il vous plaît être aimable pour indiquer la raison de DVing, donc la réponse peut être améliorée? Merci. – user3078414