IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Génération d'une chaîne de caractères aléatoires


Sujet :

C

  1. #1
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Points : 1 111
    Points
    1 111
    Par défaut Génération d'une chaîne de caractères aléatoires
    Bonjour. Je m'intéresse depuis quelques temps à générer des chaînes de caractère aléatoires. Pour la petite histoire, c'est parce que c'est énervant de se creuser la tête soi-même pour trouver un MdP aléatoire lorsqu'on s'inscrit sur un forum J'imagine que tout le monde connait ça. En ce moment, j'essaie de faire de la génération aléatoire de caractère et d'affecter chacun des caractères à une case d'un tableau déclaré dynamiquement. Pour entrer dans le vif du sujet, c'est une segmentation fault sur laquelle je me casse les dents qui m'ammène à venir ici. Je vous poste mon code. Je précise que j'ai lu ce que j'ai trouvé sur le site à propos d'allocation dynamique de mémoire, et que je n'ai pas trouvé mon erreur (erreur de segmentation qui m'arrive tout le temps quand je fais de l'allocation dynamique, alors c'est qu'il y a quelque chose que je n'ai pas compris)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(void)
    {
       short nbr_lettres,i;                //declarations des variables et pointeurs
       char *la_cle=NULL;                  //
       FILE *cle_file=NULL;                //Pointeur sur flux de données sur fichier
       cle_file=fopen("~/cle_cree","w");   //ouverture en écriture du fichier ~/cle_cree
       printf("entrez le nombre de lettres de votre clé\t"); //initialisation du nombre de
       scanf("%d",&nbr_lettres);                             //caractères de la chaîne
       la_cle=malloc(nbr_lettres*sizeof(char));           //allocation dynamique de mémoire
       for(i=0;i<nbr_lettres;i++)                   // 
       {                                            //Remplissage du tableau
          *(la_cle+i)=((rand()%26)+65);       //avec des lettres majuscules
       }                                            //
       fprintf(cle_file,"La clé est : /t%s",la_cle);//ecriture dans le fichier
       fclose(cle_file);                            
       cle_file=NULL;
       free(la_cle);
       la_cle=NULL;
       printf("/nMerci. Votre clé est dans le fichier cle_cree à la racine de votre répertoire personnel\n");
       return 0;
    }

  2. #2
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Points : 5 360
    Points
    5 360
    Par défaut
    Salut,

    Tu aurais testé le retour le fopen(), comme d'ailleurs également le retour de malloc (comme il faut toujours le faire), tu aurais remarqué un échec dans l'ouverture de ton fichier. Cela vien du fait que fopen ne gère pas le raccourci "~/" qui désigne sous unixoïde le répertoire personnel.

    Tu essayais d'écrire avec fprintf dans cle_cree qui valait NULL (erreur de segmentation). Ensuite, passer NULL à fclose() est, contrairement à free() je crois, un comportement indéterminé.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    *(la_cle+i)=((rand()%26)+65);
    C'est inutilement illisible et équivalent à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    la_cle[i] = (char) (rand() % 26) + 65;
    Par ailleurs, n'oublie pas d'initialiser ton générateur de nombre pseudo-aléatoire au début de ton programme avec srand(time(NULL)); et d'inclure time.h.

    Ce code semble se comporter normalement, sauf que le répertoire où la sauvegarde est effectuée n'est pas $HOME. Tu devrais laisser à l'utilisateur la possibilité de choisir le répertoire où il désire sauver le fichier...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
     
    int main(void)
    {
        int nbr_lettres;
        int i;
        char *la_cle = NULL;
        FILE *cle_file = NULL;
     
        /*-TC- Initialisation du générateur de nombres pseudo-aléatoires */
        srand(time(NULL));
     
        cle_file = fopen("cle_cree","w");
        if (cle_file == NULL)
        {
            fprintf(stderr, "L'ouverture du fichier a échoué!\n");
            exit(EXIT_FAILURE);
        }
     
        printf("entrez le nombre de lettres de votre clé: ");
        fflush(stdout);
        /*-TC- TODO: entrée à sécuriser pour les utilisateurs de mauvaise volonté */
        scanf("%d", &nbr_lettres);
     
        la_cle = malloc(nbr_lettres * sizeof *la_cle);
        if (la_cle == NULL)
        {
            fprintf(stderr, "L'allocation a échoué, mémoire insuffisante!\n");
            exit(EXIT_FAILURE);
        }
     
        for (i=0; i < nbr_lettres; i++)
        {
            la_cle[i] = (char) (rand() % 26) + 65;
        }
     
        fprintf(cle_file, "La clé est : \t%s", la_cle);
     
        fclose(cle_file), cle_file = NULL;
        free(la_cle), la_cle = NULL;
     
        printf("\nMerci. Votre clé est dans le fichier cle_cree à la\n");
        printf("racine de votre répertoire personnel\n");
     
        return EXIT_SUCCESS;
    }
    Meilleures salutations

    Thierry

  3. #3
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Points : 1 111
    Points
    1 111
    Par défaut
    Les variables d'environnement sont comprises par le compilateur ?
    $HOME=/home/user/ ?
    En fait, j'ai une erreur de segmentation en utilisant $HOME. Moralité, écrire les chemins complets dans les progs.
    Merci beaucoup. Je testerai les retours des fonctions d'allocation à l'avenir. Voilà mon code fonctionnel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
     
    int main(void)
    {
       srand(time(NULL));
       short nbr_lettres,i;                //declarations des variables et pointeurs
       char *la_cle=NULL;                  //
       FILE *cle_file=NULL;                //Pointeur sur flux de données sur fichier
       cle_file=fopen("/home/david/cle_cree","w");   //ouverture en écriture du fichier ~/cle_cree
       printf("entrez le nombre de lettres de votre clé\t"); //initialisation du nombre de
       scanf("%d",&nbr_lettres);                             //caractères de la chaîne
       la_cle=malloc(nbr_lettres*sizeof(*la_cle));           //allocation dynamique de mémoire
       printf("\nici la taille du tableau est de %d bits",sizeof(la_cle));//verif a l'ecran
       printf("\nLa taille d'un char est %d bits\n",sizeof(char));        //de l'allocation
       for(i=0;i<nbr_lettres;i++)                   // 
       {                                                                   //Remplissage du tableau
          la_cle[i]=(char) ( (rand()%26) + 65 );       //avec des lettres majuscules
       }                                            
       fprintf(cle_file,"La clé est : \t%s",la_cle);//ecriture dans le fichier
       fclose(cle_file);                            
       cle_file=NULL;
       free(la_cle);
       la_cle=NULL;
       printf("\nMerci. Votre clé est dans le fichier cle_cree à la racine de votre répertoire personnel\n");
       return 0;
    }
    Mais j'ai un retour bizarre dans la console, avec nbr_lettres=26 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    ici la taille du tableau est de 4 bits
    La taille d'un char est 1 bits

  4. #4
    Membre éprouvé

    Profil pro
    Inscrit en
    Août 2003
    Messages
    878
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 878
    Points : 1 067
    Points
    1 067
    Par défaut
    Bonjour,

    Citation Envoyé par kromartien
    Les variables d'environnement sont comprises par le compilateur ?
    Si ta question est "Le compilateur remplace-t-il le nom d'une variable d'environnement par sa valeur lors de la compilation ?", la réponse est non.

    Citation Envoyé par kromartien
    $HOME=/home/user/ ?
    Sous unixoïdes, cela ressemble à cela, oui.

    Citation Envoyé par kromartien
    En fait, j'ai une erreur de segmentation en utilisant $HOME.
    Je suppose que tu as dû essayer de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    cle_file=fopen("$HOME/cle_cree","w");
    Aucun répertoire ne s'appelant "$HOME" n'a été trouvé dans le répertoire courant, fopen() a renvoyé NULL.
    Comme tu n'as pas testé la valeur de retour de fopen(), tu as quand même essayé d'écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fprintf(cle_file,"La clé est : \t%s",la_cle);
    Le premier argument attendu par la fonction fprintf() est du type "FILE *" et l'étoile ("*") qu'il y a après "FILE" veut dire que c'est un pointeur.
    Donc, tu as appelé fprintf() en lui donnant un pointeur qui pointait vers une zone mémoire à laquelle il n'avait pas accès : elle n'était pas dans un segment de mémoire réservé par/pour le programme.
    Résultat : erreur de segmentation.

    Citation Envoyé par kromartien
    Moralité, écrire les chemins complets dans les progs.
    Non. Moralité : toujours vérifier les valeurs de retour des fonctions appelées, surtout malloc(), calloc(), realloc(), fopen(), etc.

    Citation Envoyé par kromartien
    Merci beaucoup. Je testerai les retours des fonctions d'allocation à l'avenir.
    Pourquoi "à l'avenir" ? Pourquoi pas dès maintenant ?
    Si tu prends cette bonne habitude maintenant, tu verras, tu remercieras encore developpez.net dans 10 ans.

    Citation Envoyé par kromartien
    Mais j'ai un retour bizarre dans la console, avec nbr_lettres=26 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    ici la taille du tableau est de 4 bits
    La taille d'un char est 1 bits
    Seulement avec nbr_lettres=26 ? En es-tu sûr ?
    Déjà, il faut savoir que sizeof() ne renvoie pas une taille en bits.
    Ensuite, "sizeof(la_cle)" renverra la valeur de "sizeof( char * )" puisque "la_cle" est du type "char *". Or, un "char *" est un pointeur sur un "char", donc "sizeof(la_cle)" renverra la taille d'un pointeur, pas la taille d'une zone de mémoire réservée pointée par ce pointeur. Autrement dit, chez toi, "sizeof(la_cle)" renverra toujours 4 (et pour infos, c'est 4 octets).

    En espérant avoir répondu à tes questions, cordialement,
    DS.

  5. #5
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Points : 1 111
    Points
    1 111
    Par défaut
    D'accord. J'ai bien compris. Une chose en tout cas, qui est que programmer en C ne s'improvise pas. Merci pour tous ces conseils. Comment accéder à la taille de la zone mémoire allouée à un tableau ? De toute façon, c'est un test stupide. Si j'ai besoin d'accéder à la taille d'un tableau alloué dynamiquement, la variable nbr_lettres est encore là à disposition.
    Oui c'est vrai la sortie à l'écran est indépendante du nombre de cases octroyées au tableau. un char, 1 octet,
    un pointeur sur char 4 octets. (Le pointeur ne contient pas de valeur au sens arithmétique, mais une adresse mémoire, qui tient sur 4 octets (c'est beaucoup 4 octets). 2^32=4 294 967 296)

  6. #6
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par kromartien
    D'accord. J'ai bien compris. Une chose en tout cas, qui est que programmer en C ne s'improvise pas.
    Voilà. Ca, tu peux le retenir. La langage C, c'est pas un langage de bricoleur...

  7. #7
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Points : 5 360
    Points
    5 360
    Par défaut
    Citation Envoyé par kromartien
    D'accord. J'ai bien compris. Une chose en tout cas, qui est que programmer en C ne s'improvise pas.
    Bienvenu au club, c'est ce que je réalise aussi jour après jour. C'est un langage plein de subtilités, et on peut vite faire n'importe quoi.
    Citation Envoyé par kromartien
    Merci pour tous ces conseils. Comment accéder à la taille de la zone mémoire allouée à un tableau ? De toute façon, c'est un test stupide. Si j'ai besoin d'accéder à la taille d'un tableau alloué dynamiquement, la variable nbr_lettres est encore là à disposition.
    Oui c'est vrai la sortie à l'écran est indépendante du nombre de cases octroyées au tableau. un char, 1 octet,
    un pointeur sur char 4 octets. (Le pointeur ne contient pas de valeur au sens arithmétique, mais une adresse mémoire, qui tient sur 4 octets (c'est beaucoup 4 octets). 2^32=4 294 967 296)
    Pour obtenir la taille d'un tableau statique ou alloué sur la pile:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    size_t taille_octets = sizeof tableau;
    te donne la taille en octets et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    size_t nb_elems = (sizeof tableau)/(sizeof *tableau);
    te donne la taille en nombre d'éléments. Pour un tableau alloué dynamiquement sur le tas, il n'y a aucun moyen de retrouver sa taille, il faut conserver cette valeur dans une variable destinée à cet effet. Cette variable ne sera modifiée qu'en cas de redimensionnement du tableau. En pratique, il peut être intéressant de réunir le tableau lui même et sa taille dans une structure et de définir un TAD (Type abstrait de donnée).

    Thierry

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 8
    Dernier message: 12/02/2013, 01h08
  2. [Turbo Pascal] Générer aléatoirement une chaîne de caractères
    Par bzminfo dans le forum Turbo Pascal
    Réponses: 4
    Dernier message: 02/04/2010, 22h08
  3. Réponses: 2
    Dernier message: 07/05/2007, 12h18
  4. Inverser une chaîne de caractères
    Par DBBB dans le forum Assembleur
    Réponses: 2
    Dernier message: 30/03/2003, 11h09
  5. Réponses: 3
    Dernier message: 09/05/2002, 01h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo