2010-11-04 32 views
3

J'utilise Linux et il y a une fonction personnalisée qui retourne un ASCII int de type clé en cours comme getch(). Lorsque vous essayez de vous y habituer et comment stocker le mot de passe que je suis entré dans une question, mon code est le suivant:Strcat jette une erreur de segmentation sur une simple entrée de mot de passe ressemblant à un getch

int main() { 
    int c; 
    char pass[20] = ""; 

    printf("Enter password: "); 
    while(c != (int)'\n') { 
     c = mygetch(); 
     strcat(pass, (char)c); 
     printf("*"); 
    } 

    printf("\nPass: %s\n", pass); 

    return 0; 
} 

Malheureusement je reçois l'avertissement de GCC:

pass.c:26: warning: passing argument 2 of ‘strcat’ makes pointer from integer without a cast 
/usr/include/string.h:136: note: expected ‘const char * __restrict__’ but argument is of type ‘char’ 

J'ai essayé d'utiliser pointeurs au lieu d'un tableau de caractères pour passer, mais la seconde, je tape une lettre segfaults. La fonction fonctionne seule mais pas dans la boucle, au moins contrairement à getch() sur un système Windows.

Que voyez-vous qui ne va pas avec mon exemple? J'apprécie apprendre ceci.

EDIT: Merci aux réponses que je suis venu avec le code suivant: stupide

int c; 
int i = 0; 
char pass[PASS_SIZE] = ""; 

printf("Enter password: "); 
while(c != LINEFEED && strlen(pass) != (PASS_SIZE - 1)) { 
    c = mygetch(); 
    if(c == BACKSPACE) { 
     //ensure cannot backspace past prompt 
     if(i != 0) { 
      //simulate backspace by replacing with space 
      printf("\b \b"); 
      //get rid of last character 
      pass[i-1] = 0; i--; 
     } 
    } else { 
     //passed a character 
     pass[i] = (char)c; i++; 
     printf("*"); 
    } 
} 
pass[i] = '\0'; 
printf("\nPass: %s\n", pass); 
+0

+1 pour "J'apprécie apprendre ceci." –

Répondre

3

Le problème est que strcat attend un char * comme second argument (il Assemble deux cordes). Vous n'avez pas deux chaînes, vous avez une chaîne et une char.

Si vous voulez ajouter c à la fin de pass, juste garder un int i qui stocke la taille actuelle de pass puis faire quelque chose comme

pass[i] = (char) c.

Veillez à terminer parlorsque vous avez terminé (en définissant la dernière position sur 0).

+0

Parfait, semble un peu bête mais ça marche. J'ai juste besoin d'ajouter ma propre vérification des tailles et ça devrait être sympa. – John

1

Un seul caractère n'est pas la même chose qu'une chaîne contenant un seul caractère. En d'autres termes, «a» et «a» sont des choses très différentes.

Une chaîne, en C, est un tableau de caractères null-terminé. Votre "passe" est un tableau de 20 caractères - un bloc de mémoire contenant de l'espace pour 20 caractères.

La fonction mygetch() renvoie un caractère.

Ce que vous devez faire est d'insérer c dans l'un des espaces. Au lieu de "strcat (pass, c)", vous voulez faire "pass [i] = c", où je commence à zéro, et augmente de un pour chaque fois que vous appelez mygetch().

Ensuite, vous devez faire une passe [i] = '\ 0', lorsque la boucle est terminée, avec i égal au nombre de fois que vous avez appelé mygetch(), pour ajouter le terminateur nul.

Vous êtes un autre problème, c'est que vous n'avez pas défini de valeur pour c, la première fois que vous vérifiez pour voir si c'est \ n '. Vous voulez appeler mygetch() avant de faire la comparaison:

int i = 0; 
for (;;) 
{ 
    c = mygetch(); 
    if (c == '\n') 
     break; 

    c = mygetch(); 
    pass[i++] = c; 
} 
pass[i] = '\0'; 
+0

J'avais déclaré mygetch retourné un nombre entier au début. Aussi, pourquoi utiliser une boucle for vide si le compilateur l'optimise à la même chose que les boucles while while/do-while? Cela semble désordonné IMO. – John

+0

Pensez-vous que vous ne pouvez pas assigner un int à un char, sans le lancer? Les conversions implicites de C géreront cela pour vous. Quant à utiliser "for (;;)" au lieu de "while (1)", ils sont équivalents. Le premier a été idiomatique depuis les premiers jours de C, mais vous pouvez utiliser celui avec lequel vous vous sentez plus à l'aise. Le point important est de s'assurer que vous initialisez la variable avant de la tester. –

0

Au-delà de la question correctement diagnostiqué avec strcat() en prenant deux cordes - pourquoi avez-vous ignorer les avertissements du compilateur, ou s'il n'y avait pas d'avertissement, pourquoi n'avez-vous pas d'avertissement activé?Comme je le disais, au-delà de ce problème, vous devez également considérer ce qui se passe si vous obtenez EOF, et vous devez également vous soucier de la valeur initiale de 'c' (qui pourrait accidentellement être '\ n' bien qu'elle ne soit probablement pas 't).

qui mène à code comme ceci:

int c; 
char pass[20] = ""; 
char *end = pass + sizeof(pass) - 1; 
char *dst = pass; 

while ((c = getchar()) != EOF && c != '\n' && dst < end) 
    *dst++ = c; 
*dst = '\0'; // Ensure null termination 

Je suis passé de « mygetch() » à 'getchar() - principalement parce que ce que je dis applique à cela et pourrait ne pas appliquer à votre « mygetch ()' fonction; nous n'avons pas de spécification de ce que fait cette fonction sur EOF.

Sinon, si vous devez utiliser strcat(), vous devez toujours garder une trace sur la longueur de la chaîne, mais vous pouvez faire:

char c[2] = ""; 
char pass[20] = ""; 
char *end = pass + sizeof(pass) - 1; 
char *dst = pass; 

while (c[0] != '\n' && dst < end) 
{ 
    c[0] = mygetch(); 
    strcat(dst, c); 
    dst++; 
} 

pas aussi élégant que tout ce qui - en utilisant strcat() dans le contexte est exagéré. Vous pourriez, je suppose, faire un simple comptage et utiliser à plusieurs reprises strcat(pass, c), mais cela a un comportement quadratique car strcat() doit sauter des caractères 0, 1, 2, 3, ... sur les itérations suivantes. En revanche, la solution où dst pointe vers le NUL à la fin de la chaîne signifie que strcat() n'a rien à sauter. Avec un ajout de taille fixe de 1 caractère, vous êtes probablement mieux avec la première boucle.

+0

mygetch utilise getchar, la seule chose qu'il fait est de désactiver la mise en mémoire tampon sous Linux afin qu'il accepte les caractères par caractère (comme la fonction getch de conio). J'aime vraiment l'aspect de ce bloc de code, mon code de travail utilise i/i ++ sur le tableau char pour l'assigner et l'itérer. Merci pour la perspicacité. – John