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 :

Incrémentation fputs failled


Sujet :

C

  1. #1
    Nouveau membre du Club
    Incrémentation fputs failled
    Bonjour,
    Je cherche a mettre les mots contenus dans mon tableau dans un fichier. Cependant j'ai une erreur de segmentation ... (La meilleure )
    Voici mon code :
    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
    #include <stdio.h>
    #include <stdlib.h>
     
     
    int main(int argc, char *argv[])
    {
        FILE* fichier = NULL;
     
        fichier = fopen("Fichier/test.txt", "a");
     
        char *Lieu[5];
     
        Lieu[0] = "a";
        Lieu[1] = "b";
        Lieu[2] = "c";
        Lieu[3] = "d";
        Lieu[4] = "e";
        Lieu[5] = "\0";
     
        int i = 1;
       // while(i<5){
        if (fichier != NULL)
        {
            for(i=0; i < 5 ; i++ ) {
                fputc(Lieu[i], fichier);    // Erreur est ici 
            }
        }
        fclose(fichier);
        return 0;
    }

    Merci d'avance

  2. #2
    Rédacteur/Modérateur

    Ce code compile ? Vu que fputc prend un char et tu fournis un char*, j'ai des doutes...
    Le niveau 0 des tableaux aurait du t'informer qu'un tableau de 5 cases ça autorise les index [0,4], donc accéder à 5 est indéterminé.
    fputc écrit 1 caractère, donc tu n'écriras pas un mot avec ça ainsi.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Nouveau membre du Club
    Merci pour tes indications.
    Voici le programme corrigé:
    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>
     
     
    int main(int argc, char *argv[])
    {
        FILE* fichier = NULL;
     
        fichier = fopen("Fichier/test.txt", "a");
        char *Lieu[6];
     
        Lieu[0] = "a";
        Lieu[1] = "b";
        Lieu[2] = "c";
        Lieu[3] = "d";
        Lieu[4] = "e";
        Lieu[5] = "\0";
    int i = 1;
        if (fichier != NULL)
        {
            while ( i < 5){
                fputs(Lieu[i], fichier);   
                fputs("\n",fichier); // Permet de mettre des | si on remplace fputs par fputc
                i = i + 1;
            }
        }
        fclose(fichier);
        return 0;
    }

    Merci beaucoup
    @+
    Bapth

  4. #4
    Expert éminent sénior
    Bonjour
    Citation Envoyé par bapth Voir le message
    Voici le programme corrigé:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    char *Lieu[6];
     
    Lieu[0] = "a";
    Lieu[1] = "b";
    Lieu[2] = "c";
    Lieu[3] = "d";
    Lieu[4] = "e";
    Lieu[5] = "\0";
    char *Lieu[6 /* 6 facultatif */]={"a", "b", "c", "d", "e", "\0'}. Ceci dit, ton code (et le mien qui fait la même chose en plus concis) ça marche, bien sûr, mais je ne vois pas trop à quoi sert Lieu[0] (i commence à 1) et surtout Lieu[5] qui ne sont jamais utilisés. T'es sûr d'avoir bien compris le rôle du '\0' dans une chaine de caractères ???

    Citation Envoyé par bapth Voir le message
    Code c :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    fputs(Lieu[i], fichier);   
    fputs("\n",fichier);
    fprintf(fichier, "%s\n", Lieu[i]). Sinon, pour un caractère, autant utiliser fputc() qui est plus rapide => fputc('\n', fichier). Et attention au fclose() qui est appelé même si le fichier n'a pas été ouvert.

    Code c :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
    #include <stdio.h>
    #include <stdlib.h>
     
     
    int main(int argc, char *argv[]) {
    	FILE* fp;
     
    	fp=fopen("Fichier/test.txt", "a");
    	if (fp == NULL) {
    		fprintf(stderr, "Erreur ouverture fichier - Abandon\n");
    		return -1;
    	}
     
    	char *Lieu="abcde";				// Ou char Lieu[]="abcde", ça dépend si on doit ou pas modifier son contenu
    	int i;
    	for (i=0; i < 5; i++) fprintf(fp, "%c\n", Lieu[i]);
    	fclose(fp);
    	return 0;
    }
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  5. #5
    Nouveau membre du Club
    Bonjour Sve@r,
    Merci pour toutes tes informations
    Pour moi, le \0 permet d'indiquer la fin de la chaîne.
    Pour le i = 1, c'était une erreur de ma part. Oups
    Voici le code que j'ai remodifié en suivant le code que tu as fait :
    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>
     
     
    int main(int argc, char *argv[])
    {
        FILE* fichier;
     
        fichier = fopen("Fichier/test.txt", "a");
     
        char *Lieu[/* 6 facultatif */]={"Place1", "Place2", "Place3", "Place4", "Place5", "\0"};
     
        int i = 0;
        if (fichier != NULL)
        {
            while ( i < 5){
                //fputs(Lieu[i], fichier);   
                //fputs("\n",fichier); // Permet de mettre des | si on remplace fputs par fputc
                fprintf(fichier, "%s\n", Lieu[i]);
                i = i + 1;
            }
        }
        else {
            fprintf(stderr, "Erreur ouverture fichier - Abandon\n"); 
    		return -1;
        }
        fclose(fichier);
        return 0;
    }

    Cependant, la partie ou l'on traite les erreurs je ne la comprends pas bien.... C'est s'il n'arrive pas à ouvrir le fichier il ressort un message d'erreur? C'est bien cela ?
    Merci beaucoup
    @+

  6. #6
    Expert éminent sénior
    Citation Envoyé par bapth Voir le message
    Pour moi, le \0 permet d'indiquer la fin de la chaîne.
    J'avais bien compris. Mais justement, quand tu écris char *Lieu[]={"Place1", "Place2", "Place3", "Place4", "Place5", "\0"}, de quelle chaine est-ce que tu parles (il y a 5 chaines différentes) ? Ou (autre façon de poser la même question), le "\0" du dernier élément indique la fin de quoi ???
    Une chaine de caractères c'est un tableau de caractères, ok. Sauf que quand tu écris char x[]="Hello", ensuite le C ne sait pas manipuler "Hello". Tout ce qu'il connait, c'est que x commence au 'H' et de là, il part dans la RAM qui est une grosse suite de cases. Il n'y a absolument rien qui dit "ici je suis dans la string, ici je n'y suis plus". Ok tu as x[0] qui contient 'H' et x[4] qui contient 'o' mais rien ne t'empêche de dépasser ces limites. Et donc il n'y a rien qui t'interdit de taper dans x[-1] ou dans x[751]. Et donc si tu pars du 'H' et que tu incrémentes un pointeur (ou un indice) pour balayer toute la chaine, tu ne sais pas où t'arrêter.
    Première solution: indiquer quelque part que "x" est limité à 5, mais ce "quelque part" il lui faut de la RAM pour le stocker. Alors c'est possible (c'est comme ça que c'est fait en Pascal) mais les concepteurs du C ont préféré une seconde solution
    Seconde solution: placer dans le tableau un caractère de plus, caractère spécial ne ressemblant à aucun autre et ne permettant aucune confusion. Ainsi quand tu balayes la chaine, dès que tu trouves ce caractère, tu sais que tu es au bout. C'est la solution adoptée en C et le caractère c'est le 0 ascii noté aussi '\0'.
    Et donc en écrivant char x[]="Hello" c'est alors strictement équivalent à char x[]={'H', 'e', 'l', 'l', 'o', '\0'} (ou char x[]={'H', 'e', 'l', 'l', 'o', 0} et tu noteras alors la différence d'écriture entre '\0' et 0 qui ne sont que deux écritures différentes pour la même chose, tout comme 0x0a ou 10 ou encore 2*5 sont le même nombre écrits différemment).

    Cela entraine plusieurs conséquences
    • une fonction qui s'attend à traiter une chaine cherchera impérativement ce '\0' et tu peux lui passer ce que tu veux pourvu que tu puisses garantir ce '\0' dans la suite de caractères que tu lui envoies
    • si tu as une suite de caractères en vrac, il te suffit d'y mettre un '\0' où que ce soit pour transformer cette suite en string (certaines fonctions de lecture par exemple renvoient le nb de caractères lus et tu peux utiliser cette valeur pour savoir où mettre ce '\0'). Et tu peux aussi "vider" une chaine en y mettant un simple '\0' au début (toute fonction d'analyse détectant ce '\0' au début concluera qu'elle n'a aucun caractère utile donc qu'elle "est vide" selon sa logique)
    • toute fonction remplissant une chaine mettra (presque) toujours ce '\0' (à toi de ton côté de t'assurer qu'il y ait la place). J'ai dit "presque" car certaines fonctions travaillent aussi avec une limite et quand la limite est atteinte, ne mettent alors pas le '\0' (ex strncpy())
    • chaque fois que tu prévoieras de l'espace pour y stocker une string, tu devras penser à l'espace nécessaire au '\0' car le C ne le fera pas pour toi (il ne sait pas, quand tu déclares un tableau, que tu vas y stocker une string). Et donc char x[]="Hello" ça marche (le compilateur comptera les caractères de la string, string qui inclus ce '\0' et mettra la bonne valeur dans les crochets), char x[100]="Hello" ça marche aussi puisque tu réserves 100 caractères pour en stocker 6 mais char x[5]="Hello" là ça ne marche plus.


    De ton côté tu as aussi parfaitement le droit d'utiliser ce principe pour tes structures de travail en utilisant une valeur spéciale pour indiquer la fin de tes tableaux. Mais en utilisant alors une valeur adaptée audit tableau (pour un tableau de caractères on utilise un caractère spécial, pour un tableau d'int on utilise un int spécial et pour un tableau de pointeurs on utilise alors un pointeur spécial). Par exemple dans ton cas, j'aurais écrit char *Lieu[]={"Place1", "Place2", "Place3", "Place4", "Place5", NULL} en utilisant donc un pointeur NULL comme limite à mon tableau. C'est pas que ton truc ne marche pas mais c'est plus rapide de tester si un pointeur est NULL qu'un pointeur pointant sur une chaine vide. Et surtout j'aurais alors utilisé cette valeur NULL dans ma boucle pour savoir quand m'arrêter plutôt que ce "5" qui te force alors à mémoriser que ton tableau contient 5 valeurs et qui rend ce NULL (ou ce "\0") totalement inutile.

    Citation Envoyé par bapth Voir le message
    Cependant, la partie ou l'on traite les erreurs je ne la comprends pas bien.... C'est s'il n'arrive pas à ouvrir le fichier il ressort un message d'erreur? C'est bien cela ?
    Oui mais c'est pas vraiment le message qui est important à voir, c'est le fait que si on commence par checker les soucis éventuels et qu'on les traite, on peut alors ensuite placer le code "utile" en bordure gauche de l'écran. Parce que si tu commences par faire truc1, puis si truc1 est bon tu fais truc2, puis si truc2 est bon tu fais truc3 (en décalant d'une tabulation à chaque fois), quand tu arrives au code "efficace" (le code qui sert vraiment à programmer l'algo) tes lignes ne font plus que 3 caractères...
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  7. #7
    Nouveau membre du Club
    Merci beaucoup pour toutes les informations que tu m'as apprises!
    J'ai en ce moment un projet à faire je pense encore avoir des questions on se recroisera peut-être ^^ Mais en tout cas merci tu m'as pas mal aidé
    @+

###raw>template_hook.ano_emploi###