J'ai fini le cours sur les structures et j'ai fait trois exercices. Je vous propose de commenter le code source du dernier exercice.
Pour qu'on parle bien de la même chose, je copie/colle l'énoncé juste ici en violet:
Ecrire un programme C, qui lit les noms complets des étudiants et leurs moyennes dans un tableau de structures. Puis actualise ces moyennes en ajoutant un bonus de:
1 point pour les étudiants ayant une note strictement inférieure à 10.
0.5 point pour les étudiants ayant une note entre 10 et 15 incluses.
N.B.: la structure doit avoir deux éléments: une chaîne de caractères et un réel.
Je mets mon code juste ici. Vous trouverez les explications directement dans le code source:
#include <stdio.h>
#include <stdlib.h>
typedef struct etudiant etudiant;
struct etudiant // le nouveau type contient deux informations "nom" et "moyenne" comme demandé par l'exercice
{
char nom[100]; //tableau à 100 mais j'avoue que j'aurais pu réduire
double moyenne; // nombre décimal pour la moyenne
};
void afficheProfil( etudiant profil); // prototype en dessous de la structure car sinon le type "etudiant" n'est pas reconnu
// par la fonction. Je me suis fait avoir sur mes autres programmes et j'ai mis du temps
int main() // à comprendre l'erreur.
{
etudiant profil[100]; // je crée un tableau de 100 cases de type étudiant. Chaque case comporte deux informations un nom
int i = 0, n = 0; // et une moyenne.
printf("Combien d'etudiants ?");
scanf("%d", &n);
// Remplissage du tableau en fonction de n (le nombre d'étudiants)
for(i=0; i<n; i++)
{
printf("Nom ?");
scanf("%s", profil[i].nom);
printf("Moyenne ?");
scanf("%lf", &profil[i].moyenne);
}
void afficheProfil( etudiant profil) // je crée une fonction qui m'affiche chaque case du tableau.
{
printf("========\n");
printf("Nom: %s\n", profil.nom);
printf("Moyenne: %lf\n", profil.moyenne);
}
for(i=0; i<n; i++)
{
afficheProfil(profil[i]); // J'affiche chaque case du tableau donc les moyennes n'ont pas encore profité du bonus
}
printf("\n\n***** ACTUALISATION APRES BONUS *****\n\n"); //On rentre dans le coeur de la fonction
for(i=0; i<n; i++) // Je parcours mon tableau de type "etudiant"
{
if(profil[i].moyenne >= 10 && profil[i].moyenne <= 15) // Ajout des 0.5 point bonus
{
profil[i].moyenne = profil[i].moyenne + 0.5;
}
else if(profil[i].moyenne < 10) // Ajout du point bonus.
{
profil[i].moyenne++;
}
}
for(i=0; i<n; i++)
{
afficheProfil(profil[i]); //copier/coller des lignes 38 à 41 pour afficher les cases du tableau avec
} //les moyennes actualisées.
return 0;
}
Résultat pour 4 étudiants:
Combien d'etudiants ?4
Nom ?Lovegood
Moyenne ?15
Nom ?Londubat
Moyenne ?6.5
Nom ?Malefoy
Moyenne ?9
Nom ?Granger
Moyenne ?20
========
Nom: Lovegood
Moyenne: 15.000000
========
Nom: Londubat
Moyenne: 6.500000
========
Nom: Malefoy
Moyenne: 9.000000
========
Nom: Granger
Moyenne: 20.000000
***** ACTUALISATION APRES BONUS *****
========
Nom: Lovegood
Moyenne: 15.500000
========
Nom: Londubat
Moyenne: 7.500000
========
Nom: Malefoy
Moyenne: 10.000000
========
Nom: Granger
Moyenne: 20.000000
Process returned 0 (0x0) execution time : 52.948 s
Press any key to continue.
Je serais curieux de le savoir car ce n'est pas le premier qui le fait. Comme l'a suggéré magma, pourquoi ne pas faire une fonction qui modifie la fiche d'un étutdiant.
Le Tout est souvent plus grand que la somme de ses parties.
Je crois que c'est une particularité de gcc d'accepter une fonction dans une fonction. Mais je n'en vois pas l'utilité. J'imagine que c'est une erreur du po. En tout cas je n'ai jamais vu un tuto montrer ce genre de code. Et même si certaines formations sont décriées, je ne pense pas qu'elle enseignent cela.
- Edité par edgarjacobs 21 octobre 2021 à 19:01:26
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Je crois que c'est une particularité de gcc d'accepter une fonction dans une fonction. Mais je n'en vois pas l'utilité.
C'est clairement une erreur du PO. L'avantage des fonctions imbriquées est qu'elles peuvent accéder au stack de la fonction qui les définit. C'est une extension gcc … aux même titre que les déclarations composées (compound statements). Cela peut donner du code un peu étrange mais permettant de coder une fonction à l'endroit de l'appel par exemple ⇒
#include <stdio.h>
int magic(int a, int (*func)(void))
{
return a+func();
}
int main(void)
{
int a=10;
int add_a(int val) {
return val+a;
}
printf("a = %d\nadd_a(32) = %d\n\n", a, add_a(32));
a=-74;
printf("a = %d\nadd_a(32) = %d\n\n", a, add_a(32));
int result=magic(1, ({ int dummy()
{
return 42;
} dummy; }));
printf("result = %d\n", result);
return 0;
}
C'est évidemment tout sauf portable … mais ça ressemble à … lol non on oublie tout ça car c'est du C ^_^
Exactement, pourquoi ne pas l'avoir mise à l'exrtérieur? Regardes les autres commentaires.
Pour une fonction qui modifierait la structure, n'oublie pas que la structure est recopiée et que c'est cette copie qui sera modifiée. Tu devras lui passer l'adresse comme pour scanf. Je te laisse chercher comment tu vas modifier tes champs dans la fonction. Ça fait partie du chapitre sur les structures.
- Edité par PierrotLeFou 22 octobre 2021 à 2:17:30
Le Tout est souvent plus grand que la somme de ses parties.
Où as-tu vu cette façon de procéder: définir une fonction dans une autre fonction? Quel cours suis-tu?
-
Edité par magma hier à 12:12
Très juste! En regardant à nouveau les cours de Mateo21 sur les tableaux, je viens de m'apercevoir que sa fonction "afficheTableau" est définie à l'extérieur du main().
Du coup, je viens de modifier mon code, dites moi si c'est mieux sur la présentation car sur le fonctionnement c'est ok il me semble.
Je mets le nouveau code juste ici:
#include <stdio.h>
#include <stdlib.h>
typedef struct etudiant etudiant;
struct etudiant // le nouveau type contient deux informations "nom" et "moyenne" comme demandé par l'exercice
{
char nom[100]; //tableau à 100 mais j'avoue que j'aurais pu réduire
double moyenne; // nombre décimal pour la moyenne
};
void afficheProfil( etudiant profil); // prototype en dessous de la structure car sinon le type "etudiant" n'est pas reconnu
// par la fonction. Je me suis fait avoir sur mes autres programmes et j'ai mis du temps
int main() // à comprendre l'erreur.
{
etudiant profil[100]; // je crée un tableau de 100 cases de type étudiant. Chaque case comporte deux informations un nom
int i = 0, n = 0; // et une moyenne.
printf("Combien d'etudiants ?");
scanf("%d", &n);
// Remplissage du tableau en fonction de n (le nombre d'étudiants)
for(i=0; i<n; i++)
{
printf("Nom ?");
scanf("%s", profil[i].nom);
printf("Moyenne ?");
scanf("%lf", &profil[i].moyenne);
}
for(i=0; i<n; i++)
{
afficheProfil(profil[i]); // J'affiche chaque case du tableau donc les moyennes n'ont pas encore profité du bonus
}
printf("\n\n***** ACTUALISATION APRES BONUS *****\n\n"); //On rentre dans le coeur de la fonction
for(i=0; i<n; i++) // Je parcours mon tableau de type "etudiant"
{
if(profil[i].moyenne >= 10 && profil[i].moyenne <= 15) // Ajout des 0.5 point bonus
{
profil[i].moyenne = profil[i].moyenne + 0.5;
}
else if(profil[i].moyenne < 10) // Ajout du point bonus.
{
profil[i].moyenne++;
}
}
for(i=0; i<n; i++)
{
afficheProfil(profil[i]); //copier/coller des lignes 38 à 41 pour afficher les cases du tableau avec
} //les moyennes actualisées.
return 0;
}
void afficheProfil( etudiant profil) // je crée une fonction qui m'affiche chaque case du tableau.
{
printf("========\n");
printf("Nom: %s\n", profil.nom);
printf("Moyenne: %lf\n", profil.moyenne);
}
juste pour donner une idée de code correctement indenté (du moins en gardant une cohérence) :
#include <stdio.h>
#include <stdlib.h>
typedef struct etudiant etudiant;
struct etudiant { // le nouveau type contient deux informations "nom" et "moyenne" comme demandé par l'exercice
char nom[100]; //tableau à 100 mais j'avoue que j'aurais pu réduire
double moyenne; // nombre décimal pour la moyenne
};
void afficheProfil( etudiant profil); // prototype en dessous de la structure car sinon le type "etudiant" n'est pas reconnu
// par la fonction. Je me suis fait avoir sur mes autres programmes et j'ai mis du temps
int main() // à comprendre l'erreur.
{
etudiant profil[100]; // je crée un tableau de 100 cases de type étudiant. Chaque case comporte deux informations un nom
int i = 0, n = 0; // et une moyenne.
printf("Combien d'etudiants ?");
scanf("%d", &n);
// Remplissage du tableau en fonction de n (le nombre d'étudiants)
for(i=0; i<n; i++) {
printf("Nom ?");
scanf("%s", profil[i].nom);
printf("Moyenne ?");
scanf("%lf", &profil[i].moyenne);
}
for(i=0; i<n; i++) {
afficheProfil(profil[i]); // J'affiche chaque case du tableau donc les moyennes n'ont pas encore profité du bonus
}
printf("\n\n***** ACTUALISATION APRES BONUS *****\n\n"); //On rentre dans le coeur de la fonction
for(i=0; i<n; i++) { // Je parcours mon tableau de type "etudiant"
if(profil[i].moyenne >= 10 && profil[i].moyenne <= 15) { // Ajout des 0.5 point bonus
profil[i].moyenne = profil[i].moyenne + 0.5;
}
else if(profil[i].moyenne < 10) { // Ajout du point bonus.
profil[i].moyenne++;
}
}
for(i=0; i<n; i++) {
afficheProfil(profil[i]); //copier/coller des lignes 38 à 41 pour afficher les cases du tableau avec
} //les moyennes actualisées.
return 0;
}
void afficheProfil( etudiant profil) // je crée une fonction qui m'affiche chaque case du tableau.
{
printf("========\n");
printf("Nom: %s\n", profil.nom);
printf("Moyenne: %lf\n", profil.moyenne);
}
enfin «correctement indenté», j'ai juste passé le code à astyle qui a fait le reste … mais bon, tout IDE sait faire cela …
Il y a des outils pour tout et il faut les connaître pour les utiliser.
mais avec des espaces additionnels (et des prototypes de fonctions sur une seule ligne).
En dehors des personnes contribuant du code pour ce projet ou des utilisateurs d'Emacs il n'est pas beaucoup utilisé. Il a aussi ses détracteurs, mais bon, utilisé de façon cohérente, pourquoi pas.
espaces dans les expressions, et après if/while/do/else.., mais pas avant la parenthèse dans les appels de fonctions. Présentation "en drapeau", l'accolade ouvrante d'un bloc est en fin de ligne du début de la structure de contrôle. Ca gagne en nombre de lignes utiles par fenêtre sans nuire à la lisibilité de l'imbrication des blocs.
Manies personnelles : détacher les * pour les rendre plus visibles dans les déclarations. Accolades même pour une seule instruction sauf si c'est un else if (dans le cas idiomatique d'un aiguillage condition par condition).
if (condition) {
// une instruction
} else if {
// une instruction
} else {
// une instruction
}
- Edité par michelbillaud 22 octobre 2021 à 19:30:22
Je prends note de vos remarques sur mon indentation et je vais essayer de l'améliorer même si je pense qu'il y a tout de même une part -aussi minime soit elle- de subjectivité.
Je vous mets mon code ici avec sa nouvelle indentation mais je ne sais pas s'il sera à votre convenance:
#include <stdio.h>
#include <stdlib.h>
typedef struct etudiant etudiant;
struct etudiant // le nouveau type contient deux informations "nom" et "moyenne" comme demandé par l'exercice
{
char nom[100]; //tableau à 100 mais j'avoue que j'aurais pu réduire
double moyenne; // nombre décimal pour la moyenne
};
void afficheProfil( etudiant profil); // prototype en dessous de la structure car sinon le type "etudiant" n'est pas reconnu
// par la fonction. Je me suis fait avoir sur mes autres programmes et j'ai mis du temps
int main() // à comprendre l'erreur.
{
etudiant profil[100]; // je crée un tableau de 100 cases de type étudiant. Chaque case comporte deux informations un nom
int i = 0, n = 0; // et une moyenne.
printf("Combien d'etudiants ?");
scanf("%d", &n);
// Remplissage du tableau en fonction de n (le nombre d'étudiants)
for(i=0; i<n; i++)
{
printf("Nom ?");
scanf("%s", profil[i].nom);
printf("Moyenne ?");
scanf("%lf", &profil[i].moyenne);
}
for(i=0; i<n; i++)
{
afficheProfil(profil[i]); // J'affiche chaque case du tableau donc les moyennes n'ont pas encore profité du bonus
}
printf("\n\n***** ACTUALISATION APRES BONUS *****\n\n"); //On rentre dans le coeur de la fonction
for(i=0; i<n; i++) // Je parcours mon tableau de type "etudiant"
{
if(profil[i].moyenne >= 10 && profil[i].moyenne <= 15) // Ajout des 0.5 point bonus
{
profil[i].moyenne = profil[i].moyenne + 0.5;
}
else if(profil[i].moyenne < 10) // Ajout du point bonus.
{
profil[i].moyenne++;
}
}
for(i=0; i<n; i++)
{
afficheProfil(profil[i]); //copier/coller des lignes 38 à 41 pour afficher les cases du tableau avec
} //les moyennes actualisées.
return 0;
}
void afficheProfil( etudiant profil) // je crée une fonction qui m'affiche chaque case du tableau.
{
printf("========\n");
printf("Nom: %s\n", profil.nom);
printf("Moyenne: %lf\n", profil.moyenne);
}
Je souhaiterais par la suite réagir à ce commentaire:
PierrotLeFou a écrit:
@RiadOuhibi: Es-tu prêt à passer à l'étape suivante? Tu nous écrit une petite fonction qui va modifier ta structure ... ?
Oui @PierrotLeFou j'ai bien bien pris en compte cette remarque mais je ne l'ai mise en application que dans la suite des exercices.
En effet, j'ai fait 6 exercices sur les structures mais j'en ai posté qu'un seul (celui-ci).
En revanche, je compte bien poster le dernier où j'ai fait une fonction pour modifier la structure mais cela m'a causé un problème. J'aimerais vraiment vous en parler mais j'attends d'abord que vous validiez cet exercice.
Est-ce que ces histoires de 4 et 8 espaces ne seraient pas dues à l'utilisation d'un mélange de tabulations et d'espaces ? Par exemple sur mon éditeur, une tabulation est représentée par 4 espaces, et sur l'éditeur du forum elle serait représentée par 8 espaces, quelque chose comme ça. Si c'est bien une des causes, une bonne idée est de régler l'éditeur pour qu'il remplace les tabulations par des espaces.
Non c'est moi qui ai choisi 8 et 4 espaces. je pensais qu'on gagnerait en lisibilité mais comme ça n'est pas cohérent alors je vais modifier.
Que pensez vous de ça :
#include <stdio.h>
#include <stdlib.h>
typedef struct etudiant etudiant;
struct etudiant // le nouveau type contient deux informations "nom" et "moyenne" comme demandé par l'exercice
{
char nom[100]; //tableau à 100 mais j'avoue que j'aurais pu réduire
double moyenne; // nombre décimal pour la moyenne
};
void afficheProfil( etudiant profil); // prototype en dessous de la structure car sinon le type "etudiant" n'est pas reconnu
// par la fonction. Je me suis fait avoir sur mes autres programmes et j'ai mis du temps
int main() // à comprendre l'erreur.
{
etudiant profil[100]; // je crée un tableau de 100 cases de type étudiant. Chaque case comporte deux informations un nom
int i = 0, n = 0; // et une moyenne.
printf("Combien d'etudiants ?");
scanf("%d", &n);
// Remplissage du tableau en fonction de n (le nombre d'étudiants)
for(i=0; i<n; i++)
{
printf("Nom ?");
scanf("%s", profil[i].nom);
printf("Moyenne ?");
scanf("%lf", &profil[i].moyenne);
}
for(i=0; i<n; i++)
{
afficheProfil(profil[i]); // J'affiche chaque case du tableau donc les moyennes n'ont pas encore profité du bonus
}
printf("\n\n***** ACTUALISATION APRES BONUS *****\n\n"); //On rentre dans le coeur de la fonction
for(i=0; i<n; i++) // Je parcours mon tableau de type "etudiant"
{
if(profil[i].moyenne >= 10 && profil[i].moyenne <= 15) // Ajout des 0.5 point bonus
{
profil[i].moyenne = profil[i].moyenne + 0.5;
}
else if(profil[i].moyenne < 10) // Ajout du point bonus.
{
profil[i].moyenne++;
}
}
for(i=0; i<n; i++)
{
afficheProfil(profil[i]); //copier/coller des lignes 38 à 41 pour afficher les cases du tableau avec
} //les moyennes actualisées.
return 0;
}
void afficheProfil( etudiant profil) // je crée une fonction qui m'affiche chaque case du tableau.
{
printf("========\n");
printf("Nom: %s\n", profil.nom);
printf("Moyenne: %lf\n", profil.moyenne);
}
La qualité de l'indentation peut être très subjective ... Tu mets le for en colonne 5 et son { en colonne 9 et la suite en colonne 13. On met d'habitude l' { en même colonne que le for et la suite n'est décalé que de 4 par rapport au for. Et personnellement, je préfère l' { SUR la ligne for: for( ... blablabla ... ) {
Le Tout est souvent plus grand que la somme de ses parties.
Une fonction ajouterBonus applicable à un etudiant, ça serait bien.
LireEtudiant aussi.
une fonction AfficherTousLesEtudiants, qui appelera afficheProfil. Ça évitera les boucles identiques lignes 32 et 52.
Edit: pour l'indentation, à chacun sa manère tant que ça reste lisible. Le défaut que je vois ici: 2 boucles for avec un if place le code qui se trouve dans le if en colonne 29. C'est quand même fort loin. Et une ligne est "perdue" à chaque ouverture d'accolade.
- Edité par edgarjacobs 23 octobre 2021 à 17:28:08
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
@edgarjacobs: est-ce que tu préfères l'accolade sur la ligne d'appel comme moi? Ou du moins, la placer au même niveau que le for, if, etc. Des fonctions pour saisir, ajouter, lister les éléments, pourquoi pas?
Le Tout est souvent plus grand que la somme de ses parties.
for (size_t i = 0; i < len; i++)
for(size_t j = 0; j < len; j++)
parce que le langage C, avec son usage immodéré des symboles, ça fait vite du pâté qui ne se décrypte pas intuitivement. cf la fameuse boucle
while (n-->0) {
...
}
dont le sens est laissé en exercice.
Mais plus fondamentalement, lireEtudiant et ajouterBonus, ça serait l'occasion incontournable de passer l'adresse d'une structure. Vu que là c'était des passages de copies, là où en rréalité on mettrait plutôt des pointeurs vers des structures constantes.
- Edité par michelbillaud 23 octobre 2021 à 19:05:15
@michelbillaud: entièrement d'accord avec toi, c'est une habitude que je n'arrive pas à prendre (ou à perdre). Quand j'ai commencé à programmer, c'était sur cartes perforées, on ne s'enquiquinait pas à mettre un espace si ce n'était pas nécessaire. Ça m'est resté.
Edit suite à n-->0: là, je mettrai un espace pour que le code soit clair.
- Edité par edgarjacobs 23 octobre 2021 à 18:12:02
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Le Tout est souvent plus grand que la somme de ses parties.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Le Tout est souvent plus grand que la somme de ses parties.
Mais je ne mets jamais l'accolade ouvrante si le code qui suit ne comporte qu'une instruction. Donc, ça devient
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent