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 :

Fonction invisible :(


Sujet :

C

  1. #1
    Nouveau membre du Club
    Fonction invisible :(
    Bonjour c'est encore moi ,
    J'ai un autre problème,
    J'ai créer 3 fonctions :
    - la premiere permet de compter le nombre de ligne dans un fichier
    - la 2eme permet d'afficher le contenue de mon fichier
    -le 3eme permet d'ajouter un contenue dans le fichier s'il n'est pas présent
    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
     #include <stdlib.h>
     #include <stdio.h>
     #include <string.h>
     
     
    int compte_ligne(FILE *fichier){
     
    	int count = 0;
    	int nLignes = 0;
     
    	while((count=fgetc(fichier)) != EOF)
    	{
    		if(count=='\n'){
    			nLignes++;
            }    
    	}
        //nLignes = nLignes + 1;
        count = 1;
        fclose(fichier);
     
     
    	return nLignes;
    }
     
    void afficher_lieu (int nLignes) {
     
        FILE *fichier;
        char* chaine;
        int i=0;
     
        fichier = fopen("Fichier/Lieu.txt", "r"); //Ouvre le fichier que en read 
     
    /* A voir apres
        if (fichier == NULL ){ //Au cas ou il y aurait une erreur lors de l'ouverture du fichier
            fprintf(stderr, "Erreur ouverture fichier - Abandon\n"); 
    		return -1; // Return -1 pour erreur
        }
    */
     
        while(i < nLignes){
            fgets(chaine, 80, fichier); 
            printf("test : %s", chaine); 
            i = i + 1;
        }
        fclose(fichier); //Ferme le fichier
     
    }
     
    void afficher_participants (int nLignes) {
     
        FILE *fichier;
        char* chaine;
        int i=0;
     
        fichier = fopen("Fichier/Participant.txt", "r"); //Ouvre le fichier que en read 
     
    /* A voir apres
        if (fichier == NULL ){ //Au cas ou il y aurait une erreur lors de l'ouverture du fichier
            fprintf(stderr, "Erreur ouverture fichier - Abandon\n"); 
    		return -1; // Return -1 pour erreur
        }
    */
     
        while(i < nLignes){
            fgets(chaine, 80, fichier); 
            printf("\nParticipant : %s", chaine); 
            i = i + 1;
        }
     
        fclose(fichier); //Ferme le fichier
     
    }
     
    void ajouter_lieu (){
     
     
        FILE *fichier;
     
        char Lieu_Dans_Fichier[30], Lieu_entree[30];
        int trouve = 0;
        fichier = fopen("Fichier/test.txt", "r"); //Ouvre le fichier que en read 
     
    /* A voir apres
        if (fichier == NULL ){ //Au cas ou il y aurait une erreur lors de l'ouverture du fichier
            fprintf(stderr, "Erreur ouverture fichier - Abandon\n"); 
    		return -1; // Return -1 pour erreur
        }
    */
     
        printf("Lieu a ajouter : ");  //Pour savoir le mot cherche
        scanf("%s",Lieu_entree);
     
        while (fgets(Lieu_Dans_Fichier,30,fichier) != NULL) // Le 30 correspond a max 30 caracteres
        {   
          if (strstr(Lieu_Dans_Fichier, Lieu_entree) != NULL){  // Si mot cherche == mot dans le fichier 
                trouve = 1;
            }
        }
        fclose(fichier); //Ferme le fichier
     
        fichier = fopen("Fichier/Lieu.txt", "a"); //Ouvre le fichier en mode écriture
     
        if (trouve == 1){
            printf("Le lieu existe deja <img src="images/smilies/icon_smile.gif" border="0" alt="" title=":)" class="inlineimg" />");
        }
        else{
            printf("OK, Ajout du lieu");
            fprintf(fichier, "%s\n", Lieu_entree);  //Ecrit le mot recherche a la fin du fichier 
        }
        fclose(fichier); //Ferme le fichier
    }
     
    int main () {
     
        FILE *fichier_lieu = fopen("Fichier/Lieu.txt", "r");
        FILE *fichier_participant = fopen("Fichier/Participant.txt", "r");
       afficher_participants(compte_ligne(fichier_participant));
        afficher_lieu(compte_ligne(fichier_lieu));
        ajouter_lieu();
     
     
        fclose(fichier_lieu); fclose(fichier_participant);
        return 0;
     
    }


    Le problème est : Quand j'exécute le programme la fonction ajouter_lieu() n'est pas exécuter. Par contre quand je retire l'appel : afficher_lieu(compte_ligne(fichier)); , la fonction ajouter_lieu() est exécutée. Je ne comprends vraiment pas pourquoi ...
    Si vous pouvez m'aider
    @+
    Bapth

  2. #2
    Nouveau membre du Club
    J'ai enfin résolu mon problème !!
    J'ai juste changé à la ligne 28 et 52 char *chaine; par char chaine[80];
    Je n'ai pas vraiment compris pourquoi ce changement rendait mon programme fonctionnel. (Peut-être on passe d'une taille dynamique à une taille fixe ...)
    Je vous mets quand même le 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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
     #include <stdlib.h>
     #include <stdio.h>
     #include <string.h>
     
     
    int compte_ligne(FILE *fichier){
     
    	int count = 0;
    	int nLignes = 0;
     
    	while((count=fgetc(fichier)) != EOF)
    	{
    		if(count=='\n'){
    			nLignes++;
            }    
    	}
        //nLignes = nLignes + 1;
        count = 1;
        fclose(fichier);
     
     
    	return nLignes;
    }
     
    void afficher_lieu (int nLignes) {
     
        FILE *fichier;
        char chaine[80];
        int i=0;
     
        fichier = fopen("Fichier/Lieu.txt", "r"); //Ouvre le fichier que en read 
     
    /* A voir apres
        if (fichier == NULL ){ //Au cas ou il y aurait une erreur lors de l'ouverture du fichier
            fprintf(stderr, "Erreur ouverture fichier - Abandon\n"); 
    		return -1; // Return -1 pour erreur
        }
    */
     
        while(i < nLignes){
            fgets(chaine, 80, fichier); 
            printf("test : %s", chaine); 
            i = i + 1;
        }
        fclose(fichier); //Ferme le fichier
     
    }
     
    void afficher_participants (int nLignes) {
     
        FILE *fichier;
        char chaine[80];
        int i=0;
     
        fichier = fopen("Fichier/Participant.txt", "r"); //Ouvre le fichier que en read 
     
    /* A voir apres
        if (fichier == NULL ){ //Au cas ou il y aurait une erreur lors de l'ouverture du fichier
            fprintf(stderr, "Erreur ouverture fichier - Abandon\n"); 
    		return -1; // Return -1 pour erreur
        }
    */
     
        while(i < nLignes){
            fgets(chaine, 80, fichier); 
            printf("\nParticipant : %s", chaine); 
            i = i + 1;
        }
     
        fclose(fichier); //Ferme le fichier
     
    }
     
    void ajouter_lieu (){
     
     
        FILE *fichier;
     
        char Lieu_Dans_Fichier[30], Lieu_entree[30];
        int trouve = 0;
        fichier = fopen("Fichier/test.txt", "r"); //Ouvre le fichier que en read 
     
    /* A voir apres
        if (fichier == NULL ){ //Au cas ou il y aurait une erreur lors de l'ouverture du fichier
            fprintf(stderr, "Erreur ouverture fichier - Abandon\n"); 
    		return -1; // Return -1 pour erreur
        }
    */
     
        printf("Lieu a ajouter : ");  //Pour savoir le mot cherche
        scanf("%s",Lieu_entree);
     
        while (fgets(Lieu_Dans_Fichier,30,fichier) != NULL) // Le 30 correspond a max 30 caracteres
        {   
          if (strstr(Lieu_Dans_Fichier, Lieu_entree) != NULL){  // Si mot cherche == mot dans le fichier 
                trouve = 1;
            }
        }
        fclose(fichier); //Ferme le fichier
     
        fichier = fopen("Fichier/Lieu.txt", "a"); //Ouvre le fichier en mode écriture
     
        if (trouve == 1){
            printf("Le lieu existe deja <img src="images/smilies/icon_smile.gif" border="0" alt="" title=":)" class="inlineimg" />");
        }
        else{
            printf("OK, Ajout du lieu");
            fprintf(fichier, "%s\n", Lieu_entree);  //Ecrit le mot recherche a la fin du fichier 
        }
        fclose(fichier); //Ferme le fichier
    }
     
    int main () {
     
    //Ouverture fichiers //
    	FILE *fichier_lieu = fopen("Fichier/Lieu.txt", "r");
        FILE *fichier_participant = fopen("Fichier/Participant.txt", "r");
     
       // afficher_lieu(compte_ligne(fichier));
        ajouter_lieu();
     
        afficher_lieu(compte_ligne(fichier_lieu));
        afficher_participants(compte_ligne(fichier_participant));
     
     
    //Fermeture fichiers //
        fclose(fichier_lieu); fclose(fichier_participant);
        return 0;
    }

    Voila
    @+
    Bapth

  3. #3
    Expert éminent
    Citation Envoyé par bapth Voir le message
    Je n'ai pas vraiment compris pourquoi ce changement rendait mon programme fonctionnel
    Pourtant la réponse est simple : ton programme plantait

    Tu utilisais des tableaux mais ils n'étaient pas initialisés.

    La solution la + simple est 1 tableau constant, comme tu l'as fait : char chaine[80];.

    Sinon, il faut l'allouer, l'initialiser si nécessaire et le désallouer :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        char* chaine;
     
        chaine = malloc(80 /* * sizeof(char) */);
     
        if (chaine != NULL) {
            memset(chaine, '\0', 80); // if needed
     
    //      ...
     
            free(chaine);
            chaine = NULL;
        }

  4. #4
    Expert éminent sénior
    Citation Envoyé par bapth Voir le message
    Bonjour c'est encore moi ,
    Hey, salut

    Citation Envoyé par bapth Voir le message
    J'ai un autre problème,
    A mon avis ce n'est pas le dernier. Quand je débutais en prog C, je faisais tellement chier mon collègue à lui poser plein de questions qu'il avait découpé un carton de jus de fruit "Joker" et m'avait donné l'étiquette. Et je n'avais eu ensuite le droit qu'à un "Joker" par jour. Si je lui posais une question, je lui donnais le carton qu'il me rendait le lendemain.

    Citation Envoyé par bapth Voir le message
    J'ai juste changé à la ligne 28 et 52 char *chaine; par char chaine[80];
    Je n'ai pas vraiment compris pourquoi ce changement rendait mon programme fonctionnel. (Peut-être on passe d'une taille dynamique à une taille fixe ...)
    C'est un peu de ça. Tu as au départ une taille effectivement dynamique mais encore non allouée (aucun espace de prévu pour y stocker quoi que ce soit). Tu as effectivement une taille qui peut-être dynamique mais qui est pour l'instant nulle. Et quand tu tentes d'y mettre des caractères (fgets()) => plantage (en réalité c'est plus subtil car c'est un comportement indéterminé donc imprévisible donc on ne peut même pas prédire qu'il y aura plantage).

    Prenons du départ: quand tu déclares un pointeur char *chaine (ou n'importe quel truc *chaine), tu ne déclares qu'un pointeur inutile. Il te faut ensuite positionner ce pointeur, c'est à dire lui donner une adresse. Pour simplifier, tu es obligé d'écrire à un moment donné chaine=quelque_chose et si tu n'écris pas cette instruction, alors tu es certain que ton programme est incorrect. C'est une certitude absolue. Ton travail est de trouver ce "quelque_chose" à mettre (mais en général ce n'est pas une difficulté car le codeur qui a l'habitude sait pourquoi il crée son pointeur et donc sait ce qu'il va y mettre).
    Si tu n'écris pas ce chaine=quelque_chose, tu n'as fait que créer en ram un pointeur (une variable) contenant une valeur (toute variable contient toujours une valeur) mais valeur indéterminée. En effet, pourquoi le compilateur s'embêterait-il à y mettre quoi que ce soit vu que tu es censé toi y mettre quelque chose de valide => un des prédicats de base du C est que pour être le plus rapide possible, il ne fait que ce qui est écrit et à toi de t'assurer que tu fais ce qu'il faut pour que ça ne soit pas invalidant du point de vue logique car il ne vérifie rien.
    Donc tu as en main un pointeur (adresse mémoire) contenant n'importe quelle valeur (n'importe quelle adresse) et là, à cette adresse, tu vas y stocker (fgets()) de la data ??? As-tu le droit d'écrire à cette adresse ? Cette adresse n'est-elle pas celle d'une autre variable ?? Fait-elle seulement partie de l'espace mémoire de ton programme ??? C'est ce qu'on nomme donc un UB (Undefined Behaviour = comportement indéterminé). Ton programme peut marcher, peut ne pas marcher, peut marcher les jours pairs et planter les jours impair, peut marcher 5 ans puis tu rajoutes un compteur et ça plante (et tu te creuses le citron à essayer de comprendre en quoi ton compteur fait planter le truc), peut te rebooter ta machine ou reformater ton disque dur (nan je déconne, il y a quand-même la barrière de l'OS qui protège mais c'est pour illustrer).

    foetus, lui, utilise aussi le pointeur mais ensuite demande au C de réserver une zone mémoire (malloc=memory allocation) et récupère cette zone alloué (chaine=malloc(...)). Il a respecté la règle du chaine=quelque_chose, son programme est correct (ce qui ne veut pas dire qu'il ne faillira pas ailleurs, un programme en C c'est une attention de tous les instants). Par exemple il faudra veiller à ne pas dépasser et surtout il faudra ensuite penser à libérer la zone free(chaine) car le C ne le fera pas automatiquement. Bon en réalité les OS modernes le font automatiquement quand le programme se termine mais déjà ce n'a pas toujours été le cas (XP par exemple ne le faisait pas) et quoi qu'il en soit, en C vaut mieux toujours faire les choses soi-même, au-moins on est sûr qu'elles sont faites, plutôt que de compter sur l'esclave de service sans être certain qu'il sera au rendez-vous (il y a des programmes en C qui tournent sur des trucs exotiques, comme par exemple le contrôle de pilotage automatique, et bon si tu as envie de voler dans un avion où le programmeur a pensé "je m'en fouts de libérer de la RAM dont je ne me sers plus, le truc doit probablement le faire automatiquement"...)

    Il y a l'autre solution du tableau réservé à la compilation, le fameux char chaine[80], ce que tu as fait. Là tu définis une zone de 80 caractères qui t'es immédiatement réservée. Tu as la garantie que rien ne pourra la pourrir ("rien" dans le cas d'un programme bien écrit évidemment, car si tu provoques un UB, il peut alors venir justement pourrir ta zone) et tu peux y mettre ce que tu veux (dans la limite de 80 caractères, sans oublier le '\0' si ce que tu y mets doit être une string). Pas de souci de réservation/libération, pas de souci de pointeur inconnu, bref la solution la plus simple chaque fois que tu devras prévoir une zone de taille fixe. A toi simplement de veiller à ne pas dépasser car le C n'y veillera pas à ta place.
    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
    Merci pour toutes tes indications.
    Si je comprends bien, il faut être constamment vigilent car une fonction créer peut se mettre à bugger lors de l'ajout de la dernière ligne de notre programme . Il faut donc être tout le temps vigilent lors de la création de nos variables
    @+ et merci encore !
    Bapth

  6. #6
    Expert éminent sénior
    Citation Envoyé par bapth Voir le message
    Il faut donc être tout le temps vigilent lors de la création de nos variables
    Et aussi dans leur utilisation !!!
    Une erreur facile à faire
    Code c :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    int n[10];
    for (i=0; i <= 10; i++) n[i]=0;		// Dépassement de capacité, un tableau de 10 va de 0 à 9 => écrire "i < 10" !!!


    Et c'est encore pire avec les strings (sur un char tab[10], tu ne peux aller que de 0 inclus à 8 inclus car il faut au minimum tab[9] de libre pour y stocker le '\0'). Il existe toutefois pour ça un consensus permettant de limiter les risques: rajouter systématiquement "+1" =>char tab[10 + 1] signifiant "ma chaine aura 10 caractères réels et j'ai bien pensé au '\0'" et si on veut boucler, on peut alors écrire for (i=0; i < 10; i++) ....
    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

###raw>template_hook.ano_emploi###