Question

J'utilise Linux. Je suis en train d'écrire un programme en c qui imprimera une chaîne en arrière. Voici mon code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (){
    char string[100];
    printf ("Enter string:\n");
    gets (string);
    int length = strlen (string)-1;
    for (length = length; length>=0; length--){
        puts (string[length]);
    }
}

Et voici l'erreur:

a.c:10: warning: passing argument 1 of ‘puts’ makes pointer from integer without a cast
/usr/include/stdio.h:668: note: expected ‘const char *’ but argument is of type ‘char’
/tmp/cc5rpeG7.o: In function `main':
a.c:(.text+0x29): warning: the `gets' function is dangerous and should not be used.

Que dois-je faire?

Était-ce utile?

La solution

Tout d'abord:

NE JAMAIS jamais jamais jamais utiliser gets(); il introduire un point de défaillance dans votre code . Il n'y a aucun moyen de dire gets() la taille de la mémoire tampon cible est, donc si vous passez un tampon dimensionné pour contenir 10 caractères et il y a 100 caractères dans le flux d'entrée, gets() se fera un plaisir de stocker ces 90 caractères supplémentaires dans la mémoire au-delà de la fin de votre tampon , potentiellement quelque chose d'important démolir. les dépassements de tampon sont un malware facile exploiter; le ver Morris exploité spécifiquement un appel gets() dans sendmail.

Utilisez fgets() à la place; il vous permet de spécifier le nombre maximum de caractères à lire à partir du flux d'entrée. Cependant, contrairement à gets(), fgets() sauvera le caractère de nouvelle ligne de terminaison au tampon s'il y a de la place pour cela, vous devez tenir compte pour cela:

char string[100]; 
char *newline;
printf("Enter a string: ");
fflush(stdout);
fgets(string, sizeof string, stdin);
newline = strchr(buffer, '\n');      // search for the newline character
if (newline)                         // if it's present
  *newline = 0;                      // set it to zero

Maintenant, qui est de la façon ...

Votre erreur provient du fait que puts() attend un argument de type char *, mais vous passez un argument de type char, d'où le « entier en pointeur sans cast » message (char est un type intégral). Pour écrire un seul caractère à stdout, l'utilisation putchar() ou fputc().

Autres conseils

Oublier que la fonction existe gets() - il est mortel. Utilisez fgets() à la place (mais note qu'il ne supprime pas la nouvelle ligne à la fin de la ligne).

Vous voulez mettre un seul caractère à la fois: l'utilisation putchar() écrire à stdout. Ne pas oublier d'ajouter une nouvelle ligne à la sortie après la boucle.

En outre, for (length = length; length >= 0; length--) est pas idiomatique C. Utilisation d'une:

  • for ( ; length >= 0; length--)
  • for (length = strlen(string) - 1; length >= 0; length--)
  • for (int length = strlen(string) - 1; length >= 0; length--)

La dernière alternative utilise une fonctionnalité ajoutée à C99 (qui était disponible en C ++ bien avant).

En outre, nous pourrions débattre si length est le nom approprié pour la variable. Il serait mieux rebaptisé i ou pos ou quelque chose parce similaire, bien qu'il soit initialisé à la longueur de l'entrée, il est en fait utilisé comme un indice de tableau, et non comme la longueur de quoi que ce soit.

Subjective : Ne pas mettre un espace entre le nom d'une fonction et sa liste de paramètres. Les pères fondateurs de C ne fait pas ça -. Vous non


Pourquoi est-gets () mortel?

Le premier ver Internet - le ver de Morris de 1988 - exploité le programme fingerd qui a utilisé gets() au lieu de fgets(). Depuis lors, de nombreux programmes ont été utilisés parce qu'ils écrasements gets() et non fgets() ou une autre alternative.

Le problème fondamental est que gets() ne sait pas combien d'espace est disponible pour stocker les données, il se lit comme suit. Cela conduit à « débordements de tampon », un terme qui peut être recherché dans votre moteur de recherche préféré qui renverra un très grand nombre d'entrées.

Si quelqu'un tape 150 caractères d'entrée à l'exemple de programme, puis gets() va stocker 150 caractères dans le tableau qui a une longueur 100. Cela n'a jamais conduit au bonheur - il est habituellement conduit à une décharge de base, mais avec des entrées soigneusement choisis - souvent généré par un script Perl ou Python - vous pouvez probablement obtenir le programme pour exécuter un autre code arbitraire. Ce qui importe vraiment si le programme sera jamais exécuté par un utilisateur avec des « privilèges élevés ».

Par ailleurs, gets() doit être retiré probablement de la bibliothèque standard C dans la prochaine version (C1x - voir n1494 GT14 ). Il ne disparaîtra pas de bibliothèques réelles C pendant longtemps encore, mais il doit être remplacé par cette mise en œuvre (ou similaire) (20 ans?):

#undef NDEBUG
#include <assert.h>
char *gets(char *buffer)
{
    assert("Probability of using gets() safely" == 0);
}

Un autre détail mineur, discuté en partie dans les commentaires à la question principale.

Le code affiché est clairement C99; la déclaration de façon length partiel par la fonction est invalide dans C89. Compte tenu de cela, il est « OK » pour la fonction main() ne pas revenir explicitement une valeur, car la norme C99 emboîte le pas du C ++ standard et vous permet d'omettre le retour de main() et l'effet est le même que return(0); ou return 0; à la fin.

En tant que tel, le programme de cette question ne peut être strictement reprocher de ne pas avoir un return à la fin. Cependant, je considère que comme l'un des plus particulier la normalisation des décisions, et préférerions de beaucoup si les normes avaient laissé cette disposition sur - ou quelque chose fait plus radicaux comme permettant l'void main() omniprésente mais erronée observant que lorsque le contrôle revient de cela, le résultat est qu'un état de réussite est retourné à l'environnement. Il ne se bat pas la peine d'obtenir cet aspect de la norme changé - malheureusement - mais comme une décision de style personnel, je ne profite pas de la licence accordée à omettez le return finale de main(). Si le code doit travailler avec les compilateurs C89, il devrait avoir le return 0; explicite à la fin (mais la déclaration de length doit être fixé aussi).

Vous pouvez également utiliser la récursivité pour le faire. Je pense qu'il semble plus agréable alors lorsque vous utilisez une boucle.

Il suffit d'appeler la méthode avec votre chaîne, et avant d'imprimer le caractère dans la méthode, appelez de nouveau la méthode avec la même chaîne, moins le premier caractère.

Cette imprimera vous chaîne dans l'ordre inverse.

Vous devez utiliser putchar au lieu de puts

cette boucle:

for (length = length; length>=0; length--){
    puts (string[length]);
}

sont les suivants:

for (length = length; length>=0; length--){
    putchar (string[length]);
}

putchar prendra un seul char comme un paramètre et l'imprimer à stdout, qui est ce que vous voulez. puts, d'autre part, imprime toute la chaîne à stdout. Ainsi, lorsque vous passez un seul char une fonction qui attend une chaîne entière (tableau de caractères, NULL chaîne terminée), le compilateur devient confus.

Utilisez putc ou putchar, comme puts est spécifié pour prendre une char* et vous nourrissez un char.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top