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 :

interprétation des données lues dans un fichier


Sujet :

C

  1. #1
    Membre du Club Avatar de Redgard
    Homme Profil pro
    x
    Inscrit en
    Décembre 2014
    Messages
    90
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : x

    Informations forums :
    Inscription : Décembre 2014
    Messages : 90
    Points : 60
    Points
    60
    Par défaut interprétation des données lues dans un fichier
    Bonjour,

    J'ai un exercice qui consiste à lire des données dans un fichier source et à les copier dans un fichier destination, en y incrémentant 2 à chaque note de chaque ligne. Cette note ne devant pas dépasser 20.

    Fichier source :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    15; Aline
    12; Bernard
    9; Mafalda
    19; Eliot
    Fichier destination :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    17; Aline
    14; Bernard
    11; Mafalda
    20; Eliot
    Débutant avec toutes les fonctions fget, fread, j'ai encore du mal à me figurer comment elle marche et comment les données sont manipulées.
    la situation idéal serait quelles soient récupérés (fget?) et stockés dans un tableau de structure à deux colonnes.
    De là, je n'aurais qu'à récupérer la première colonne de chaque ligne (persone[0][i]) et d'incrémenter via une boucle (for (int i = 0; i < nbrPers; i++)), en m'assurant que la note ne dépasse pas 20 (if & else)

    Est-ce qu'il ne serait pas une bonne idées de diviser ma fonction Anniversaire()? J'ai l'impression que je veux faire trop de chose dedans...

    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
    #include <stdio.h>
    #include <stdlib.h>
     
     
    // ================================= STRUCTURE =================================
    // tableau de structure stockant une personne et sa note
    struct personne
    {
    	float note;
    	char nom[30];
    };
     
    //déclaration de ce tableau sous le pointeur tab
    struct personne *tab;
     
    // ================================= FONCTION APPELEE =================================
    // fonction copiant les données d'un fichier dans un autre en y incrémentant deux point
    void Anniversaire(FILE *source; FILE *dest) {
     
    	// déclaraction de la taille du tableau.
    	tab = malloc(nbrPers * sizeof(struct personne));
     
    	//copie des données fichier source dans le tableau tab.
     
     
    	// incrémentation à la variable note.
    	for (int i = 0; i < nbrPers; i++)
    	{
    		if (tab[i].note < 19) {
    			tab[i].note + 2
    		}
    		else
    		{
    			tab[i].note + 1
    		}
     
    	}
     
    	// copie des données du tableau tab dans le fichier dest.
     
     
    }
     
     
    // ================================= FONCTION MAIN =================================
    int main() {
    	FILE *fo, *fw;
     
    	if ((fo = fopen("/note.txt", "r")) == NULL)
    	{
    		printf("impossible d'ouvrir en lecture le fichier note.txt !\n");
    		exit(0);
    	}
    	if ((fw = fopen("/anniversaire.txt", "w"))) == NULL)
    	{
    		printf("impossible d'ouvrir en écriture le fichier anniversaire.txt !\n");
    		exit(1);
    	}
     
    	Anniversaire(*fo, *fw);
     
    	fclose(fo);
    	fclose(fw);
     
    	return 0;
    }
    Merci d'avance,
    Red'

  2. #2
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Commence par écrire ton programme en pseudo-code sur une feuille de papier. Ça devrait déjà te donner une assez bonne idée des différentes tâches nécessaires et de leur découpage.

    Partage ensuite cet algorithme, puis un squelette de programme qui compile (celui-ci n'est pas du C valide).

    L'implémentation effective se fera probablement autour d'appels à fgets puis sscanf. On y viendra dans un second temps.

  3. #3
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Redgard Voir le message
    débutant avec toutes les fonctions fget, fread, j'ai encore du mal à me figurer comment elle marche et comment les données sont manipulées.
    Bonjour

    Ces deux fonctions ont le même rôle, à savoir récupérer des données dans un fichier.
    fgets() récupère les données mais se cale sur la ligne. Elle récupère donc de l'octet mais s'arrête dès que le nb d'octets a été atteint, ou bien dès qu'elle atteint la fin de la ligne. Idéal donc pour traiter des fichiers textes. Et quand on veut être sûr de récupérer toute la ligne, on demande alors généralement un nb d'octets assez élevé (1000) => fgets(zone, 1000 + 1, fp) (le "+1" indique qu'on a bien pensé au '\0' qui doit terminer toute chaine).
    fread() récupère de l'octet mais ne se préoccupe que du nb d'octets demandé. Plus adapté aux fichiers binaires (images, vidéos, sons, etc).
    Dans tous les cas, tu récupères de l'octet à suivre sans que ce que tu récupères soit interprété d'une façon ou d'une autre. Si par exemple ta ligne contient "15; Aline" alors tu récupèreras '1', '5', ';', ' ', 'A', 'l', 'i', 'n', 'e', '\n' et si tu utilises fgets(), alors la fonction te rajoutera un '\0'. A toi ensuite d'analyser la chaine reçue pour convertir '1', '5', ';' en "15"...

    Citation Envoyé par Redgard Voir le message
    Est-ce qu'il ne serait pas une bonne idées de diviser ma fonction Anniversaire()? J'ai l'impression que je veux faire trop de chose dedans...
    Ben oui. Tu devrais avoir une fonction pour lire les données et d'autres fonctions pour les traiter (ce qu'on nomme généralement "programmation MVC"). Ca rend ton code beaucoup plus évolutif. Ceci dit, tu ne lui passes pas les bons paramètres. Ta fonction attend du "FILE étoile" et tu lui passes "étoile fo". Alors c'est quoi "étoile fo" ?
    Ben puisque "fo" est défini comme un "FILE étoile" (pointeur sur fichier) alors lui passer "étoile fo" c'est lui passer l'élément pointé donc le fichier donc un "FILE". Or un "FILE" n'est certainement pas un "FILE étoile" !!!
    Pour résumer, si "fo=FILE étoile", alors "étoile fo=FILE" (l'étoile passe de l'autre côté de l'égalité).
    Sinon pour tes notes tu te casses vraiment la tête pour rien. Rajoute systématiquement 2 à ta note et si elle dépasse 20 alors tu lui mets 20. Ca t'évite de devoir gérer les cas "19" et "20" (qui n'a pas été géré)...
    Accessoirement les variables en global c'est possible (puisque le C le permet) mais déclarer "tab" en global c'est vraiment faire sa grosse faignasse pour ne pas avoir à le passer aux fonctions (surtout que tab étant un pointeur, une fonction qui voudrait le modifier devrait recevoir un double pointeur). Malheureusement si tu commences à travailler comme ça, tu te libèreras d'un souci immédiat mais tu génèreras en retour cent fois plus de problèmes d'autant plus difficiles à résoudre qu'ils arriveront plus tard quand ton code sera bien plus avancé.

    PS: j'ai du mal à faire l'analogie entre le nom de ta fonction ("Anniversaire()") et le but de cette fonction (choper des notes et leur rajouter 2). Mais c'est vrai que si les fonctions devaient porter un nom correspondant à leur rôle, cela faciliterait trop la relecture et la compréhension du code...
    PS2: tu travailles souvent à la racine de ton système ("/note.txt", "/anniversaire") ? T'as à ta disposition un tas de dossiers pour bosser ($HOME, $HOME/tmp, /tmp) c'est vraiment malheureux de pourrir ton OS avec tes fichiers à la c. Surtout que ça indique aussi que tu bosses sous root...
    Mon Tutoriel sur la programmation «Python»
    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
    Et on poste ses codes entre balises [code] et [/code]

  4. #4
    Membre du Club Avatar de Redgard
    Homme Profil pro
    x
    Inscrit en
    Décembre 2014
    Messages
    90
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : x

    Informations forums :
    Inscription : Décembre 2014
    Messages : 90
    Points : 60
    Points
    60
    Par défaut
    Citation Envoyé par Matt_Houston Voir le message
    j'ai du mal à faire l'analogie entre le nom de ta fonction ("Anniversaire()")
    Juste un manque d'idée du prof lié au fait qu'on fasse cadeau de deux points sur la note à chaque personne ( cadeau > anniversaire). De là j'ai aussi repris le truc pour rester dans le thème même si c'était pas du tout explicite...

    L'objectif de l'exercice est de lire un ficher textesource de modifier la note de chaque personne et d'inscrire ces changements dans un fichier TexteDestination


    Citation Envoyé par Matt_Houston Voir le message
    écrire ton programme en pseudo-code
    Je débute donc je suis loin d'être parfait, en espérant que ça explique un peu mieux ce que je veux faire :/

    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
    =========Texte Source=========
    15; Aline
    12; Bernard
    9; Mafalda
    19; Eliot
     
     
    ========= Initialisation du programme=========
    	STRUCTURE
    		Personne
    			Float note
    			Tableau nomPersonne[]
     
    	FONCTION
    		Int NbrsPersonne(FILE Textesource)     //calcule le nombre de ligne dans le fichier texte
    			Int nbrsLignes
    			Boucle While calculant le nombre de ligne du fichier TexteSource
    				nbrsLignes++
    			Retourne nbrsLignes
     
    		Void Récupérateur(FILE TexteSource, Struct tab)     // copie TexteSource > tab
    			???
     
    		Void Incrementeur(Struct tab, int nbrpers)     // modifie la première colonne du tableau
    			???
     
    		Void Envoyeur(Struct tab, FILE TexteDestination)     // copie tab > TexteDestination
    			???
     
     
    	MAIN
    		// déclaration des données
    		Struct personne *tab;
    		FILE *fileOriginal, *fileDestination;
     
    		// association des pointeurs
    		Boucle if lisant et associant le pointeur fileOrigine au fichier TexteSource, vérifiant si le fichier existe
    		Boucle if écrivant le fichier Texte Destination et l'associant au pointeur fileDestination, vérifiant si le fichier existe.
     
    		// déclaration de la taille du tableau tab
    		Int nbrsPers = NbrsPersonne(File *fileOrigine)
     
    		tab = malloc(nbrPers * sizeof(struct personne));
     
    		// copie du contenu du fichier texteSource dans le pointeur
    		Récupérateur( *fileOriginal, *tab)
     
    		// incrémente 2 à la colonne note du tableau tab
    		Incrementateur(*tab, nbrsPers)
     
    		//écrit le contenu du tableau tab dans le fichier TexteDestination
    		Envoyeur(*tab, *fileDestination)
     
    		//fermeture des flux
    		Fclose(fileOriginal);
    		Fclose(fileDestination);
     
    		//retour fonction main
    		Return 0;
     
     
    =========Texte Destination=========
    17; Aline
    14; Bernard
    11; Mafalda
    20; Eliot
    En fait ce que j'aimerais savoir précisément, c'est comment le fichier TexteSource.txt est traité par la machine en utilisant les commandes fgets/freads.

    En cherchant sur le net, je suis tombé sur ce tuto > http://www.zentut.com/c-tutorial/c-read-text-file/
    Donc si je comprends bien, c'est comme si fgets traitait le fichier .txt comme un tableau. exemple sur base de mes données:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     char tab[4] = ("15; Aline","12; Bernard","9; Mafalda","19; Eliot")
    Ce qui voudrait dire qu'il me faudrait une étape supplémentaire pour assigner les nombres à tab[i].note et les lignes de caractère à tab[i].nomPersonne?
    Dans ce cas là, il me faudrait un fonction pour extraire les deux parties via boucle while( tab[i]=! ";"). Mais là encore faudrait que je cherche sur le net.

    Citation Envoyé par Matt_Houston Voir le message
    Ta fonction attend du "FILE étoile" et tu lui passes "étoile fo".
    J'ai encore du mal avec les pointeurs. Ils se sont concentrés sur comment les pointeurs étaient stocké dans la mémoire, mais n'ont pas trop communiqué sur comment correctement les utiliser. N'hésites pas à me reprendre dessus, ça m'évitera de faire n'importe quoi.

  5. #5
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Redgard Voir le message
    En fait ce que j'aimerais savoir précisément, c'est comment le fichier TexteSource.txt est traité par la machine en utilisant les commandes fgets/freads.
    Je te l'ai expliqué. Tu ne lis que du caractère et, même si les fonctions te remplissent une zone, ces caractères sont lus un à un. Au final, tu as donc un gros tableau de caractères.

    Citation Envoyé par Redgard Voir le message
    En cherchant sur le net, je suis tombé sur ce tuto > http://www.zentut.com/c-tutorial/c-read-text-file/
    Donc si je comprends bien, c'est comme si fgets traitait le fichier .txt comme un tableau. exemple sur base de mes données:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     char tab[4] = ("15; Aline","12; Bernard","9; Mafalda","19; Eliot")
    Déjà tu définis un tableau de 4 caractères et tu y mets 4 chaines (sous-entendu avec chaque chaine contenant "n" caractères) !!!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     char *tab[4] = {"15; Aline","12; Bernard","9; Mafalda","19; Eliot"}
    Sinon t'as mal lu. Dans l'exemple fgets() récupère au plus MAXCHAR - 1 caractères (on demande "MAXCHAR" mais il conserve 1 caractère pour y mettre le '\0' => d'où mon exemple où je demandais "1000 + 1"...).
    Mais si la ligne se termine avant, il s'arrête alors à la fin de ligne (bref il te récupère donc une ligne du fichier). Et toi, tu n'as au final qu'une grosse chaine "15; Aline\n".

    Citation Envoyé par Redgard Voir le message
    Ce qui voudrait dire qu'il me faudrait une étape supplémentaire pour assigner les nombres à tab[i].note et les lignes de caractère à tab[i].nomPersonne?
    Bien que tu aies mal compris ce que tu obtiens, la conclusion est correcte. Oui, il te faut décomposer la chaine reçue.

    Citation Envoyé par Redgard Voir le message
    Dans ce cas là, il me faudrait un fonction pour extraire les deux parties via boucle while( tab[i]=! ";"). Mais là encore faudrait que je cherche sur le net.
    Tu peux utiliser strchr() qui recherche un caractère particulier dans une chaine et qui te renvoie l'adresse (qui peut être aussi compris comme étant la position) de ce caractère.
    Exemple
    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
    #include <stdio.h>
    #include <string.h>
     
    int main() {
    	char chaine[]="15 ; Aline";
    	char *note;
    	char *nom;
    	char *pt;
     
    	pt=strchr(chaine, ';');
    	if (pt != NULL) {
    		*pt='\0';
    		note=chaine;
    		nom=pt+1;
    		printf("nom=[%s], note=[%s]\n", nom, note);
    	}
    }

    Reprend cet exemple, compile-le pour que tu vois ce que ça fait. Puis quand tu l'auras compris, tu sauras alors comment récupérer tes noms et tes notes...

    Citation Envoyé par Redgard Voir le message
    J'ai encore du mal avec les pointeurs. Ils se sont concentrés sur comment les pointeurs étaient stocké dans la mémoire, mais n'ont pas trop communiqué sur comment correctement les utiliser.
    Mouais. C'est dommage car la bonne compréhension des pointeurs est primordiale à la compréhension du C. N'hésite pas à creuser le sujet et à revenir nous voir si tu as des questions...
    Mon Tutoriel sur la programmation «Python»
    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
    Et on poste ses codes entre balises [code] et [/code]

  6. #6
    Membre du Club Avatar de Redgard
    Homme Profil pro
    x
    Inscrit en
    Décembre 2014
    Messages
    90
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : x

    Informations forums :
    Inscription : Décembre 2014
    Messages : 90
    Points : 60
    Points
    60
    Par défaut
    Dis moi si c'est bon

    1. Ce que je retiens des pointeur:
    Nom : c-pointers.png
Affichages : 704
Taille : 3,3 Ko
    "px = &x" == "*px = x" == "px = *x"

    Int x = 10
    > x = 10
    >*x = 28FF1C

    Int *px = x
    >*px = x = 10
    > px = *x = 28FF1C

    2. Quelle est l'intérêt de définir ses fonctions en dessous de main et de la déclarer au dessus? La lisibilité?
    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
    void display_array(int*,const int);
     
    int main()
    {return 0;
    }
     
    /*Display an array of integers with predefined size*/
     
    void display_array(int* p,const int size)
    {
    int i;
    for(i = 0; i < size; i++)
    {
    printf("%d ",p[i]);
    }
    printf("\n");
    }
    3. Quelle est la différence entre ces deux notations? "Int* pa" et "int *pa"

    4. Juste pour être sûr, fopen retourne une adresse, d'où la nécessité de le lier à un pointeur?
    Source 1: http://www.zentut.com/c-tutorial/c-read-text-file/
    Source 2: http://www.cplusplus.com/reference/cstdio/fopen/

    5. Ce que j'en comprend de ton 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
    #include <stdio.h>
    #include <string.h>
    *
    int main() {
    	char chaine[]="15 ; Aline";   // initialisation d'un tableau de charactère
    	char *note;     // initialisation d'un pointeur note
    	char *nom;     // initialisation d'un pointeur note
    	char *pt;     // initialisation d'un pointeur note
    *
    	pt=strchr(chaine, ';');     //tu fais pointé pt sur ";" / tu enregistres l'adresse de ";" dans le pointeur pt
    	if (pt != NULL) {     // tu mets en place une condition pour éviter les bugs, dans le cas ou pt serait null/ quel chaine de caractère ne contiendrait pas ";"
    		*pt='\0';     // tu remplaces ";" par "\0" signifiant à la machine que le tableau s'arrête ici
    		note=chaine;     // tu attribues le contenu du tableau à au pointeur note, qui prend l'adresse du premier caractère  
    		nom=pt+1;     // tu attribues la chaine de caractère orpheline au pointeur nom, qui prend l'adresse du premier caractère
    		printf("nom=[%s], note=[%s]\n", nom, note);     // impression écran du résultat
    	}
    }

  7. #7
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Redgard Voir le message
    1. Ce que je retiens des pointeur:
    Nom : c-pointers.png
Affichages : 704
Taille : 3,3 Ko
    "px = &x" == "*px = x" == "px = *x"

    Int x = 10
    > x = 10
    >*x = 28FF1C

    Int *px = x
    >*px = x = 10
    > px = *x = 28FF1C
    Si je reprends ton exemple, tu écris int x=10. Ok. Donc tu définis une variable "x" (située à l'adresse "28FF1C") qui vaut 10. Jusque là ça va.
    Ensuite tu écris *x=28FF1C. Peut-être qu'effectivement à l'adresse "10" (ou 0x000a) il y a la valeur "28FF1C" mais 1) ce n'est pas garanti et 2) de toute façon, le C ne saura pas interpréter *x car il ne connait pas la nature de cette valeur (int, char, float, double ?)

    Ensuite tu écris int *px=x. C'est peu orthodoxe mais là encore fondamentalement ça peut le faire (en forçant un peu). Donc tu stockes la valeur "10" dans le pointeur "px".
    Mais ensuite tu écris px=*x et là ça ne va plus. Tu as écrit px=x donc px vaut la valeur de x et non ce qui y est pointé.

    En fait, tu confonds l'écriture int *pt=10 (ici définition de variable) et *pt=10 (ici affectation). Elles sont semblables, mais ne signifient pas la même chose.

    En écrivant int *pt=10, tu déclares un pointeur "pt" dont le pointé est de type "int" ; mais tu affectes la valeur "10" à "pt" et non à ce vers quoi il pointe. C'est comme si tu écrivais int *pt; pt=10;.
    En écrivant ensuite *pt=10, là tu affectes la valeur 10 à la case pointée par pt (donc à "étoile pt" et non à "pt").

    Voici une série d'instructions plus correctes
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int v=123;     // v est une variable, qui aura par exemple l'adresse "0xff01", et qui contient la valeur "123".
    int *pt=&v;              // pt est une variable, qui aura par exemple l'adresse "0xff02", et qui contient la valeur "0xff01"
    int **dpt=&pt;        // dpt est une variable, qui aura par exemple l'adresse "0xff03", et qui contient la valeur "0xff02"
     
    printf("%d\n", v);    // j'affiche la valeur de v => 123
    printf("%d\n", *pt);  // j'affiche la valeur de ce qu'il y a à l'adresse "0xff01". Or, à cette adresse il y a la valeur 123
    printf("%d\n", **dpt);
    /* j'affiche la valeur de ce qu'il y a à l'adresse dont la valeur est ce qu'il y a à l'adresse "0xff02".
    Or, à l'adresse "0xff02" il y a la valeur "0xff01"; et à l'adresse "0xff01" il y a la valeur 123 */

    Citation Envoyé par Redgard Voir le message
    2. Quelle est l'intérêt de définir ses fonctions en dessous de main et de la déclarer au dessus? La lisibilité?
    Si a() appelle b() alors tu dois d'abord déclarer b() avant que le compilo ne tombe sur l'instruction qui l'appelle (donc avant d'écrire a()).
    Si on écrit le code de b() sans l'avoir déclaré alors cela équivaut à une déclaration donc généralement on peut écrire les fonctions sans les déclarer pourvu qu'on les écrive dans le bon ordre.
    Mais si on n'a pas envie de se préoccuper de l'ordre, ou bien si c'est impossible (a qui appelle b et b qui appelle a) alors il faut les déclarer au préalable. Perso j'ai choisi cette solution...

    Citation Envoyé par Redgard Voir le message
    3. Quelle est la différence entre ces deux notations? "Int* pa" et "int *pa"
    Aucune.

    Citation Envoyé par Redgard Voir le message
    4. Juste pour être sûr, fopen retourne une adresse, d'où la nécessité de le lier à un pointeur?
    Source 1: http://www.zentut.com/c-tutorial/c-read-text-file/
    Source 2: http://www.cplusplus.com/reference/cstdio/fopen/
    Exactement. Le terme "pointeur" signifie "variable apte à recevoir une adresse"
    Une adresse étant un nombre, tu pourrais penser qu'écrire int pt=&truc fonctionnerait. Et (à la base) tu n'aurais pas tort. Le seul souci c'est qu'en l'écrivant ainsi, le C ne connait pas la nature de*pt (y a-t-il un char d'un octet ou un double de 8 octets ???).
    Tu es donc obligé de déclarer à la fois que tu vas recevoir une adresse, et à la fois la nature de ce qu'il y a à cette adresse. Si tu veux déclarer par exemple un pointeur sur un double, alors tu écriras double *pt=&truc (ou bien en décomposé double *pt; pt=&truc;). Cela signifie "pt est une variable qui recevra une adresse" et "étoile pt est de type double" et "je stocke l'adresse de truc dans pt".
    Grace à cette façon de déclarer "pt", si tu écris ensuite int var=*pt * 2 le C sait analyser *pt, en extraire les 8 octets qui appartiennent à ce double et le multiplier par 2...

    Citation Envoyé par Redgard Voir le message
    5. Ce que j'en comprend de ton 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
    #include <stdio.h>
    #include <string.h>
    *
    int main() {
    	char chaine[]="15 ; Aline";   // initialisation d'un tableau de charactère - Exact
    	char *note;     // initialisation d'un pointeur note
    	char *nom;     // initialisation d'un pointeur nom
    	char *pt;     // initialisation d'un pointeur pt
    // Exact mais vaut mieux parler de déclaration plutôt qu'initialisation
    
    	pt=strchr(chaine, ';');     //tu fais pointé pt sur ";" / tu enregistres l'adresse de ";" dans le pointeur pt - Exact
    	if (pt != NULL) {     // tu mets en place une condition pour éviter les bugs, dans le cas ou pt serait null/ quel chaine de caractère ne contiendrait pas ";" - Exact
    		*pt='\0';     // tu remplaces ";" par "\0" signifiant à la machine que le tableau s'arrête ici - Pas vraiment à la machine, mais plutôt à toute fonction du C qui voudrait utiliser ce tableau comme une chaine de caractères
    		note=chaine;     // tu attribues le contenu du tableau à au pointeur note, qui prend l'adresse du premier caractère  - Pas tout le contenu du tableau, juste son adresse (ou plus exactement l'adresse de son premier élément)
    		nom=pt+1;     // tu attribues la chaine de caractère orpheline au pointeur nom, qui prend l'adresse du premier caractère - Le pointeur "nom" se positionne sur l'adresse du caractère qui suit immédiatement le ";"
    		printf("nom=[%s], note=[%s]\n", nom, note);     // impression écran du résultat
    /*
    Exact. Et comme le tableau "nom" (qui correspond aussi au tableau "chaine") s'arrête au premier '\0', le printf() s'arrêtera à celui que j'ai mis (au ";").
    Et comme le tableau "note" (dont le point de départ commence dans le tableau "chaine" mais après le ";") et que ce tableau "chaine" contenait déjà un '\0' initial qui n'a pas été enlevé, le second printf() s'arrêtera à ce second '\0'
    */
    	}
    }
    Mes remarques en rouge dans ton code
    Mon Tutoriel sur la programmation «Python»
    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
    Et on poste ses codes entre balises [code] et [/code]

  8. #8
    Membre du Club Avatar de Redgard
    Homme Profil pro
    x
    Inscrit en
    Décembre 2014
    Messages
    90
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : x

    Informations forums :
    Inscription : Décembre 2014
    Messages : 90
    Points : 60
    Points
    60
    Par défaut
    Tu n'aurais pas un bon IDE à conseiller, facile et rapide d'utilisation pour un débutant?

    Parce que je passais avant par visual studio pour l'écriture du code et un compilateur en ligne pour la compilation, mais ça me limite dans mes manipulations.
    Donc je me suis décidé à passer sur un IDE pour le C, mais je n'arrive pas à faire marcher Eclipse et CodeBlock est en train de me rendre dingue...
    Nom : C.PNG
Affichages : 537
Taille : 109,0 Ko

    J'installe tout ce qui est "dev" sur mon second disque dur, dans un dossier dédié, or j'ai l'impression ça contribue à mon problème...
    Nom : C1.PNG
Affichages : 501
Taille : 21,8 Ko

  9. #9
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Redgard Voir le message
    Tu n'aurais pas un bon IDE à conseiller, facile et rapide d'utilisation pour un débutant?
    "vi" sous Linux. Et "make" pour compiler. Désolé, je ne bosse pas avec un IDE. Eclipse a très bonne réputation mais ce n'est pas ma partie (ni celle de cette rubrique). Il doit y avoir une section dédiée sur ce fofo...

    PS: je suis revenu sur ton premier dessin...
    Mon Tutoriel sur la programmation «Python»
    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
    Et on poste ses codes entre balises [code] et [/code]

  10. #10
    Membre du Club Avatar de Redgard
    Homme Profil pro
    x
    Inscrit en
    Décembre 2014
    Messages
    90
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : x

    Informations forums :
    Inscription : Décembre 2014
    Messages : 90
    Points : 60
    Points
    60
    Par défaut
    Sérieusement, je sais plus quoi faire... j'ai déjà été voir la catégorie parlant des compilateurs et autre sur Developpez.com, c'est ce qui m'a orienté vers Mingw et Eclipse.
    Sauf que je n'arrive pas à faire marcher Eclipse avec Mingw, malgré les tutos (obsolet?) trouvé sur le net. A l'heure actuelle, Eclipse m'affiche des erreurs d'intégration pour mes #include <stdio.h>, ce qui doit être lié au fait que j'arrive pas à intégrer Mingw.
    Je me suis ensuite tourné vers codeBlock suite à zentut.com, que j'ai réussi à faire marcher sans problème avec Mingw, mais ayant certaines histoire*, j'ai décidé de me tourner vers MingW64, qui est un compilateur plus récent et qui support le 64bits. Mais là encore, malgré les tutos, je n'arrive pas à le faire marcher.

    Au final, j'ai passé des heures à chercher sur internet, sans trouver de solutions. Je suis dégouté. Comment tu veux que les gens aient envie d'apprendre le C dans de telle condition. Je comprends pourquoi ils nous font passer par des compilateurs en ligne...

    *histoire:
    "je déclare une boucle for(int i=0, i < ..., i++){} et il m'affiche une erreur comme quoi ma variable "i" n'est pas déclaré... -_- I hate you so much!"

    ====================================

    Je me suis planté dans mes notations, confondant avec la lecture des équations. ce que je voulais dire:

    "Int x = 10
    > x == 10
    >*x == 28FF1C

    Int *px = x
    >*px == x == 10
    > px == *x == 28FF1C
    "

    ====================================

    Sérieusement avec toutes ces histoires, je me demande si j'essaie pas de faire trop compliqué, et que le problème viendrait de moi :/ ...

    à la base, l'énnoncé de l'excercisse est le suivant:

    À l'occasion de son anniversaire, le ministre de la Très Haute Éducation Très Nationale décide d'augmenter de deux points les notes de tous les élèves de la République.

    Écrire un programme qui lit un fichier nommé notes.txt qui contient sur chaque ligne une note (float) suivie d'un point-virgule et du nom d'un élève et écrit un fichier nommé anniversaire.txt qui contient les mêmes informations avec chaque note augmentée de 2 points (sans toutefois dépasser 20).

    Voici un exemple de fichier notes.txt . Notez que le fichier se termine par une fin de ligne en dernier caractère.

    12;albert
    8;martine
    11;marguerite
    19;sofia
    ====================================

    Cette histoire de compilateur & IDE m'a fait pété un plomb, le mooc finit le 4 janvier, j'ai pas de temps à perdre! Pour éviter de tout abandonner, j'ai tout taper d'une traite sans me poser la question de si ce que j'écrivais était bon.
    Je suis un peu désespéré, lasse de la situation -_-. Est-ce que tu pourrais jeter un oeil à mon code (faveur)? J'ai pas envie de toucher à un compilateur là...

    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
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    #include <stdio.h>
    #include <stdlib.h>
     
     
    // ================================= STRUCTURE =================================
    // tableau de structure stockant une personne et sa note
    struct personne
    {
    	float note;
    	char nom[30];
    };
     
    // ================================= FONCTION APPELEE =================================
    //Calcule la taille du tableau.
    int SizeFile(FILE source) {
    	char tab[50];
    	int size = 0;
     
    	while (fgets(tab, 50, source) = !NULL)
    	{
    		size++;
    	}
     
    	return size;
    }
     
     
    //récupère et ajoute les données d'un fichier source dans un tableau de structure
    void Recuperateur(FILE source, char Tableau[][1]) {
    	char tab[50];
    	int i = 0;
     
    	while (fgets(tab, 50, source) =! NULL)  // j'aurais bien utilisé une boucle for*
    	{
    		tab = Tableau[i][1];
    		i++;		
    	}
    }
     
    //Copie les données d'un simple tableau dans un tableau de structure
    void Copieur(char simpTab[][1], struct personne structTab) {
    	int i = 0;
     
    	char *note;
    	char *nom;
    	char *pt;
     
    	while (simpTab[i][1] == NULL) 
    	{
    		//division des données du tableau en remplaçant le caractère ';' par '\0'
    		pt = strchr(simpTab[i][1], ';');
    		if (pt != NULL)
    		{
    			*pt = '\0';
    			note = simpTab[i][1];
    			nom = pt + 1;
    		}
     
    		//incrémentation des données au tableau de structure
    		structTab[i].note = *note;
    		structTab[i].nom = *nom;
     
    		i++;
    	}
    }
     
    // incrémente un nombre dans un tableau
    void Incrementateur(struct personne structTab) {
     
    	// incrémentation à la variable note.
    	for (int i = 0; structTab[i] == NULL; i++)
    	{
    		if (tab[i].note < 19) {
    			tab[i].note = tab[i].note + 2
    		}
    		else
    		{
    			tab[i].note = 20
    		}
    	}
    }
     
    // fonction copiant les données d'un tableau de structure dans un fichier destination.
    void Ecriveur(struct personne structTab; FILE dest) {
    	char simpTab[50];
     
    	for (int i = 0; structTab[i].note == NULL; i++)
    	{
    		simpTab = structTab[i].note + "; " + structTab[i].nom;
    		fputs (simpTab, dest)
    	}
     
    }
     
     
    // ================================= FONCTION MAIN =================================
    int main() {
    	// déclaration des variables;
    	FILE *fileO, *fileW;
    	int size ;
    	char simpTab[size][1];
     
    	//déclaration d'un tableau de structure personne sous le pointeur "tab".
    	struct personne *tab;
     
    	// lit un fichier note.txt associé au pointeur fileO et vérifie la présence du premier
    	if ((fileO = fopen("/note.txt", "r")) == NULL)
    	{
    		printf("impossible d'ouvrir en lecture le fichier note.txt !\n");
    		exit(0);
    	}
    	// écrit un fichier anniversaire.txt associé au pointeur fileW et vérifie la présence du premier
    	if ((fileW = fopen("/anniversaire.txt", "w"))) == NULL)
    	{
    		printf("impossible d'ouvrir en écriture le fichier anniversaire.txt !\n");
    		exit(1);
    	}
     
    	//calcul le nombre de ligne du fichier
    	size = SizeFile(*fileO);
     
    	//déclaration de la taille du tableau de structure
    	tab = malloc(size * sizeof(struct personne));
     
    	//récupération du contenu du fichier note.txt dans un tableau
    	Recuperateur(*fileO, *simpTab);
     
    	//Copie du tableau dans le tableau de structure
    	Copieur(simpTab, *tab);
     
    	//Incrémentation de deux points à la variable note du tableau de structure
    	Incrementateur(*tab);
     
    	//Ecrit le contenu du tableau de structure dans le fichier .txt de sortie 
    	Ecriveur(*tab, *fileW);
     
    	//Fermeture des streams
    	fclose(fileO);
    	fclose(fileW);
     
    	return 0;
    }

  11. #11
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Redgard Voir le message
    *histoire:
    "je déclare une boucle for(int i=0, i < ..., i++){} et il m'affiche une erreur comme quoi ma variable "i" n'est pas déclaré... -_- I hate you so much!"[/CODE]
    Oui, ce type de notation (où tu définis la variable dans le for) ne fonctionne qu'avec les compilateurs récents.

    Citation Envoyé par Redgard Voir le message
    Je me suis planté dans mes notations, confondant avec la lecture des équations.[/CODE]
    Oui enfin d'accord. Mais cela ne t'interdit pas de lire ce que j'ai écrit !!!

    Citation Envoyé par Redgard Voir le message
    "Int x = 10
    > x == 10
    >*x == 28FF1C &x == 28FF1C

    Int *px = x int *px=&x
    >*px == x == 10
    > px == *x == 28FF1C px == &x == 28FF1C
    [/CODE]
    Mes corrections en rouge.


    Citation Envoyé par Redgard Voir le message
    Est-ce que tu pourrais jeter un oeil à mon code (faveur)? J'ai pas envie de toucher à un compilateur là...

    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
    #include <stdio.h>
    #include <stdlib.h>
    
    
    // ================================= STRUCTURE =================================
    // tableau de structure stockant une personne et sa note
    struct personne
    {
    	float note;           // A ce que j'ai vu dans le fichier, la note semblait entière... Mais bon, c'est un détail
    	char nom[30];
    };
    
    // ================================= FONCTION APPELEE =================================
    //Calcule la taille du tableau.
    int SizeFile(FILE source) {
    	char tab[50 + 1];
    	int size = 0;
    
    	while (fgets(tab, 50 + 1, source) = !NULL)
    	{
    		size++;
    	}
    
    	return size;
    }
    // Ok. Mais pense à écrire "+1" dans tes tailles de chaines. Ca montre que tu as pensé au '\0'.
    
    
    //récupère et ajoute les données d'un fichier source dans un tableau de structure
    void Recuperateur(FILE *source, char Tableau[][1]  /* C'est quoi ce "1" ??? */) {
    	char tab[50];
    	int i = 0;
    
    	while (fgets(tab, 50, source) =! NULL)  // j'aurais bien utilisé une boucle for*   Pourquoi pas...
    	{
    		tab = Tableau[i][1];    // Me semble que t'as inversé les opérandes. Sinon je en vois pas pourquoi tu remplis "tab" juste avant. Ceci dit, tu ne peux pas écrire "truc_complexe=autre_truc_complexe" parce que le C ne sait pas gérer
    		i++;		
    	}
    }
    
    //Copie les données d'un simple tableau dans un tableau de structure
    void Copieur(char simpTab[][1], struct personne structTab) {
    	int i = 0;
    
    	char *note;
    	char *nom;
    	char *pt;
    
    	while (simpTab[i][1] == NULL) 
    	{
    		//division des données du tableau en remplaçant le caractère ';' par '\0'
    		pt = strchr(simpTab[i][1], ';');
    		if (pt != NULL)
    		{
    			*pt = '\0';
    			note = simpTab[i][1];
    			nom = pt + 1;
    		}
    		
    		//incrémentation des données au tableau de structure
    		structTab[i].note = *note;
    		structTab[i].nom = *nom;
    		/*
    				Erreur, tu ne fais ici que copier des pointeurs.
    				Reprends ton propre exemple. Que se passe-t-il si tu écris "py=px" ??? Tu copies simplement une adresse.
    				Tu ne peux pas utiliser "=" pour copier des tableaux. Tu dois les copier élément par élément.
    				Heureusement pour les chaines tu as la fonction "strcpy" qui peut se charger de ce boulot...
    																				*/
    
    
    		i++;
    	}
    }
    
    // incrémente un nombre dans un tableau
    void Incrementateur(struct personne structTab) {
    	
    	// incrémentation à la variable note.
    	for (int i = 0; structTab[i] == NULL; i++)
    	{
    		if (tab[i].note < 19  /* <= 18 serait plus parlant... */) {
    			tab[i].note = tab[i].note + 2
    		}
    		else
    		{
    			tab[i].note = 20
    		}
    	}
    }
    Mes commentaires en rouge. Ta principale erreur est que tu pense pouvoir manipuler un tableau. Or tu ne peux pas. Dès que ça dépasse l'élément simple (int, char, float) le C passe au pointeur. Donc tout ce que tu as, c'est l'adresse du premier élément du tableau.
    Sinon je pige pas le [1]. Un tableau c'est "n" éléments, si tu n'en as qu'un à gérer autant rester à l'élément simple...
    Mon Tutoriel sur la programmation «Python»
    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
    Et on poste ses codes entre balises [code] et [/code]

  12. #12
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Citation Envoyé par Redgard Voir le message
    Au final, j'ai passé des heures à chercher sur internet, sans trouver de solutions. Je suis dégouté. Comment tu veux que les gens aient envie d'apprendre le C dans de telle condition. Je comprends pourquoi ils nous font passer par des compilateurs en ligne... [...] Cette histoire de compilateur & IDE m'a fait pété un plomb, le mooc finit le 4 janvier, j'ai pas de temps à perdre! Pour éviter de tout abandonner, j'ai tout taper d'une traite sans me poser la question de si ce que j'écrivais était bon.
    Je suis un peu désespéré, lasse de la situation -_-. Est-ce que tu pourrais jeter un oeil à mon code (faveur)? J'ai pas envie de toucher à un compilateur là...
    Je compatis et comprends ta frustration. Là se trouve ton erreur : avant d'utiliser un IDE, il faut comprendre ce que tu fais. Je me permets de me citer moi-même, parce que ce problème revient régulièrement sur le forum :

    Citation Envoyé par Matt_Houston Voir le message
    Le truc avec les IDE c'est que ce sont des logiciels destinés à la productivité, visant les programmeurs confirmés. Ce ne sont pas des outils d'apprentissage adaptés aux débutants. Ils abstraient et automatisent beaucoup d'aspects liés au modèle de compilation C qu'il est important de connaître pour maîtriser ce que l'on fait.
    N'utilise pas d'IDE. Ce n'est pas de cette manière qu'on apprend à programmer efficacement. Pour ce faire il te faut - comme l'a précisé Sve@r - un éditeur de texte et une ligne de commande (l'IDE en ligne est également une bonne alternative !).

    Windows ne te facilite pas les choses. Il s'agit d'un environnement par défaut peu adapté au développement (et sans même vraiment troller, peu adapté à quoi que ce soit au final.. ). Il y a quelques solutions pour développer sans IDE sous Windows. Je te conseille d'essayer MSYS2 en premier, j'en parle ici et .


    Citation Envoyé par Sve@r Voir le message
    Oui, ce type de notation (où tu définis la variable dans le for) ne fonctionne qu'avec les compilateurs récents.
    À savoir qu'ici récent signifie : postérieur à.. 1999.

  13. #13
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Matt_Houston Voir le message
    (et sans même vraiment troller, peu adapté à quoi que ce soit au final.. )
    Si, il est adapté aux jeux. Pourquoi tu crois qu'on met du windows dans tout les ministères ? Parce que les chefs (qui pannent que dalle à l'informatique), quand ils ont besoin de conseil, demandent à leurs gosses qui leur répondent "windows c'est super car il y a beaucoup de jeux"...


    Citation Envoyé par Matt_Houston Voir le message
    À savoir qu'ici récent signifie : postérieur à.. 1999.
    Oui t'as raison. J'aurais dû plutôt dire "ne fonctionne que si on précise au compilateur que l'on veut activer cette possibilité (avec -std=c99, -std=gnu99, -std=c11 ou -std=gnu11)"...
    Mon Tutoriel sur la programmation «Python»
    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
    Et on poste ses codes entre balises [code] et [/code]

  14. #14
    Membre du Club Avatar de Redgard
    Homme Profil pro
    x
    Inscrit en
    Décembre 2014
    Messages
    90
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : x

    Informations forums :
    Inscription : Décembre 2014
    Messages : 90
    Points : 60
    Points
    60
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Oui, ce type de notation (où tu définis la variable dans le for) ne fonctionne qu'avec les compilateurs récents.
    Tu ne me l'aurais pas dit, ça m'aurait pris beaucoup de temps de trouver cette information sur internet.

    Citation Envoyé par Sve@r Voir le message
    Oui enfin d'accord. Mais cela ne t'interdit pas de lire ce que j'ai écrit !!!
    Je suis en train de relire, mais je pense que je vais y aller par écrit.

    Citation Envoyé par Sve@r Voir le message
    Mes commentaires en rouge. Ta principale erreur est que tu pense pouvoir manipuler un tableau. Or tu ne peux pas. Dès que ça dépasse l'élément simple (int, char, float) le C passe au pointeur. Donc tout ce que tu as, c'est l'adresse du premier élément du tableau.
    Le problème est que je ne sais pas comment je suis censé faire passer les données dans les variables de mes fonctions, et je suis pas encore tombé sur quelques choses en parlant clairemant.

    Citation Envoyé par Sve@r Voir le message
    Sinon je pige pas le [1]. Un tableau c'est "n" éléments, si tu n'en as qu'un à gérer autant rester à l'élément simple...
    J'utilise un tableau multidimensionnel. Je suis tombé sur ça: http://www.cplusplus.com/doc/tutorial/arrays/
    Tu en penses quoi?

    Citation Envoyé par Matt_Houston Voir le message
    Je compatis et comprends ta frustration. Là se trouve ton erreur : avant d'utiliser un IDE, il faut comprendre ce que tu fais. Je me permets de me citer moi-même, parce que ce problème revient régulièrement sur le forum :
    Je pense que ça dépend aussi pas mal des languages/ du type de langage, je m'explique:
    - J'ai commencé sur le Java et un IDE de base est fourni par défaut avec le pack de développement, permettant le traitement de texte et l'interprétation du code. (J'ai arrêté d'apprendre ce langage parce que je m'y sentais pas bien, que j'avais l'impression qu'il n'était pas optimisé pour là ou je voulais aller.)
    - J'ai ensuite switché sur le C# et aie utilisé Visual studio, et le truc marche vraiment bien. ( J'aime bien le langage et sa flexibilité, mais j'ai fait un pause, car je sentais qu'il me manquait des bases, ce qui m'a poussé faire le C.)

    Dans ma formation en C, on nous a parlé des différents outils de développement et on nous fait utiliser un compilateur en ligne, mais on nous a pas expliqué pourquoi ce choix. Ils nous ont donnés aucun conseil à ce niveau là.

    Citation Envoyé par Matt_Houston Voir le message
    un éditeur de texte et une ligne de commande (l'IDE en ligne est également une bonne alternative !).
    Jamais entendu parlé... tu peux développer/ conseiller? ça m'évitera d'en essayer 5 mauvais avant d'en trouver un bon...

    Citation Envoyé par Matt_Houston Voir le message
    Windows ne te facilite pas les choses. Il s'agit d'un environnement par défaut peu adapté au développement (et sans même vraiment troller, peu adapté à quoi que ce soit au final.. ). Il y a quelques solutions pour développer sans IDE sous Windows. Je te conseille d'essayer MSYS2 en premier, j'en parle ici et .
    Je vais checker ça.
    J'ai pas trop envie de m'encombrer d'un dualboot. J'ai pas mal fait mumuse avec la console sous archlinux, via un serveur virtuel, et je n'avais aucun problème avec; Mais pour une raison que j'ignore, je déteste la console sous windows.
    Si je devais vraiment donner un ressenti, les mots qui me viennent sont "elle est pas intuitive"... Maintenant j'ai pas beaucoup d'expérience donc mon avis est pas très critique.

    Citation Envoyé par Matt_Houston Voir le message
    À savoir qu'ici récent signifie : postérieur à.. 1999.
    lol, juste presque 20 ans... Concrètement, je ne fais qu'appliquer ce qu'on m'a appris, donc quand j'ai été confronté à ce problème, j'ai cru que l'IDE faisait n'importe quoi.
    ça doit expliquer pourquoi rien ne marchait dans mon code, vu que j'utilise des fonctions trop récente (sans parler des erreurs de débutants)

    C'est vraiment ça qui est important! Quand tu apprends quelques choses, tu as besoin de savoir que les outils que tu utilises marche, parce que ça t'évite de faire des erreurs d'attribution. Quelle sont les chances que je sache que c'est une histoire de norme quand je pense que c'est juste mon IDE qui fait n'importe quoi? De même avec certains compilateur en ligne, qui marche dans certains cas et pas dans d'autres.

    J'ai laché le truc pendant un jour pour faire une pause, mais j'étais plus sûr de rien après toutes ces histoires de compilateurs. Combien de personnes abandonnent à cause de situation similaire?

    Citation Envoyé par Sve@r Voir le message
    Si, il est adapté aux jeux. Pourquoi tu crois qu'on met du windows dans tout les ministères ? Parce que les chefs (qui pannent que dalle à l'informatique), quand ils ont besoin de conseil, demandent à leurs gosses qui leur répondent "windows c'est super car il y a beaucoup de jeux"...
    Si je vois l'idée, je pense que c'est un peu trop facile.

    Comme tu l'as dit le chef (mais aussi la majorité de ses employers?) comprennent rien à l'informatique. A ton avis, qu'est ce qui est le plus facile à utiliser, demande le moins d'apprentissage ( =formation payée par l'entreprise) et nécessite le moins de temps à set up? un OS que même les enfants peuvent utiliser ou un OS qui demande d'apprendre des commandes de base et d'installer un interface? Et je parle pas des logiciels disponible.

    Pour être un peu moins pescimiste:
    On peut qu'en même voir une amélioration par l'apparition de parc tournant sous Ubuntu dans certaines école, mais c'est bien parce qu'un effort a été fourni sur la facilité de set up et la prise en main de l'OS.

    Maintenant, ça reste des initiatives occasionnelles. Qu'est ce qui est le plus facile, prendre ce que l'on connait ou aller chercher que l'on connait pas?

    Citation Envoyé par Sve@r Voir le message
    (avec -std=c99, -std=gnu99, -std=c11 ou -std=gnu11)"...
    C'est la commande, pour demander l'utilisation d'une normes particulière en C? (ils nous avaient parlé des normes au début de la formation, dans l'historique du langage et du développement de la programation)

    ===================

    Je vais finir cette formation et après je repasserai surement un peu sur tout.
    je cherckerai sur developpez.net et sur http://www.zentut.com/c-tutorial/int...to-c-language/, qui m'a l'air pas mal

    ===================
    EDIT:

    J'ai pris mon courage à deux mains et j'ai review ta correction. J'avais vraiment pas envie de regarder mon code…

    Tu as raison, j'ai passer la variable note de float à integer

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // tableau de structure stockant une personne et sa note
    struct personne
    {
    	int note; 
    	char nom[30];
    };

    Pour "\0", c'est un coups à prendre que je n'ai pas encore pris. Ils n'en ont presque pas parlé dans la formation. Ils ont juste dit que les tableau finissait par "\0 " sans parler de la pratique. Quelle intérêt de le préciser?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //Calcule la taille du tableau.
    int SizeFile(FILE *source) {
    	char tab[50 + 1];
    	int size = 0;
     
    	while (fgets(tab, 50 + 1, source) =! NULL)
    	{
    		size++;
    	}
     
    	return size;
    }

    Pour le tableau[][1], je savais pas comment déclarer un tableau à deux dimensions dans les variables d'une fonction.
    En regardant sur internet, cette déclaration est apparemment valide. Tu vas juste restreindre le type de tableau accepté par ta fonction.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //récupère et ajoute les données d'un fichier source dans un tableau à deux dimensions
    void Recuperateur(FILE *source, char tableau[][1]) {
    	char tab[50 + 1];
     
    	//récupère et copie un ligne de texte d'un tableau "tab" dans un tableau à deux dimensions
    	for (int i = 0, fgets(tab, 50 + 1, source) =! NULL, i++)
    	{
    		strcpy(tableau[i][1], tab);
    	}
    }
    Pour la boucle for, je ne l'ai pas utilisé parce qu'à cause de cette histoire de compilateur, je ne savais plus comment je devais faire.
    Et effectivement, j'ai inversé l'incrémentation des tableaux. "tab = tableau[i][1]" aurait dû être "tableau[i][1] = tab". J'inverse souvent, problème de dyslexie.
    Je l'ai remplacé par une strcpy, vu ta remarque. Je sais pas si je peux le faire comme ça, avec un pointeur... Je n'ai pas trouvé de contre indication.


    Pour l'utilisation des pointeurs dans la copie d'un tableau, je suis partie du principe que note contient l'adresse et que *note contient le tableau, d'où mon erreur.
    Mais c'est vrai que la manière dont les tableaux sont stockés dans la mémoire (une adresse par caractère) empêche cette pratique.
    En faisant ça, je vais juste copier le premier caractère du tableau, non?
    J'ai utilisé strcpy (string copy) une fois, je l'avais totalement oublié.
    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
    //Copie les données d'un simple tableau dans un tableau de structure
    void Copieur(char simpTab[][], struct personne structTab) {
    	int i = 0;
     
    	char *note;
    	char *nom;
    	char *pt;
     
    	while (simpTab[i][1] == NULL) 
    	{
    		//division des données du tableau en remplaçant le caractère ';' par '\0'
    		pt = strchr(simpTab[i][1], ';');
    		if (pt != NULL)
    		{
    			*pt = '\0';
    			note = simpTab[i][1];
    			nom = pt + 1;
    		}
     
    		//incrémentation des données au tableau de structure
    		structTab[i].note = atoi(note);
    		strcpy(structTab[i].nom, nom);
     
    		i++;
    	}
    }
    Est-ce que je peux utiliser un pointeur pour copier une phrase dans un tableau, comme ci-dessus?


    Pour le "tab[i].note < 19", je savais pas trop comment l'exprimer et je voulais le faire en le moins de caractère possible; Mais c'est peut être une idée de merde?

    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
    // incrémente un nombre dans un tableau
    void Incrementateur(struct personne structTab) {
     
    	// incrémentation à la variable note.
    	for (int i = 0; structTab[i] == NULL; i++)
    	{
    		if (tab[i].note <= 18) {
    			tab[i].note = tab[i].note + 2
    		}
    		else
    		{
    			tab[i].note = 20
    		}
    	}
    }
    J'ai pas mal chipoté, en regardant différentes choses sur internet, et j'ai obtenu ça en regardant sur internet:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // fonction copiant les données d'un tableau de structure dans un fichier destination.
    void Ecriveur(struct personne structTab; FILE dest) {
    	char simpTab[50 + 1];
     
    	for (int i = 0; structTab[i].note == NULL; i++)
    	{
    		sprintf(simpTab, "%d; %s", structTab[i].note, structTab[i].nom);
    		fputs (simpTab, dest)
    	}
     
    }
    J'ai voulu au début utiliser itoa, mais n'étant pas compris dans l'ANSCI, j'ai préféré pas prendre de risque et j'ai continuer à chercher.

  15. #15
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Redgard Voir le message
    Le problème est que je ne sais pas comment je suis censé faire passer les données dans les variables de mes fonctions, et je suis pas encore tombé sur quelques choses en parlant clairemant.
    Pas compliqué
    Si une fonction attend un nombre pour juste l'utiliser, tu lui fais passer ce nombre => carre(5). Dans la fonction, il faut juste définir dans quoi ce nombre ira (ici un int) => int carre(int x) {return x*x;}. Ensuite, tu peux utiliser ce "x" qui vaut (ici) 5.
    Si ton nombre initial se trouve dans une variable, alors tu passes la variable à la fonction. Son contenu sera recopié dans la variable de la fonction => int i=5; carre(i). Attention, c'est important de bien se rappeler que le contenu de la variable est recopié.
    Si ton nombre initial se trouve à un endroit de la mémoire et que tu n'as que l'adresse de cet endroit (donc un pointeur) ben tu passes à ta fonction le pointé => int i=5; int *pt=&i; carre(*pt).

    Si maintenant ta fonction attend une variable pour la modifier, là ça se complique un poil. Le souci, c'est que la variable est recopiée dans la fonction. Donc la variable initiale (ici "i" dans mon premier exemple) n'est pas modifiable dans la fonction (en fait elle n'est même pas vue).
    La solution: tu ne passes pas la variable à la fonction, mais son adresse. Cette adresse sera recopiée dans la fonction (dans une variable apte à la recevoir => un pointeur) mais la mémoire d'un programme étant globale, taper à cette adresse te permettra de modifier la valeur qui s'y trouve. Et du côté de l'appelant, cette adresse étant reliée à une variable, la variable sera modifiée par ricochet.
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void init(int *pt  /* pt est de type "int étoile" et "étoile pt" est de type "int" */) {
        *pt=0;   // Je modifie "étoile pt" donc un int
    }
     
    int main() {
        int i;
        int *pt=&i;     // Attention, "&i" ira dans "pt" et non "*pt" !!!
        init(&i);         // &i étant de type "int étoile", c'est correct
        init(pt);         // pt étant de type "int étoile", c'est tout aussi correct
    }

    Pour un tableau on entre dans un autre concept qui va de pair: le C ne sait pas manipuler les tableaux. Tout ce qu'il sait, c'est manipuler une case mémoire (quand je dis "manipuler" je veux parler d'utiliser la valeur qui s'y trouve ou son adresse).
    Mais le C te garantit que les différentes cases d'un tableau se suivent toutes en mémoire.
    Il s'ensuit que si tu connais l'adresse de la première case d'un tableau, tu as sa valeur. Et en passant ensuite à l'adresse suivante, tu peux récupérer la valeur de cette seconde case. Et etc jusqu'à la fin du tableau.
    De plus, le C t'offre un raccourci avec le nom du tableau car ce nom équivaut à l'adresse du premier élément. Autrement dit, dans char tab[10] alors tab == &tab[0]. Et par extension, (tab+n) == &tab[n]. Et par extension, *(tab+n) == *(&tab[n]) mais l'opération "*&" (qui pourait se traduire par "va regarder la valeur de la case dont l'adresse est l'adresse de tab[n]) s'annule donc *(tab+n) == tab[n]. C'est pour ça qu'on dit qu'il y a équivalence entre tableau et pointeur.

    Exemple de fonction qui affiche un tableau d'int

    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
    void affiche(int *tab, int n) {
        int i;
        int *pt;
        for (i=0, pt=tab; i < n; i++, pt++) {
            printf("La valeur %d vaut %d\n", i, tab[i]);
            printf("La valeur %d vaut %d\n", i, *(tab + i));
            printf("La valeur %d vaut %d\n", i, *pt);
       }
    }
     
    int main() {
        int tab[]={1, 3, 5, 7, 9, 11};
        affiche(tab, 6);
        affiche(&tab[0], 6);
        affiche(tab + 2, 4);
        affiche(&tab[2], 4);
    }

    Citation Envoyé par Redgard Voir le message
    J'utilise un tableau multidimensionnel. Je suis tombé sur ça: http://www.cplusplus.com/doc/tutorial/arrays/
    Tu en penses quoi?
    Du tuto ? J'en sais rien, suis pas allé voir. Du tableau multidimensionnel ? Pourquoi faire ? Tu as "n" élèves donc (selon moi) un tableau en une dimension suffit. Si par exemple j'écris un élève par ligne, alors j'ai au final une seule colonne et non un carré. D'ailleurs tu dois bien t'en rendre compte vu que ta seconde dimension est à "1" (généralement définir un int tab[1] est assez absurde vu qu'on peut faire la même chose avec un int i).
    Il est vrai qu'un élève se découpe en "un nom + une note". Donc c'est vrai que si j'écris les noms dans une première colonne et les notes dans une seconde, ça me fait un carré. Mais la seconde dimension est déjà donnée par la structure (qui contient bien 2 éléments !!!)
    Donc un simple tableau de structures devrait suffire... (je dis "devrais" par politesse parce que de fait, c'est totalement sufffisant).

    Citation Envoyé par Redgard Voir le message
    J'ai pas trop envie de m'encombrer d'un dualboot.
    Tu connais "VirtualBox" ??? Tu peux simuler un ordi intégral avec ça. Moi c'est ce que j'utilise. Je virtualise ainsi un XP (parce que j'ai une imprimante Canon LBP 3200 et que cette faignasse de Canon n'a pas juger bon d'écrire de driver Seven pour son client que j'ai été mais que je ne vais certainement pas me laisser faire donc quand je veux imprimer me suffit de lancer le XP virtualisé et imprimer de là sur l'USB virtuel relié à l'USB physique). Je virtualise aussi un Seven parce que parfois je veux tester un programme sans l'installer sur ma machine physique. Je virtualise aussi un Debian8 pour mon travail, un Debian9 pour tester (jusqu'au moment où je jugerai que ça va et transfèrerai tout mon home Debian8). Je virtualise aussi un Knoppix (parce que parfois pour aller taper avec finesse sur les autres disques virtualisés c'est ce qu'il y a de mieux). Je virtualise aussi Android parce que j'aimerais bien écrire des programmes pour cet OS. Bref avec un seul OS j'accède (sans dual boot) à tous les autres.

    Citation Envoyé par Redgard Voir le message
    Mais pour une raison que j'ignore, je déteste la console sous windows.
    Si je devais vraiment donner un ressenti, les mots qui me viennent sont "elle est pas intuitive"... Maintenant j'ai pas beaucoup d'expérience donc mon avis est pas très critique.
    Il est super !!! Simple et naturel. C'est vrai que face à la console Linux (où tu peux choisir la police de caractère, la couleur du texte, la couleur du fond et même le taux de transparence pour programmer bien confortablement), quand tu vois ce truc en blanc sur fond noir qui se pose comme une bouse, tu sens bien que les programmeurs zindow l'ont mis juste pour dire que eux aussi ils ont un terminal même si tu perds 1/10° par oeuil à chaque minute que tu l'utilises...

    Citation Envoyé par Redgard Voir le message
    C'est la commande, pour demander l'utilisation d'une normes particulière en C? (ils nous avaient parlé des normes au début de la formation, dans l'historique du langage et du développement de la programation)
    Oui, la commande "cc" sous Linux qui permet de compiler un source. Syntaxe: cc -std=c99 source.c -o executable.

    Citation Envoyé par Redgard Voir le message
    Pour "\0", c'est un coups à prendre que je n'ai pas encore pris. Ils n'en ont presque pas parlé dans la formation. Ils ont juste dit que les tableau finissait par "\0 " sans parler de la pratique. Quelle intérêt de le préciser?
    Une chaine c'est déjà un concept trop lourd pour le C. Il ne sait pas gérer. Donc les programmeurs n'ont eu d'autre solution que d'utiliser un tableau de caractères pour pouvoir stocker une chaine.
    Or il faut bien que tu comprennes que le C ne sait pas distinguer les limites d'un tableau dans la mémoire (qui n'est qu'une suite de cases noyée au milieu d'autres cases de la mémoire). Ainsi, bien qu'ayant défini un int tab[10], le compilateur ne t'interdira pas d'aller taper dans tab[125] ou tab[-8]. Et pire, le résultat au niveau de l'exécution peut même se passer sans erreur visible (ni plantage, ni rien). On nomme ce type de comportement un "comportement indéterminé" (parce que non prévisible). Ca peut bien se passer comme ça peut te reformatter ton disque dur (j'exagère mais c'est pour montrer l'idée). Pire encore, ça peut bien se passer mais planter un 29 février. Ou bien se passer les années paires et planter les années impaires. Ou même bien se passer tout court mais avec un résultat totalement incohérent parce que tab[125] correspond pile poil à la zone de la mémoire où tu avais stocké la valeur de pi (et c'est comme ça que ton logiciel d'aide à l'atterrissage fait crasher l'avion). Bref le vrai sens du mot "indéterminé". Et pour débugguer un programme qui plante une fois sur quinze et qui répond n'importe quoi les autres fois...
    Donc (si tu regardes mon exemple où j'affiche tab), je suis obligé de donner à ma fonction 1) le tableau 2) son nombre d'éléments parce que c'est à moi de mettre mes barrières. Ca alourdit mon code et ça l'alourdira à chaque fonction qui aura besoin d'utiliser le tableau (déjà je me suis fait ch... à calculer "6 - 2" quand j'ai demandé à la fonction de commencer au 3° élément).

    Or, si j'ai un tableau de n éléments, ça ne fatiguera pas beaucoup le compilateur si j'en rajoute un "n+1" (de toute façon, les états d'âme d'un compilo...). Et si ce "n+1" contient une valeur spéciale (qui ne peut pas se trouver au naturel dans le tableau), alors je pourrai utiliser cette valeur comme indicateur de fin. Ainsi j'introduis la barrière dans le tableau lui-même et je n'ai plus besoin de la gérer à côté.
    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
    void affiche(int *tab) {
        int i;
        int *pt;
        for (pt=tab, i=0; *pt != -1; pt++, i++) {
            printf("La valeur %d vaut %d\n", i, tab[i]);
            printf("La valeur %d vaut %d\n", i, *(tab + i));
            printf("La valeur %d vaut %d\n", i, *pt);
       }
    }
     
    int main() {
        int tab[]={1, 3, 5, 7, 9, 11, -1};
        affiche(tab);
        affiche(&tab[0]);
        affiche(tab + 2);
        affiche(&tab[2]);
        // Et si je veux brusquement couper mon tableau à 2 éléments: tab[2]=-1
    }

    Voilà. j'ai utilisé "-1" comme barrière (on nomme cet élément une "valeur sentinelle"). Tout ce que j'ai à faire, c'est que mes fonctions cherchent ce "-1".

    C'est exactement ainsi que fonctionne une chaine (sauf que la sentinelle c'est '\0' mais à la limite on s'en fout). Et toutes les fonctions qui traitent une chaine cherchent systématiquement ce '\0' pour s'arrêter. Et toutes les fonctions qui te promettent une chaine veillent bien à positionner ce '\0' quand elles ont fini de la créer. Et même toi tu as le droit de le faire. Exemple
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main() {
        char tab[5 + 1]={'H', 'e', 'l', 'l', 'o'};
        printf("%s\n", tab);     // Interdit !!! Comment printf() sait où s'arrêter ???
        tab[5]='\0';
        printf("%s\n", tab);     // Ok
    }

    La seule chose que tu dois t'assurer, c'est que ton tableau ait bien la place pour qu'on y mette ce '\0' parce que la place c'est toi qui gère. Et généralement on le montre en mettant "+1" (pour que les autres lecteurs de ton code sachent que tu y as pensé).
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main() {
        char tab[5 + 1];
        strcpy(tab, "Hello")
    }
    Attention, ne te méprend pas. Même si tu as l'impression que printf() ou strcpy() traitent une chaine, il n'en est rien. Dans chaque cas les fonctions ne reçoivent que l'adresse du premier élément d'un tableau de caractères. Et ce sont elles qui se chargent de boucler d'élément en élément pour respectivement afficher ou remplir la chaine (comme dans mon exemple d'affichage de tableau d'int).

    Citation Envoyé par Redgard Voir le message
    Pour le "tab[i].note < 19", je savais pas trop comment l'exprimer et je voulais le faire en le moins de caractère possible; Mais c'est peut être une idée de merde?
    Tu es franc donc je vais pas contredire. Non, le compilateur c'est ton esclave donc les caractères qu'il doit bouffer pour bosser tu t'en balance. Ce qui compte, c'est que le relecteur de ton code puisse facilement associer ton code au problème à résoudre. Tu comprendras quand tu auras commencé à coder et que tu reviendras sur un programme 6 mois après.
    Dans l'absolu, c'est vrai que tester "inférieur ou égal" est plus long que tester "inférieur" car il y a 2 opérations à faire. Mais d'une part la seconde opération n'intervient que pour les notes "18", "19" et "20" (donc statistiquement 3/21 fois) et d'autre part, le compilateur (qui est quand-même le chef des esclaves) a à sa disposition un petit scribe nubien qui se nomme "optimiseur". Et donc quand le compilateur se met à bosser, il commence par demander au scribe s'il n'y a pas des trucs qui peuvent s'alléger. Nul doute que dans ce cas là, le scribe remplace en interne "<= 18" par "< 19"...

    Bon, je vais te donner un gros coup de pouce parce que je vois que tu t'accroches bien et que tu ne fais pas partie des branluchons qui viennent ici pleurer "j'ai rien fait pendant 3 mois parce que je ne comprends pas et mon devoir est à rendre demain" (tu bossais encore à 2h du mat !!!).
    Voici un exemple qui te charge tes elèves dans un tableau de structures à partir d'un fichier comme tu l'as montré au début (je l'ai appelé "fic"). Généralement on ne le fait pas mais si les bons intervenants du forum respectent les règles, les intervenants brillants peuvent les transgresser exceptionnellement. Soyons brillant...

    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
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    #include <stdio.h>
    #include <string.h>
     
    typedef struct {
    	int note;
    	char nom[100+1];
    } t_eleve;				// On nomme les types "t_xxx" par convention
     
    int chargeEleve(char *fic, t_eleve *tab) {
    	FILE *fp;
    	char zone[100 + 1];
    	char *c;
    	if ((fp=fopen(fic, "r")) == NULL) return -1;
     
    	while (fgets(zone, 100 + 1, fp) != NULL) {
    		if ((c=strchr(zone, '\n')) != NULL) *c='\0';		// Me supprime ce '\n' qui finit toute ligne d'un fichier
    		if ((c=strchr(zone, ';')) == NULL) continue;		// Au cas où j'aurais une ligne ne contenant pas de ";"...
    		*c='\0';
    		tab->note=atoi(zone);					// Grace au '\0', la zone s'arrête au ";"
    		strcpy(tab->nom, c+1);					// Puisque "c" pointe sur le ";", "c+1" commence fatalement au nom qui le suit...
    		tab++;							// Je passe à l'élément suivant de mon tableau => les mathématiques des pointeurs garantissent que le déplacement ira bien sur la case suivante de la structure
    	}
    	fclose(fp);
    	tab->note=-1;							// Sentinelle
    	tab->nom[0]='\0';						// Je la double pour montrer qu'on peut le faire mais c'est inutile
    	return 0;
    }
     
    int main() {
    	t_eleve tab[100];
    	t_eleve *pt;
    	chargeEleve("fic", tab);
    	for (pt=tab; pt->note != -1 /* Ou bien strcmp(pt->nom, "") == 0 puisque j'ai aussi mis cette sentinelle */; pt++)
    		printf("elève=%s, note=%d\n", pt->nom, pt->note);
    }
    Mon Tutoriel sur la programmation «Python»
    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
    Et on poste ses codes entre balises [code] et [/code]

  16. #16
    Membre du Club Avatar de Redgard
    Homme Profil pro
    x
    Inscrit en
    Décembre 2014
    Messages
    90
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : x

    Informations forums :
    Inscription : Décembre 2014
    Messages : 90
    Points : 60
    Points
    60
    Par défaut
    Il y a un truc qui me chiffone. dans l'idée, "i" aura la même adresse mémoire que "5", là où un pointeur "pi" aura sa propre adresse dans la mémoire et stockera l'adresse de "i"/"5". i est géré comment par la mémoire? il fait coloc avec 5?
    Sinon, en bref:
    - les fonctions font des copier-coller de ce que tu leur donnes en variable, ce qui nous obliges à passer par des pointeurs si on veut que la fonction modifie des valeurs.
    - pour résumer: (j'ai deux compilateurs en ligne qui plantent avec :/ ... c'est ma manière d'utiliser printf dans PrintPVar? )
    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
    #include <stdio.h>      //j'ai "No output". ça marchait jusqu'à PrintPVar...
     
    void PrintVar(int x){
        printf("numero : %d\n", x);
    }
     
    void PrintPVar(int *x){     
     
        printf("numero pointe: %d\n", *x);
    }
     
     
    int main() {
        int *pn;
     
        int x = 5;
        int *px;
     
        int y = 7;
        int *py;
     
        px = &x;
        py = &y;
        *pn = 3,
     
     
        PrintVar(3);
        PrintVar(x);
        PrintVar(*py);
     
        PrintPVar(pn);      //Est-il possible de passer l'adresse d'un nombre sans pointer? J'ai des erreurs avex "&3" et "*3"
        PrintPVar(px);      //Est-il possible de faire passer "x" sans pointer? J'ai des erreurs avex "&x" et "*x"
        PrintPVar(py);
     
    	return 0;
    }
    - les tableaux:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    char tab[10];
     
    tab == &tab[0];          // *tab == tab[0]
    (tab+n) == &tab[n]     // *(tab+n) == *(tab[n]) == tab[n]
    ======================

    En regardant le coups de pouce que tu m'as données, j'ai eu la réponse que je voulais avoir au tout début (comment les données sont récupérées et stockées dans la mémoire par la fonction "fgets").
    Donc pour ce qui est du tableau multi-dimensionnel, il ne sert à rien, à moins comme tu le dis, que l'on y classe directement les données dedans, mais ça serait rajouter inutilement une étape.
    J'ai fait ce choix parce que j'arrive pas à savoir comment le C fait la différence entre un tableau de caractère et un tableau de string.

    ======================

    Pour la VM, j'en aie déjà entendu parlé, mais je n'en aie jamais installé. D'ailleur les VPS, c'est pas ça? ou ils utilisent un système de session?
    D'ailleurs Win10 en intègre un je crois pour permettre la compilation avec le bash, ou je sais plus trop quoi.

    ======================

    Il en ont parlé en 5 minute de la possibilité de débordement de mémoire pour insister sur l'importance "\0" dans le tableau. Mais ils n'ont pas parlé du fait de créer manuellement des " valeurs sentinelles".
    Concrètement la valeur sentinelle, c'est juste une double sécurité?

    La fonction ne bloque pas automatiquement une case supplémentaire pour stoquer "\0"? ça veut dire que si je déclare "char tab[10]", le "0\" sera stocker sur "tab[10]".

    ======================

    Pour "printf()" et "strcpy()": bon a savoir, je n'étais pas au courant.

    ======================

    Pour la relecture, c'est pour ça que je commente pas mal mon code, mais je n'avais pas poussé la réflexion aussi loin.

    ======================

    2h du mat? vérifies les heures de réédition. J'ai modifié mon message au fur et à mesure que je corrigeais des trucs, trouvais de nouvelles informations sur internet, etc.

    A la base je fais cette formation en ligne parce que je le veux, pas pour remplir des cases, je n'ai aucune obligation de la finir ou quoi que ce soit d'autres. Donc je le fais pour moi, pour servir un projet personnel. Maintenant c'est une formation faites sur un modèle ou tu passes environ 5h par semaine sur 10 semaine. Or pour ce que j'en vois, le format m'a l'air pas trop adapté, ce qui fait qu'il n'ont pas le temps de tout expliquer et que la difficulté n'est pas toujours bien qualibré et va en s'accroissant. J'ai checké le test de la semaine prochaine, ça va être la joie, je vais devoir faire notament joujou avec le Makefile.
    Et je parle pas des compilateur en ligne qui atteigne leur limite.


    J'ai regardé et analysé ton code. Il est intéressant, on peut en tirer plein d'informations et de conclusion. ça m'a pris une heure de le déchiffrer et comprendre mais j'en apprend plus en déchiffrant ce genre de code qu'en écoutant pendant une heure une vidéo de ma formation.

    dis moi si je me plante à un endroit.
    Mes appelations reste bancale, mais l'idée derrière y est.
    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
    #include <stdio.h>
    #include <string.h>
     
    typedef struct {
    	int note;
    	char nom[100 + 1];
    } t_eleve;	
     
    int chargeEleve(char *fic, t_eleve *tab) {
    	FILE *fp;
    	char zone[100 + 1];
    	char *c;
    	if ((fp = fopen(fic, "r")) == NULL) return -1;			//ouvre le fichier "fic" et copie son contenu dans un buffer pointé par fp + valeur sentinelle.
     
    	while (fgets(zone, 100 + 1, fp) != NULL) {				//boucle "while", tournant tant que la liste "zone" remplit à partir de "fp", est non-"NULL".
    		if ((c = strchr(zone, '\n')) != NULL) *c = '\0';	//condition "if", remplaçant "\n" par "\0", si le pointeur "c" est non-"NULL"
    		if ((c = strchr(zone, ';')) == NULL) continue;		//condition "if", continuant si le pointeur "c" est "NULL"
    		*c = '\0';											//si pointeur "c" est non-"NULL", remplace ";" par "\0"
    		tab->note = atoi(zone);								//transforme les charactères du tableau zone en entier et les incrémentent au membre "note" du tableau pointé par "tab"
    		strcpy(tab->nom, c + 1);							//copie les caractère du tableau pointé par "c+1" dans le membre du tableau pointé par "tab"
    		tab++;												// tab = tab + 1
    	}
    	fclose(fp);												// fermeture du flux "fp"
    	tab->note = -1;											// tab ayant été incrémenté encore une fois à la fin de la boucle, tu utilises cette case pour mettre des valeurs sentinelles. J'ai eu du mal à comprendre.
    	tab->nom[0] = '\0';										// De même. 
    	return 0;												// De même. enn conclusion, soit tu renvoies zéro si il n'y a pas de problème, soit tu renvoies -1 qui est une valeur qui va interrompre la suite du programme
    }
     
    int main() {
    	t_eleve tab[100];										//tableau "tab" de 100 structure t-eleve
    	t_eleve *pt;											//pointeur pt de structure t_eleve
    	chargeEleve("fic", tab);								//remplit le tableau "tab" avec le contenu du fichier "fic"
    	for (pt = tab; pt->note != -1 ; pt++)					// boucle for imprimant à l'écran les données du tableau pointé par "tab", condition d'interruption: les valeurs sentinelles
    		printf("elève=%s, note=%d\n", pt->nom, pt->note);
     
    	// OU
     
    	/*
    	for (pt = tab; strcpy(pt->nom, "") == 0 ; pt++)			// boucle for imprimant à l'écran les données du tableau pointé par "tab", condition d'interruption: les valeurs sentinelles
    		printf("elève=%s, note=%d\n", pt->nom, pt->note);
    	*/
    }

    ======================

  17. #17
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Redgard Voir le message
    Il y a un truc qui me chiffone. dans l'idée, "i" aura la même adresse mémoire que "5", là où un pointeur "pi" aura sa propre adresse dans la mémoire et stockera l'adresse de "i"/"5". i est géré comment par la mémoire? il fait coloc avec 5?
    Non, je n"ai pas dit que "i" avait la même adresse que 5.
    Dans mon tout premier exemple, je veux calculer le carré de 5 donc je demande bêtement carre(5). La valeur "5" sera recopiée dans la variable "x" de ma fonction "carre()".
    Ensuite si j'ai une variable "i" qui vaut 5, j'ai alors parfaitement le droit de passer "i" à ma fonction. Mais "i" possède une adresse mémoire bien à elle. Et si je définis une autre variable "pi", alors cette autre variable aura elle aussi une adresse mémoire bien à elle (et fatalement différente).
    Tout ce que tu as à comprendre, c'est que la variable "pi", si elle est définie correctement, alors pourra stocker l'adresse d'une autre variable (on va dire "de i") et que tu pourras accéder à la valeur soit en passant directement par "i", soit en passant indirectement (via l'opérateur étoile) par "pi" (d'où le terme "indirection").

    Citation Envoyé par Redgard Voir le message
    Sinon, en bref:
    - les fonctions font des copier-coller de ce que tu leur donnes en variable, ce qui nous obliges à passer par des pointeurs si on veut que la fonction modifie des valeurs.
    - pour résumer: (j'ai deux compilateurs en ligne qui plantent avec :/ ... c'est ma manière d'utiliser printf dans PrintPVar? )
    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
    #include <stdio.h>
    void PrintVar(int x){
        printf("numero : %d\n", x);
    }
    
    void PrintPVar(int *x){     
        printf("numero pointe: %d\n", *x);
    }
    
    int main() {
        int *pn;
        
        int x = 5;
        int *px;
        
        int y = 7;
        int *py;
        
        px = &x;
        py = &y;
        *pn = 3,   // Horreur !!!
        
        
        PrintVar(3);
        PrintVar(x);
        PrintVar(*py);
        
        PrintPVar(pn);      //Est-il possible de passer l'adresse d'un nombre sans pointer? J'ai des erreurs avex "&3" et "*3"
        PrintPVar(px);      //Est-il possible de faire passer "x" sans pointer? J'ai des erreurs avex "&x" et "*x"
        PrintPVar(py);
        
    	return 0;
    }
    Une seule erreur (en rouge). Tu définis une variable "pn" sans l'initialiser. "pn" contient donc n'importe quoi (par exemple 0xFF11EE). Que sais-tu de la case d'adresse 0xFF11EE ? Est-ce qu'elle fait partie de la mémoire que l'OS a alloué à ton programme ? Si oui, est-elle réellement libre ou bien n'est-elle pas affectée à une autre variable ?? Et si elle est libre, le restera-t-elle durant toute la durée de vie de ton programme ??? Et malgré toutes ces inconnues, tu remplis cette case 0xFF11EE avec la valeur 3.
    Tu ne dois jamais utiliser *truc si tu n'as pas la garantie que "truc=adresse_valide". Tu peux obtenir cette garantie
    • soit parce que tu l'écris toi-même à partir d'une variable déjà existante (px=&x) ou bien à partir d'une fonction qui te renvoie une adresse spécifique (px=malloc(...); py=fopen(...))
    • soit parce que tu le reçois en paramètre d'une fonction et donc tu dois partir du principe que celui qui te l'envoie a bien pris cette précaution (de toute façon tu ne peux pas le vérifier donc t'es obligé de faire confiance)

    Une seule erreur mais elle suffit à tout faire planter...

    Citation Envoyé par Redgard Voir le message
    - les tableaux:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    char tab[10];
    
    tab == &tab[0];          // *tab == tab[0]  OK
    (tab+n) == &tab[n]     // *(tab+n) == *(tab[n]) == tab[n]  ERREUR, *(tab[n]) au milieu est malvenu (*(tab[n]) ne peut pas être égal à tab[n] sinon ça veut dire que *truc égale truc !!!)
    Voir mes remarques en rouge

    Citation Envoyé par Redgard Voir le message
    j'ai eu la réponse que je voulais avoir au tout début (comment les données sont récupérées et stockées dans la mémoire par la fonction "fgets").
    Oui enfin j'avais aussi répondu à cette question. Tu ne récupères que de l'octet brut. A toi ensuite de l'analyser. Et t'as de la chance d'avoir fgets() qui s'arrête à la fin de la ligne parce que sans ça, tu aurais non seulement des octets brut mais en plus tu pourrais n'avoir que le début de la ligne (et la fin au tour de boucle suivant)...

    Citation Envoyé par Redgard Voir le message
    J'ai fait ce choix parce que j'arrive pas à savoir comment le C fait la différence entre un tableau de caractère et un tableau de string.
    La notion de "string" n'existe pas en C. Une "string" c'est
    • soit un tableau de caractères. Donc un tableau de, comme tu dis "strings", ce sera un tableau de tableaux de caractères ou un tableau 2D => char semaine[][10]={{'l', 'u', 'n', 'd', 'i', '\0'}, {'m', 'a', 'r', 'd', 'i', '\0'}, ...}.
    • soit une adresse (comme quand j'écris strcpy(tab, "Hello") la chaine "Hello" est stockée en mémoire constante et le compilo te donne juste l'adresse du 'H') donc un tableau de strings ne sera qu'un tableau de pointeurs => char *semaine[]={"lundi", "mardi", ..., "dimanche"}.


    Citation Envoyé par Redgard Voir le message
    D'ailleurs Win10 en intègre un je crois pour permettre la compilation avec le bash, ou je sais plus trop quoi.
    Oui, W10 (sorti en 2015) intègre effectivement un bash. Alors que Unix est sorti en 1970 et Linux est sorti en 1998. Et donc ? Ils veulent une médaille aussi ???

    Citation Envoyé par Redgard Voir le message
    Concrètement la valeur sentinelle, c'est juste une double sécurité?
    Non, pas une double sécurité mais une seule et unique sécurité. Si (dans mon second exemple avec "-1") je supprime le "-1" du tableau, ma fonction "affiche()" partira en torche...

    Citation Envoyé par Redgard Voir le message
    La fonction ne bloque pas automatiquement une case supplémentaire pour stoquer "\0"?
    Non. C'est toi qui défini tes variables et leur mémoire. Les fonctions partent du principe qu'elles auront la place de stocker tout ce qu'il y a à stocker.

    Citation Envoyé par Redgard Voir le message
    ça veut dire que si je déclare "char tab[10]", le "0\" sera stocker sur "tab[10]".
    Là tu ne déclares qu'un simple tableau de caractère. Le compilo n'a aucune raison d'y mettre quoi que ce soit où que ce soit.
    Si ensuite tu écris strcpy(tab, "Hello") la fonction "strcpy()" écrira la chaine "Hello" dans chaque case de "tab" (un caractère par case) et rajoutera ensuite (dans la case immédiatement suivante) un '\0'. Donc "tab" contiendra 'H', 'e', 'l', 'l', 'o', '\0', xxx, xxx, xxx, xxx ("xxx" signifiant "n'importe quoi")

    Citation Envoyé par Redgard Voir le message
    2h du mat? vérifies les heures de réédition. J'ai modifié mon message au fur et à mesure que je corrigeais des trucs, trouvais de nouvelles informations sur internet, etc.
    Les intervenants ne voient pas les heures de réédition, seulement l'heure du post initial. Les modos peuvent voir plus de trucs mais je ne suis pas modo. De même tu verras que mon post date de 9h mais je l'ai réédité aussi jusqu'à 14h...

    Citation Envoyé par Redgard Voir le message
    je vais devoir faire notament joujou avec le Makefile.
    Pas de souci, ça a l'air effrayant mais une fois qu'on a compris le principe...

    Citation Envoyé par Redgard Voir le message
    J'ai regardé et analysé ton code. Il est intéressant, on peut en tirer plein d'informations et de conclusion. ça m'a pris une heure de le déchiffrer et comprendre mais j'en apprend plus en déchiffrant ce genre de code qu'en écoutant pendant une heure une vidéo de ma formation.
    Je regrette que tu aies mis 1h...

    Citation Envoyé par Redgard Voir le message
    dis moi si je me plante à un endroit.
    Mes appelations reste bancale, mais l'idée derrière y est.
    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
    #include <stdio.h>
    #include <string.h>
    
    typedef struct {
    	int note;
    	char nom[100 + 1];
    } t_eleve;	
    
    int chargeEleve(char *fic, t_eleve *tab) {
    	FILE *fp;
    	char zone[100 + 1];
    	char *c;
    	if ((fp = fopen(fic, "r")) == NULL) return -1;			//ouvre le fichier "fic" et copie son contenu dans un buffer pointé par fp + valeur sentinelle.
    	// Non - Ouvre fic et lui affectes un "oeuil de lecture". Toi, tu récupères juste cet "oeuil" que tu stockes dans "fp". Il n'y a aucune notion de "sentinelle" ici ni même de buffer.
    
    	while (fgets(zone, 100 + 1, fp) != NULL) {				//boucle "while", tournant tant que la liste "zone" remplit à partir de "fp", est non-"NULL". OK
    		if ((c = strchr(zone, '\n')) != NULL) *c = '\0';	//condition "if", remplaçant "\n" par "\0", si le pointeur "c" est non-"NULL". OK
    		if ((c = strchr(zone, ';')) == NULL) continue;		//condition "if", continuant si le pointeur "c" est "NULL". OK
    		*c = '\0';											//si pointeur "c" est non-"NULL", remplace ";" par "\0".
    		// Plus explicitement: si c est non nul, alors il contient l'adresse de la case contenant le ';' (case faisant elle-même partie du tableau "zone"). Je remplace donc ce qu'il y a dans cette case par un '\0'
    
    		tab->note = atoi(zone);								//transforme les charactères du tableau zone en entier et les incrémentent au membre "note" du tableau pointé par "tab"
    		/*
    				Euh, je n'aime pas le verbe "incremente". La fonction "atoi" transforme une chaine représentant un nombre (exemple "15") en sa valeur numérique (donc 15)
    				Moi je récupère juste ce nombre que je stocke effectivement dans le membre "note" du tableau "tab"
    																																*/
    		strcpy(tab->nom, c + 1);							//copie les caractère du tableau pointé par "c+1" dans le membre du tableau pointé par "tab" OK
    		tab++;												// tab = tab + 1
    		 /*
    				Plus détaillé, le pointeur "tab" passe sur l'élément suivant et ce, quelle que soit la taille de cet élément (arithmétique des pointeurs)
    				Ici la structure occupe 105 octets mémoires (101 octets du nom et 4 de l'int). Mon pointeur, avec ce "++", passe donc de l'octet "x" à l'octet "x+115".
    				Equation: tab+n équivaut (en mémoire) à tab + n * sizeof(*tab)
    																																		*/
    	}
    	fclose(fp);												// fermeture du flux "fp" OK
    	tab->note = -1;											// tab ayant été incrémenté encore une fois à la fin de la boucle, tu utilises cette case pour mettre des valeurs sentinelles. J'ai eu du mal à comprendre.
    	// Super bien vu. Effectivement tab s'incrémente à chaque fois donc y compris la dernière fois qu'on le remplit
    	// Tu seras souvent confronté à ce genre de "raccourci logique" en C...
    	tab->nom[0] = '\0';										// De même. OK
    	return 0;												// De même. En conclusion, soit tu renvoies zéro si il n'y a pas de problème, soit tu renvoies -1 qui est une valeur qui va interrompre la suite du programme
    	// Exact (si l'appelant veut bien tester le cas 0/-1)
    }
    
    int main() {
    	t_eleve tab[100];										//tableau "tab" de 100 structure t-eleve
    	t_eleve *pt;											//pointeur pt de structure t_eleve
    	chargeEleve("fic", tab);								//remplit le tableau "tab" avec le contenu du fichier "fic"
    	for (pt = tab; pt->note != -1 ; pt++)					// boucle for imprimant à l'écran les données du tableau pointé par "tab", condition d'interruption: les valeurs sentinelles
    		printf("elève=%s, note=%d\n", pt->nom, pt->note);
    
    	// OU
    
    	/*
    	for (pt = tab; strcmp(pt->nom, "") == 0 ; pt++)			// boucle for imprimant à l'écran les données du tableau pointé par "tab", condition d'interruption: les valeurs sentinelles
    		printf("elève=%s, note=%d\n", pt->nom, pt->note);
    	*/
    	// Ouais. T'as bien pigé l'utilisation
    }
    Voir mes remarques en rouge. Attention je m'étais trompé dans l'exemple car ce n'est pas "strcpy()" qu'il faut utiliser pour comparer tab avec chaine_vide ; mais "strcmp()". J'ai rectifié mon post de ce matin.

    Autre façon de faire aussi
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    	for (pt = tab; pt->nom[0] != '\0' ; pt++)
    		printf("elève=%s, note=%d\n", pt->nom, pt->note);
    Autant éviter d'utiliser une fonction dédiée à comparer tout une chaine alors qu'on ne veut vérifier que son premier caractère...
    Mon Tutoriel sur la programmation «Python»
    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
    Et on poste ses codes entre balises [code] et [/code]

  18. #18
    Membre du Club Avatar de Redgard
    Homme Profil pro
    x
    Inscrit en
    Décembre 2014
    Messages
    90
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : x

    Informations forums :
    Inscription : Décembre 2014
    Messages : 90
    Points : 60
    Points
    60
    Par défaut
    Pour ce qui est des rééditions:
    Va falloir que je fasse attention car entre le moment où je lis ton message et le moment ou je poste la réponse, certains points peuvent avoir changé

    =================================

    En fait mon erreur avec pn est d'avoir voulu le définir indirectement, avant de le définir directement, et donc d'avoir voulu définir un pointeur sans avoir préalablement définit un variable avant.
    Pour reprendre mon exemple:
    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
    #include <stdio.h>      //j'ai encore "No output" quand j'utilise la fonction "PrintPVar"...
     
    void PrintVar(int x){
        printf("numero : %d\n", x);
    }
     
    void PrintPVar(int *x){     
     
        printf("numero pointe: %p\n", *x);      // j'ai remplacé "%d" par "%p" mais ça change pas grand chose
    }
     
     
    int main() {
        int n, size;
        int *pn;
        int *py;
     
        size = 1,
        n = 3,
        *pn=n;
        *py = malloc(size * sizeof(int));
     
        PrintVar(3);
        //PrintVar(*pn);        //No Output
        //PrintVar(*py);        //No Output
     
        //PrintPVar(pn);        //No Output
        //PrintPVar(py);        //No output - Est-ce qu'il y a un moyen de faire passer un pointeur dans printf sans avoir une erreur?
     
    	return 0;
    }
    ===========================

    En fait, j'ai du mal à voir où s'arrête ta condition "if", et donc qu'est ce qui est concerné par l'état "continue".
    Par déduction, je dirais quelle passe l'instruction '"*c ='\0'" de la ligne juste en dessous? Mais alors est ce que la première condition "if" englobe la deuxième? Je sais grâce au C# que quand une condition/ une boucle tient sur une ligne, on peut enlever les accolades, mais j'ai pas encore trop l'habitude de lire du code optimisé à ce point.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    	while (fgets(zone, 100 + 1, fp) != NULL) {				
    		if ((c = strchr(zone, '\n')) != NULL) *c = '\0';	
    			if ((c = strchr(zone, ';')) == NULL) continue;		
    				*c = '\0';											//si pointeur "c" est non-"NULL", remplace ";" par "\0".
    		// Plus explicitement: si c est non nul, alors il contient l'adresse de la case contenant le ';' (case faisant elle-même partie du tableau "zone"). Je remplace donc ce qu'il y a dans cette case par un '\0'
     
    		tab->note = atoi(zone);																																						*/
    		strcpy(tab->nom, c + 1);																								*/
    	}
    ===========================

    EDIT 04:11

    J'ai repris ton code comme base et aie tout réécrit pour avoir quelque chose de plus propre, moins brouillon, en essayant d'imiter ta syntax et de respecter la logique que tu avais mis en place.
    Il y a surement des choses qui ne sont pas encore maîtrisée, mais je pense que le résultat est déjà meilleur que mon premier jet (pas très compliqué quand tu vois que ça avait été construit sur des postulats totalement faux).

    au passage, est-ce que ce genre d'addition est permise en C > (x += y) == (x = x + y) ? j'ai cherché sur internet mais je tombe sur des questions parlant de python et de C#. je présume que l'absence de réponse veut dire non, mais ça ne coute rien de poser la question.
    EDIT 04:41 - J'ai fini par trouver ma réponse en tournant sur cplusplus.com au lieu de demander à google

    EDIT 05:00 - est-ce que je ne pourrais pas utiliser "fprintf" pour remplacer "sprintf" et "fputs"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int EcritEleve(char *destf, t_eleve *pt) {					// écrit le contenu du tableau "pt" dans un fichier "destf"
    	FILE *fd;
     
    	if ((fd = fopen(destf, "w")) == NULL) return -1;		// crée un fichier "destf" en écriture, affecte un "oeil d'écriture" qu'on stock dans "fd". Si l'oeil est NULL, retourne -1
     
    	while (pt->note != -1)	{								// boucle while tournant tant quelle ne reconntre pas de valeur sentinelle
    		fprintf(fd, "%d; %s", pt->note, pt->nom);
    		pt++;												// passe à la case suivante du tableau "pt" de structure "t_eleve"
    	}
    	fclose(fd);												// fermeture du flux "fd"
    	return 0;
    }
    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
     
    #include <stdio.h>
    #include <string.h>
     
    typedef struct {
    	int note;
    	char nom[100 + 1];
    } t_eleve;	
     
    int chargeEleve(char *fic, t_eleve *tab) {
    	FILE *fp;
    	char zone[100 + 1];
    	char *c;
    	if ((fp = fopen(fic, "r")) == NULL) return -1;			//ouvre le fichier "fic", affecte un "oeil de lecture" qu'on stock dans "fp". Si l'oeil est "NULL" retourne -1 (valeur sentinelle)
     
    	while (fgets(zone, 100 + 1, fp) != NULL) {				//boucle "while", tournant tant que la liste "zone" remplit à partir de "fp", est non-"NULL".
    		if ((c = strchr(zone, '\n')) != NULL) *c = '\0';	//condition "if", remplaçant "\n" par "\0", si le pointeur "c" est non-"NULL"
    		if ((c = strchr(zone, ';')) == NULL) continue;		//condition "if", continuant si le pointeur "c" est "NULL"
    		*c = '\0';											//si pointeur "c" est non-"NULL", remplace ";" par "\0"
    		tab->note = atoi(zone);								//transfprme la chaine de caractère représentant un nombre dans le tableau "zone" en son équivalent numérique et le place dans le membre note du tableau tab
    		strcpy(tab->nom, c + 1);							//copie les caractère du tableau pointé par "c+1" dans le membre du tableau pointé par "tab"
    		tab++;												//passe à la case suivante de la structure, qui est 1*sizeof(*tab) plus loin. (tab + n == tab + n * sizeof(*tab))
    	}
    	fclose(fp);												// fermeture du flux "fp"
    	tab->note = -1;											// tab ayant été incrémenté encore une fois à la fin de la boucle, une valeur sentinelle est placé afin d'éviter tout débordement de mémoire
    	tab->nom[0] = '\0';										// de même.
    	return 0;												// retour d'une valeur sentinelle
    }
     
    void Incrementeur(t_eleve *pt){								// prend la cellule active du tableau et ajoute 2 points au membre note, si ça ne dépasse pas 20
    	if (pt->note <= 18)										// ajoute 2 points si le membre note du tableau pt est plus petit ou égal à 18 
    		pt->note += 2;
    	else
    		pt->note = 20;										// sinon le membre note du tableau pt est égal à 20
    }
     
    int EcritEleve(char *destf, t_eleve *pt) {					// écrit le contenu du tableau "pt" dans un fichier "destf"
    	FILE *fd;
    	char zone[100 + 1];
     
    	if ((fd = fopen(destf, "w")) == NULL) return -1;			// crée un fichier "destf" en écriture, affecte un "oeil d'écriture" qu'on stock dans "fd". Si l'oeil est NULL, retourne -1
     
    	while (pt->note != -1)	{								// boucle while tournant tant quelle ne reconntre pas de valeur sentinelle
    		sprintf(zone, "%d; %s", pt->note, pt->nom);			// recompose la phrase sur base des deux membres "note" et "nom" du tableau pt et les stock dans le tableau zone
    		fputs(zone, fd);										// prend le contenu du tableau "zone" et l'écrit dans l'"oeil d'écriture" stocké dans "fd".
    		pt++;												// passe à la case suivante du tableau "pt" de structure "t_eleve"
    	}
    	fclose(fd);												// fermeture du flux "fd"
    	return 0;
    }	
     
     
    int main() {
    	t_eleve tab[100];										// tableau "tab" de 100 structure t-eleve
    	t_eleve *pt;											// pointeur pt de structure t_eleve
     
    	chargeEleve("note.txt", tab);							//remplit le tableau "tab" avec le contenu du fichier "fic"
    	for (pt = tab; pt->note != -1; pt++)					// boucle for imprimant à l'écran les données du tableau pointé par "tab", condition d'interruption: les valeurs sentinelles
    	{
    		Incrementeur(pt);									//Ajout de deux points à la note.
    		printf("elève=%s, note=%d\n", pt->nom, pt->note);	//impression écran des résultats des élèves 
    	}
     
    	/*			OU
    	for (pt = tab; strcmp(pt->nom, "") == 0 ; pt++)			// boucle "for" imprimant à l'écran les données du tableau pointé par "tab", condition d'interruption: les valeurs sentinelles
    	printf("elève=%s, note=%d\n", pt->nom, pt->note);
    	*/
     
    	EcritEleve("anniversaire.txt", pt);						//
     
    	return 0;	
    }
    juste une erreur avec avec une déclaration implicite. Si je me goure pas ça veut dire une répétition entre ce qui est déclaré dans la fonction et les variables que tu lui donnes.
    EDIT 04:30 - OK, j'avais tout faux il me manquait le "stdlib.h". Il est pas plutôt censé me dire comme quoi la fonction atoi n'est pas déclaré?
    Attention! La compilation a produit les anomalies suivantes sur son flux d'erreur:
    anniversaire.c: In function 'chargeEleve':
    anniversaire.c:19:3: error: implicit declaration of function 'atoi' [-Werror=implicit-function-declaration]
    cc1: all warnings being treated as errors
    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
    #include <stdio.h>
    #include <string.h>
    
    typedef struct {
    	int note;
    	char nom[100 + 1];
    } t_eleve;	
    
    int chargeEleve(char *fic, t_eleve *tab) {
    	FILE *fp;
    	char zone[100 + 1];
    	char *c;
    	if ((fp = fopen(fic, "r")) == NULL) return -1;			//ouvre le fichier "fic", affecte un "oeil de lecture" qu'on stock dans "fp". Si l'oeil est "NULL" retourne -1 (valeur sentinelle)
    
    	while (fgets(zone, 100 + 1, fp) != NULL) {				//boucle "while", tournant tant que la liste "zone" remplit à partir de "fp", est non-"NULL".
    		if ((c = strchr(zone, '\n')) != NULL) *c = '\0';	//condition "if", remplaçant "\n" par "\0", si le pointeur "c" est non-"NULL"
    		if ((c = strchr(zone, ';')) == NULL) continue;		//condition "if", continuant si le pointeur "c" est "NULL"
    		*c = '\0';											//si pointeur "c" est non-"NULL", remplace ";" par "\0"
    		tab->note = atoi(zone);								//transfprme la chaine de caractère représentant un nombre dans le tableau "zone" en son équivalent numérique et le place dans le membre note du tableau tab
    		strcpy(tab->nom, c + 1);							//copie les caractère du tableau pointé par "c+1" dans le membre du tableau pointé par "tab"
    		tab++;												//passe à la case suivante de la structure, qui est 1*sizeof(*tab) plus loin. (tab + n == tab + n * sizeof(*tab))
    	}
    	fclose(fp);												// fermeture du flux "fp"
    	tab->note = -1;											// tab ayant été incrémenté encore une fois à la fin de la boucle, une valeur sentinelle est placé afin d'éviter tout débordement de mémoire
    	tab->nom[0] = '\0';										// de même.
    	return 0;												// retour d'une valeur sentinelle
    }

  19. #19
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 689
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 689
    Points : 30 983
    Points
    30 983
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Redgard Voir le message
    Va falloir que je fasse attention car entre le moment où je lis ton message et le moment ou je poste la réponse, certains points peuvent avoir changé
    Moui. Et quand tu reviens éditer tes trucs, autant supprimer ce qui est devenu faux plutôt que le laisser en mettant en dessous "c'est faux je corrige en dessous"...

    Citation Envoyé par Redgard Voir le message
    En fait mon erreur avec pn est d'avoir voulu le définir indirectement, avant de le définir directement, et donc d'avoir voulu définir un pointeur sans avoir préalablement définit un variable avant.
    Non. Tu peux très bien définir un pointeur et la variable vers laquelle il pointera après: int *pn; int toto=123; pn=&toto.

    Ton erreur (que tu as refaite ici) est de vouloir accéder à "étoile pn" sans avoir écrit auparavant pn=adresse_valide. Tant que tu continueras ainsi, ça ne pourra jamais fonctionner.
    Citation Envoyé par Redgard Voir le message
    Pour reprendre mon exemple:

    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
    #include <stdio.h>      //j'ai encore "No output" quand j'utilise la fonction "PrintPVar"...
    // Parce que tu ne l'utilises pas avec les bons arguments
    
    void PrintVar(int x){
        printf("numero : %d\n", x);
    }
    
    void PrintPVar(int *x){     
        
        printf("numero pointe: %p\n", *x);      // j'ai remplacé "%d" par "%p" mais ça change pas grand chose
    }
    
    
    int main() {
        int n, size;
        int *pn;
        int *py;
        
        size = 1,
        n = 3,
        *pn=n;       // pn=&n
        *py = malloc(size * sizeof(int));       // py=malloc(size * sizeof(int)) - C'est le pointeur qui reçoit l'adresse allouée, pas son pointé !!!
        
        PrintVar(3);
        //PrintVar(*pn);        //No Output
        //PrintVar(*py);        //No Output     => Normal, tu as alloué de la mémoire à la zone pointée par "py" mais tu n'as pas rempli cette zone !!!
    
        //PrintPVar(pn);        //No Output
        //PrintPVar(py);        //No output - Est-ce qu'il y a un moyen de faire passer un pointeur dans printf sans avoir une erreur?
        // Oui, si tu lui mets le bon format
        printf("%p - %d\n", pn, *pn);   // Tu auras la valeur de pn (donc l'adresse qui y est stockée) et la valeur de la case située à cette adresse (donc 3)
    
        // Et n'oublie pas free(py) parce qu'il faut toujours libérer la mémoire allouée quand on n'en a plus besoin
    
    	return 0;
    }
    Correction en rouge

    Citation Envoyé par Redgard Voir le message
    En fait, j'ai du mal à voir où s'arrête ta condition "if", et donc qu'est ce qui est concerné par l'état "continue".
    Par déduction, je dirais quelle passe l'instruction '"*c ='\0'" de la ligne juste en dessous? Mais alors est ce que la première condition "if" englobe la deuxième? Je sais grâce au C# que quand une condition/ une boucle tient sur une ligne, on peut enlever les accolades, mais j'ai pas encore trop l'habitude de lire du code optimisé à ce point.
    Pas de souci. La ligne if ((c = strchr(zone, '\n')) != NULL) *c = '\0'; peut s'écrire en plus détaillé
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    c = strchr(zone, '\n');
    if (c != NULL) {
    	*c='\0';
    }
    Lire ce genre de ligne demande effectivement une certaine habitude mais qui viendra assez vite (quand tu commenceras à les écrire)

    Citation Envoyé par Redgard Voir le message
    au passage, est-ce que ce genre d'addition est permise en C > (x += y) == (x = x + y) ? j'ai cherché sur internet mais je tombe sur des questions
    Oui, l'instruction var = var operateur valeur peut s'écrire var operateur= valeur. Ca fait maintenant partie des standards de tous les langages

    Citation Envoyé par Redgard Voir le message
    est-ce que je ne pourrais pas utiliser "fprintf" pour remplacer "sprintf" et "fputs"
    Bien entendu !!! Tu as des outils, tu peux les utiliser. Et si tu trouves un outil qui peut en remplacer deux autres, alors banco. En effet, au lieu de 1) remplir une zone de datas formatées avec sprintf() puis 2) écrire la zone dans le fichier avec fputs() autant écrire directement les datas formatées dans le fichier avec fprintf(). Déjà tu simplifies ton code intelligement et tu t'évites des noeuds au cerveau (quelle taille donner à ma zone ???)
    C'est pour ça que tu dois essayer aussi d'apprendre quelles sont les fonctions disponibles pour telle ou telle tâche.

    Citation Envoyé par Redgard Voir le message
    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
    int EcritEleve(char *destf, t_eleve *pt) {					// écrit le contenu du tableau "pt" dans un fichier "destf"
    	FILE *fd;
    
    	if ((fd = fopen(destf, "w")) == NULL) return -1;		// crée un fichier "destf" en écriture, affecte un "oeil d'écriture" qu'on stock dans "fd". Si l'oeil est NULL, retourne -1
    	// Mouais. Le terme "oeil" s'adapte bien à la lecture. Pour l'écriture tu pourras parler de "stylo"...
    	// Et ensuite tu simplifieras en parlant de "pointeur"...
    
    	while (pt->note != -1)	{								// boucle while tournant tant quelle ne reconntre pas de valeur sentinelle
    		fprintf(fd, "%d; %s", pt->note, pt->nom);
    		pt++;												// passe à la case suivante du tableau "pt" de structure "t_eleve"
    	}
    	fclose(fd);												// fermeture du flux "fd"
    	return 0;
    }
    Ok - A priori (j'ai pas testé) ça a l'air correct.

    Citation Envoyé par Redgard Voir le message
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void Incrementeur(t_eleve *pt){								// prend la cellule active du tableau et ajoute 2 points au membre note, si ça ne dépasse pas 20
    	if (pt->note <= 18)										// ajoute 2 points si le membre note du tableau pt est plus petit ou égal à 18 
    		pt->note += 2;
    	else
    		pt->note = 20;										// sinon le membre note du tableau pt est égal à 20
    }
    Alors ici on entre dans un nouveau concept. Vaut-il mieux écrire un incrementeur qui travaille sur un seul élève (et l'appeler n fois) ou bien un incrementeur qui peut traiter d'un coup tout le tableau. Il n'y a pas de bonne réponse à cette question car ça dépend de tes besoins. Si tu choisis un incrementeur qui gère tout le tableau, tu ne l'appelles qu'une fois (gain de code) mais tu te prives ensuite de pouvoir traiter un élève particulier. Si au contraire tu choisis un incrementeur qui ne traite qu'un élève tu as un code plus fin mais tu devras écrire une boucle à chaque fois que tu voudras incrémenter tout le tableau.

    Ceci dit, et si le besoin s'en fait sentir, rien ne t'interdit d'écrire 2 fonctions. La première qui gère un élément du tableau et la seconde qui balaye tout le tableau en appelant la première.

    Citation Envoyé par Redgard Voir le message
    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
    20
    int main() {
    	t_eleve tab[100];										// tableau "tab" de 100 structure t-eleve
    	t_eleve *pt;											// pointeur pt de structure t_eleve
     
    	chargeEleve("note.txt", tab);							//remplit le tableau "tab" avec le contenu du fichier "fic"
    	for (pt = tab; pt->note != -1; pt++)					// boucle for imprimant à l'écran les données du tableau pointé par "tab", condition d'interruption: les valeurs sentinelles
    	{
    		Incrementeur(pt);									//Ajout de deux points à la note.
    		printf("elève=%s, note=%d\n", pt->nom, pt->note);	//impression écran des résultats des élèves 
    	}
     
    	/*			OU
    	for (pt = tab; strcmp(pt->nom, "") == 0 ; pt++)			// boucle "for" imprimant à l'écran les données du tableau pointé par "tab", condition d'interruption: les valeurs sentinelles
    	printf("elève=%s, note=%d\n", pt->nom, pt->note);
    	*/
     
    	EcritEleve("anniversaire.txt", pt);						//
     
    	return 0;	
    }
    Ca a l'air correct (encore une fois je peux pas tester car suis au bureau et internet n'est pas connecté à mon poste de travail). En tout cas tu commences à mieux comprendre les pointeurs. C'est vraiment dommage que tu chies encore ton premier exemple...

    Citation Envoyé par Redgard Voir le message
    j'avais tout faux il me manquait le "stdlib.h". Il est pas plutôt censé me dire comme quoi la fonction atoi n'est pas déclaré?
    C'est ce qu'il te dit. Une fonction non déclarée est implicitement déclarée en "int". Si ensuite tu ne l'utilises pas comme il l'a implicitement déclarée, il te dit qu'il ne comprend pas cette différence.
    Mon Tutoriel sur la programmation «Python»
    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
    Et on poste ses codes entre balises [code] et [/code]

  20. #20
    Membre du Club Avatar de Redgard
    Homme Profil pro
    x
    Inscrit en
    Décembre 2014
    Messages
    90
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : x

    Informations forums :
    Inscription : Décembre 2014
    Messages : 90
    Points : 60
    Points
    60
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Non. Tu peux très bien définir un pointeur et la variable vers laquelle il pointera après: int *pn; int toto=123; pn=&toto.
    Parce que je pensais que je pouvais sauter l'étape de la variable, pensant pouvoir faire pointé un pointeur directement sur un nombre. Le problème c'est qu'en faisant ça je le fais pointé sur un espace vide, car non-défini.

    Citation Envoyé par Sve@r Voir le message
    Ton erreur (que tu as refaite ici) est de vouloir accéder à "étoile pn" sans avoir écrit auparavant pn=adresse_valide. Tant que tu continueras ainsi, ça ne pourra jamais fonctionner.
    Parce que je pensais que déclarer un pointeur étoile était équivalent à associer un pointeur à une adresse, en bref que *pn = x == pn = &xOr apparament non, il faut absolument que je le déclare comme ci pn = &x.

    Effectivement, maintenant ça marche:
    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
    #include <stdio.h>      //j'ai encore "No output" quand j'utilise la fonction "PrintPVar"...
     
    void PrintVar(int x){
        printf("numero : %d\n", x);
    }
     
    void PrintPVar(int *x){     
     
        printf("numero pointe: %d\n", *x);      // j'ai remplacé "%d" par "%p" mais ça change pas grand chose
    }
     
     
    int main() {
        int n;
        int *pn;
     
        n = 3,
        pn = &n;
     
     
        PrintVar(3);
        PrintVar(*pn);        
     
     
        PrintPVar(pn);
     
    	return 0;
    }
    Citation Envoyé par Sve@r Voir le message
    Pas de souci. La ligne if ((c = strchr(zone, '\n')) != NULL) *c = '\0'; peut s'écrire en plus détaillé
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    c = strchr(zone, '\n');
    if (c != NULL) {
    	*c='\0';
    }
    En fait, je parlais de cette ligne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if ((c = strchr(zone, ';')) == NULL) continue;		
    		*c = '\0';
    		tab->note = atoi(zone);
    la fonction continue permet de sauter la *c = '\0';?

    Citation Envoyé par Sve@r Voir le message
    C'est ce qu'il te dit. Une fonction non déclarée est implicitement déclarée en "int". Si ensuite tu ne l'utilises pas comme il l'a implicitement déclarée, il te dit qu'il ne comprend pas cette différence.
    J'avais compris le message d'erreur comme quoi je le déclarais deux fois, vu qu'il était déjà déclaré implicitement dans la fonction. "implicite" voulant dire "qui est signifié dedans".

    ================================================

    En fouillant sur le net, je suis tombé sur la fonction fscanf, donc je l'ai utilisé pour encore raccourcir le code. J'ai pas tout compris, donc j'ai du faire quelques suppositions.
    Il ne disait pas si elle lisait une ligne, ou si elle lisait tout le fichier donc j'ai supposé quelle lisait qu'une ligne et l'aie inclus dans la boucle while. J'ai lu quelle pouvait renvoyer le status "fin de fichier/ End-Of-File", ce qui m'a permis de l'inclure directement dans la boucle. J'ai gardé l'incrémentation de tab, pour les valeurs sentinelles.

    Je sais pas si mon utilisation est correcte.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int chargeEleve(char *fic, t_eleve *tab) {
    	FILE *fp;
     
    	if ((fp = fopen(fic, "r")) == NULL) return -1;								//ouvre le fichier "fic", affecte un "oeil de lecture" qu'on stock dans "fp". Si l'oeil est "NULL" retourne -1 (valeur sentinelle)
    	while (fscanf(fp, "%d; %s", &tab->note, tab->nom) != EOF)					//boucle "while", tournant tant la fin du fichier n'est pas atteinte.
    		tab++;																	//passe à la case suivante de la structure, qui est 1*sizeof(*tab) plus loin. (tab + n == tab + n * sizeof(*tab))
    	fclose(fp);																	// fermeture du flux "fp"
    	tab->note = -1;																// tab ayant été incrémenté encore une fois à la fin de la boucle, une valeur sentinelle est placé afin d'éviter tout débordement de mémoire
    	tab->nom[0] = '\0';															// de même.
    	return 0;																	// retour d'une valeur sentinelle
    }
    Code global (pas grand chose ne change):
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    typedef struct {
    	int note;
    	char nom[100 + 1];
    } t_eleve;
     
    int chargeEleve(char *fic, t_eleve *tab) {
    	FILE *fp;
     
    	if ((fp = fopen(fic, "r")) == NULL) return -1;								//ouvre le fichier "fic", affecte un "oeil de lecture" qu'on stock dans "fp". Si l'oeil est "NULL" retourne -1 (valeur sentinelle)
    	while (fscanf(fp, "%d; %s", &tab->note, tab->nom) != EOF)					//boucle "while", tournant tant la fin du fichier n'est pas atteinte.
    		tab++;																	//passe à la case suivante de la structure, qui est 1*sizeof(*tab) plus loin. (tab + n == tab + n * sizeof(*tab))
    	fclose(fp);																	// fermeture du flux "fp"
    	tab->note = -1;																// tab ayant été incrémenté encore une fois à la fin de la boucle, une valeur sentinelle est placé afin d'éviter tout débordement de mémoire
    	tab->nom[0] = '\0';															// de même.
    	return 0;																	// retour d'une valeur sentinelle
    }
     
    void Incrementeur(t_eleve *pt) {												// prend la cellule active du tableau et ajoute 2 points au membre note, si ça ne dépasse pas 20
    	if (pt->note <= 18)															// ajoute 2 points si le membre note du tableau pt est plus petit ou égal à 18 
    		pt->note += 2;
    	else
    		pt->note = 20;															// sinon le membre note du tableau pt est égal à 20
    }
     
    int EcritEleve(char *destf, t_eleve *pt) {										// écrit le contenu du tableau "pt" dans un fichier "destf"
    	FILE *fd;
     
    	if ((fd = fopen(destf, "w")) == NULL) return -1;							// crée un fichier "destf" en écriture, affecte un "oeil d'écriture" qu'on stock dans "fd". Si l'oeil est NULL, retourne -1
     
    	while (pt->note != -1) {													// boucle while tournant tant quelle ne reconntre pas de valeur sentinelle
    		fprintf(fd, "%d;%s\n", pt->note, pt->nom);								// mannière plus courte
    		pt++;																	// passe à la case suivante du tableau "pt" de structure "t_eleve"
    	}
    	fclose(fd);																	// fermeture du flux "fd"
    	return 0;
    }
     
     
    int main() {
    	t_eleve tab[100];															// tableau "tab" de 100 structure t-eleve
    	t_eleve *pt;																// pointeur pt de structure t_eleve
     
    	chargeEleve("note.txt", tab);												//remplit le tableau "tab" avec le contenu du fichier "fic"
    	for (pt = tab; pt->note != -1; pt++)										// boucle for imprimant à l'écran les données du tableau pointé par "tab", condition d'interruption: les valeurs sentinelles
    	{
    		Incrementeur(pt);														//Ajout de deux points à la note.
    		printf("note=%d;elève=%s\n", pt->note, pt->nom);						//impression écran des résultats des élèves 
    	}
     
    	EcritEleve("anniversaire.txt", pt);											//crée un fichier anniversaire vierge et y inscrit le contenu du pointeur de tableau "pt" de structure "T_élève" 
     
    	return 0;
    }
    J'envisage de plus en plus de passer sur une VM, comme tu l'as suggéré précédemment dans la discussion.
    Je pense que c'est quelques choses que les profs auraient dû nous faire faire au début de la formation, pour normaliser l'environnement de travail/d'étude, car actuellement si un élève a un problème sur un autre système d'exploitation que le leur, ils sont moins/pas en mesure de les aider. Et ça aurait permis de nous faire installer directement un compilateur et de nous rendre/ pousser à une certaines autonomie.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 7
    Dernier message: 10/06/2008, 15h38
  2. Réponses: 3
    Dernier message: 04/01/2007, 17h42
  3. Transposer des données sql dans un fichier texte
    Par Anakior dans le forum Outils
    Réponses: 3
    Dernier message: 11/12/2005, 10h01
  4. récupérer des données saisies dans un fichier
    Par natie_49 dans le forum C++
    Réponses: 6
    Dernier message: 24/11/2005, 11h29
  5. [JList] Lecture des données sauvegardées dans un fichier
    Par Myogtha dans le forum Composants
    Réponses: 7
    Dernier message: 10/06/2004, 21h05

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