Alors, comme informaticienzero, je poste mon code niveau 2 :
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
/*Liste chainee*/
typedef struct Atome
{
char nom[3];
float val;
struct Atome *suiv;
} Atome;
/*Calcule la masse atomique d'un atome*/
float calcul_masse(Atome *liste, char *s)
{
Atome *tmp = liste;
float masse = 0.0;
if(liste->suiv != NULL)
{
while(tmp != NULL)
{
if(strcmp(s, tmp->nom) == 0) /*Si l'atome s est egal a l'un des atomes de la liste*/
{
masse = tmp->val;
break; /*On quitte la boucle*/
}
tmp = tmp->suiv;
}
}
printf("\t%s = %f\n", tmp->nom, masse);
return masse;
}
/*Calcule la masse moleculaire d'une modecule*/
float masse_moleculaire(Atome *liste, char mol[])
{
float masse = 0.0;
int i = 0;
int t = strlen(mol);
char tmp[3] = ""; /*Atome actuel*/
printf("\nLa masse moleculaire actuelle --> %f\n", masse);
while(i <= t)
{
if((isupper(mol[i])) != 0) /*Si c'est un atome*/
{
tmp[0] = mol[i]; /*tmp prend la premiere lettre du nom de l'atome*/
if(i < t && islower(mol[i+1]) != 0) /*Si le caractere suivant est en minuscule (= atome a plusieurs lettres)*/
{
tmp[1] = mol[i+1]; /*tmp se complete avec la deusieme lettre de l'atome*/
i++;
}
masse += calcul_masse(liste, tmp); /*On met a jour la masse actuelle*/
printf("La masse moleculaire apres l'ajout de la valeur ci-dessus --> %f\n\n", masse);
}
sprintf(tmp, " "); /*On reinitialise tmp (l'atome actuel)*/
i++;
}
return masse;
}
/*Affiche la liste*/
void afficher_liste(Atome *liste)
{
Atome *tmp = liste;
if(liste->suiv != NULL)
{
while(tmp != NULL)
{
printf("%s %f\n", tmp->nom, tmp->val);
tmp = tmp->suiv;
}
}
}
/*Ajoute un atome dans la liste*/
Atome *ajout(Atome *liste, char nom[], float val)
{
Atome *tmp = malloc(sizeof(Atome));
if(tmp == NULL)
{
exit(EXIT_FAILURE);
}
/*On copie les attributs mis en argument dans la liste*/
sprintf(tmp->nom, nom);
tmp->val = val;
tmp->suiv = liste;
return tmp; /*On renvoie le nouvel atome*/
}
/*Renvoie la liste d'atome qu'il y a dans le fichier*/
Atome *liste_atomes(FILE *fichier)
{
Atome *liste = NULL;
float val = 0;
char nom[3] = "";
while(nom[0] != '~') /*Si on est pas a la fin du fichier*/
{
fscanf(fichier, "%02s %f", nom, &val); /*On copie les attributs de l'atome actuel qui se trouve dans le fichier*/
if(nom[0] != '~') /*Si on est pas a la fin du fichier, on ajoute l'atome actuel dans la liste*/
liste = ajout(liste, nom, val);
}
return liste;
}
int main(void)
{
FILE *fichier = NULL;
Atome *liste = NULL;
char mol[100] = "";
if((fichier = fopen("atomes.txt", "r")) == NULL)
exit(EXIT_FAILURE);
liste = liste_atomes(fichier);
/*Affiche la liste des atomes connus*/
afficher_liste(liste);
printf("\n>>> ");
scanf("%s", mol);
printf("\nLa masse molaire de cette molecule est %f g.mol-1\n\n\n", masse_moleculaire(liste, mol));
fclose(fichier);
return EXIT_SUCCESS;
}
Aucun warning sous GCC avec une bonne douzaine d'option de compilation.
Un petit exemple d’exécution :
Na 22.989000
Cl 35.452999
Li 6.941000
He 4.002600
H 1.007900
O 15.999000
C 12.011000
>>> HeOCCClOb
La masse moleculaire actuelle --> 0.000000
He = 4.002600
La masse moleculaire apres l'ajout de la valeur ci-dessus --> 4.002600
O = 15.999000
La masse moleculaire apres l'ajout de la valeur ci-dessus --> 20.001600
C = 12.011000
La masse moleculaire apres l'ajout de la valeur ci-dessus --> 32.012600
C = 12.011000
La masse moleculaire apres l'ajout de la valeur ci-dessus --> 44.023600
Cl = 35.452999
La masse moleculaire apres l'ajout de la valeur ci-dessus --> 79.476597
Aucun atome 'Ob' n'a ete trouve, masse = 0.0
La masse moleculaire apres l'ajout de la valeur ci-dessus --> 79.476593
La masse molaire de cette molecule est 79.476593 g.mol-1
J'espère avoir fait un boulot relativement correct.
Je m'attaquerai au level 3 un peu plus tard dans la journée.
Voici enfin mon code. Et pour une fois, en français.
Étant donné qu'il s'agit d'une syntaxe linéaire, je me suis contenté d'une lecture en place de la formule entrée, sans traitement préalable.
Pour la lecture du fichier, je charge toutes les infos dans un grand tableau statique et sans les trier, c'est plus simple. J'aurais sans doute pu faire plus performant avec un tri alphabétique par exemple, mais je ne me suis pas fatigué.
PS: Pour la bonne cause, je me suis amusé à recoder une fonction de lecture de fichier avec allocation dynamique de mémoire (j'aurais bien utilisé scanf("%as") mais c'est une extension GNU).
Je pense encore l'améliorer, notamment au niveau de la lecture du nom d'un atome de la formule et de la recherche de sa masse (deux fonctions séparées actuellement, je pense pouvoir faire directement la recherche avec une comparaison en place plutôt que de recopier le nom d'abord).
Je suis allé jusqu'au niveau 4.
Pour les parenthèses, je gère les imbrications infinies simplement avec de la récursivité.
Je ne vois pas trop l'intérêt du niveau 5 (avec scanf et fprintf, c'est fait en moins de deux), d'autant plus que ça compliquerait "l'interface utilisateur".
En revanche, je pense pouvoir mettre en place facilement l'affichage du détail des calculs (avec un petit bonus dont j'ai idée mais qui me pose des problèmes conceptuels).
Je n'ai pas fait beaucoup de tests, mais ça a l'air de fonctionner normalement pour chaque cas de figure (une parenthèse en trop, manquante, un atome inconnu…).
Excusez la présentation et les commentaires absents ou pas clairs, c'est fait à la va-vite.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
typedef struct Atome {
double masseMol;
char nom[3];
} Atome;
/* vérifie que le nom de l'atome est valide (au plus les 2 premiers caractères) */
int nomAtomeValide(const char* nom) {
return isupper(nom[0]) && (!nom[1] || islower(nom[1]));
}
/* lit le fichier et en extrait les informations, qu'on enregistre dans le
tableau de structures `Atome` pointé (contenant `nbTab` éléments aux maximum) ;
renvoie le nombre d'atomes lus */
size_t chargerInfos(FILE* f, Atome tabInfos[], size_t nbTab) {
size_t i = 0;
int r = 2;
rewind(f);
while(r!=EOF && i<nbTab) {
r = fscanf(f, "%2s %lf\n",
tabInfos[i].nom,
&tabInfos[i].masseMol);
if(r!=EOF && !nomAtomeValide(tabInfos[i].nom))
fprintf(stderr, "erreur dans le fichier d'informations :"
" nom d'atome invalide : '%s'\n", tabInfos[i].nom);
else if(r==1)
fputs("erreur dans le fichier d'informations :"
" saisie invalider : il manque la masse molaire\n",
stderr);
else
++i;
}
return i-1;
}
/* écrit le nom d'atome se trouvant au début de la chaîne `formule`.
Retourne l'adresse du 1er caractère non-lu. */
void lireNomAtome(const char** formule, char* nom) {
if(isupper(**formule)) {
*nom++ = *(*formule)++;
if(islower(**formule))
*nom++ = *(*formule)++;
}
*nom = '\0';
}
/* renvoie la masse molaire de l'atome du nom spécifié */
double masseMolAtome(const char* nom, const Atome tabInfos[], size_t nbTab) {
size_t i;
for(i=0; i<nbTab; ++i)
if(strcmp(nom, tabInfos[i].nom) == 0)
return tabInfos[i].masseMol;
fprintf(stderr, "erreur : atome inconnu : '%s'\n", nom);
return 0.0;
}
/* calcule la masse molaire de la molécule dont la formule est passée en
argument (sous la forme d'un pointeur sur un pointeur sur char). S'arrête au
caractère spécifié ; retourne le résultat et met le pointeur `*formule` sur
le dernier caractère lu. */
double calculerMasseMol(const char** formule, char cFin,
const Atome tabInfos[], size_t nbTab) {
double r = 0,
masseMol,
coeff;
char nomLu[3];
while(1) {
if(**formule=='(') {
++*formule;
masseMol = calculerMasseMol(formule, ')',
tabInfos, nbTab);
r += masseMol;
if(**formule) ++*formule;
}
else if(**formule == cFin)
return r;
else if(**formule==')' || **formule=='\0') {
fputs("erreur : fin ou parenthèse fermante inattendue\n",
stderr);
return r;
}
else if(isdigit(**formule)) {
coeff = (double)atoi(*formule);
r += (coeff-1)*masseMol;
while(isdigit(**formule)) ++*formule;
}
else if(isupper(**formule)/*nomAtomeValide(*formule)*/) {
lireNomAtome(formule, nomLu);
masseMol = masseMolAtome(nomLu, tabInfos, nbTab);
r += masseMol;
}
else {
fprintf(stderr, "erreur : saisie invalide à partir"
" d'ici : `%s`\n", *formule);
return r;
}
}
}
/* écrit toute la ligne du fichier ('\n' exclus) dans un buffer dynamique et
renvoie ce buffer */
char* lireLigneFichier(FILE* f) {
char *s, *p;
int c;
size_t size = 0,
capac = 32;
s = malloc(capac*sizeof(char));
if(s==NULL) exit(EXIT_FAILURE);
while((c=fgetc(f)) != '\n' && c!=EOF) {
s[size] = c;
++size;
if(size >= capac) {
capac *= 2;
p = realloc(s, capac*sizeof(char));
if(p==NULL) {
free(s);
return NULL;
}
s = p;
}
}
s[size] = '\0';
p = realloc(s, (size+1)*sizeof(char));
if(p==NULL) {
free(s);
return NULL;
}
return p;
}
int main(int argc, char** argv) {
FILE* f;
Atome tabInfos[118]; // il y a jusqu'à 118 atomes dans la classification périodique
char* formule;
const char* p;
double res = 0;
size_t nbTab;
f= fopen("mol.inf", "r+");
if(f==NULL) {
fputs("erreur : échec à l'ouverture du fichier"
" d'informations.\n", stderr);
return EXIT_FAILURE;
}
nbTab = chargerInfos(f, tabInfos, sizeof(tabInfos)/sizeof(*tabInfos));
if(argc==1) {
fputs("Entrez une molécule :\n>>> ", stdout);
//scanf("%as", &formule);
formule = lireLigneFichier(stdin);
} else
formule = argv[1];
//printf("formule entrée : %s\n", formule);
p = formule;
res = calculerMasseMol(&p, 0, tabInfos, nbTab);
printf("masse molaire moléculaire : %f g.mol-1\n", res);
if(argc==1) free(formule);
fclose(f);
return EXIT_SUCCESS;
}
En effet, 200 lignes n'étaient pas de trop… Je me tairais la prochaine fois (je n'ai aucun « compas dans l'œil »).
Ces exos sont pour débutants, et s'adressent principalement à un public qui n'a pas encore forcément réalisé de parser (mais c'est prévu dans la liste de GuilOooo ).
Oui. Surtout que ici, à moins de demander une gestion d'erreurs complète, l'évaluation est notablement plus simple.
Concernant la gestion des erreurs, on peut assez facilement gérer les parenthèses (Pouet à proposé une methode, j'en propose une différente ci-dessous, il me semble que d'autres aussi en ont mis), mais je ne crois pas que ce soit si facile de gérer tous les types d'erreurs, il va falloir définir une grammaire à un moment, et il ne semble pas que ce soit le but de l'exo. Exemple, supposons que ceci soit une erreur (je pense que ça devrait l’être) : O2 5, il faut encore surcharger le code pour gérer ça, etc. A terme, ce n'est pas viable, il me semble.
Code modifié pour la gestion des parenthèses (j'aime pas trop) :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define filename "Atomes.txt"
#define ATOM_NAME_SZ 8
#define INPUT_SZ 80
typedef struct
{
char nom[ATOM_NAME_SZ];
double masse;
} Atome;
typedef struct _ls
{
Atome at;
struct _ls* next;
} Lst_Atomes;
typedef struct
{
size_t size;
Atome* array;
} Tab_Atomes;
/* fonction de comparaison, pour trier les atomes par noms */
static int cmp (const void* a, const void *b)
{
return strcmp ( ((Atome*)a)->nom, ((Atome*)b)->nom );
}
/* fonction qui charge le fichier à l'aide d'une liste chainée,
puis passe le tout dans un tableau,
et retourne le tableau trié par nom */
Tab_Atomes chargement_fichier (void)
{
FILE* infile = NULL;
Lst_Atomes* lst = NULL;
size_t sz = 0;
/* charge le contenu du tableau dans une liste chainee */
if ( (infile = fopen(filename, "r")) != NULL )
{
Atome a;
while ( fscanf(infile, "%s %lf\n", a.nom, &a.masse) == 2 )
{
Lst_Atomes* nelem = malloc(sizeof *nelem);
nelem->at = a, nelem->next = lst, lst = nelem;
++sz;
}
fclose(infile);
}
/* initialise le tableau */
Tab_Atomes tab;
tab.size = sz;
tab.array = malloc(sz * sizeof(Atome));
/* on remplit le tableau et on free la liste en meme temps */
size_t i;
for (i=0; i<tab.size; ++i)
{
tab.array[i] = lst->at;
Lst_Atomes* tmp = lst;
lst = lst->next, free(tmp), tmp = NULL;
}
/* on trie les atomes par noms, pour utiliser bsearch ulterieurement */
qsort(tab.array, sz, sizeof *(tab.array), cmp);
return tab;
}
/* fonction qui effectue le parsing de l'expression,
et calcule la masse molaire à la volée */
double _eval (char** pinput, Tab_Atomes liste_atomes)
{
double retval = 0, current = 0;
while (**pinput)
{
char name[ATOM_NAME_SZ] = "";
if (isalpha(**pinput)) /* Atome */
{
retval += current;
char* start = *pinput;
size_t sz = 1;
while ( islower(*++*pinput) ) /* avance tant qu'on trouve des lettres minuscules */
++sz;
strncpy(name, start, sz);
Atome* at = bsearch(name, liste_atomes.array, liste_atomes.size, sizeof(Atome), cmp);
if (at == NULL) /* si l'atome correspondant n'est pas trouvé dans le tableau - erreur */
{
fprintf(stderr, "Atome inconnu '%s': arret.\n", name);
exit(1);
}
current = at->masse;
}
else if (isdigit(**pinput)) /* Quantite */
{
char* end;
unsigned factor = strtoul(*pinput, &end, 10);
*pinput = end;
current *= factor;
}
else if (**pinput == '(')
{
++*pinput;
retval += current;
current = _eval(pinput, liste_atomes); /* on fait un appel recursif */
if (**pinput == ')')
{
++*pinput;
break;
}
else
{
fprintf(stderr, "Erreur : parenthses fermante attendue.\n");
exit(1);
}
}
else if (isspace(**pinput))
{
++*pinput;
}
else /* Entrée non reconnue */
{
break;
}
}
return retval + current;
}
double eval (char* input, Tab_Atomes liste_atomes)
{
double ret = _eval(&input, liste_atomes);
if (*input != '\0') /* si toute la chaine n'a pas pu etre évaluée */
{
fprintf(stderr, "Entree inattendue : arret.\n");
exit(1);
}
return ret;
}
int main()
{
Tab_Atomes liste_atomes = chargement_fichier();
char input[INPUT_SZ];
while (1)
{
printf( "Entrez une molecule : \n--> " );
if ( fgets(input, INPUT_SZ, stdin) != NULL )
{
printf("\nLa masse molaire de cette molecule est %lf g.mol-1\n\n", eval(input, liste_atomes));
}
}
free(liste_atomes.array);
return 0;
}
O2 5, il faut encore surcharger le code pour gérer ça, etc. A terme, ce n'est pas viable, il me semble.
Mais, suffit de se faire une fonction qui te dit dès le début si ta chaîne est correct ou pas.
Cette fonction fera appel à une autre fonction qui elle seule regardera si tout est bien parenthésé.
Et ainsi de suite.
Pour ton cas: O2 5 bah faut faire une autre fonction qui regarde si avant chaque digit on ne trouve pas un espace puis c'est fini.
Le code qui calcul ne doit pas constamment vérifier si la chaîne est correct.
Mais, suffit de se faire une fonction qui te dit dès le début si ta chaîne est correct ou pas.
Cette fonction fera appel à une autre fonction qui elle seule regardera si tout est bien parenthésé.
Et ainsi de suite.
Pour ton cas: O2 5 bah faut faire une autre fonction qui regarde si avant chaque digit on ne trouve pas un espace puis c'est fini.
OK, mais c'est ce que j'appelle du bricolage. Même si ça tient ici, l'approche reste globalement mauvaise.
Citation : Mr21
Le code qui calcul ne doit pas constamment vérifier si la chaîne est correct.
Une fois que tu as défini une grammaire, tu as le choix entre séparer les étapes (plus propre), ou mettre tout ensemble (plus fun).
Je viens soumettre ma solution pour le niveau quatre. La molécule et le nom (ou chemin) du fichier sont transmis dans les paramètres de main. Je verrais comment modifier/améliorer mon code plus tard. Pour le moment, je me suis contenter aux tests de l'énoncé.
Le code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* Unité de la masse molaire moléculaire. */
const char unite[] = "g.mol-1";
struct Atome
{
char nom[3]; /* le nom de l'atome */
float masse; /* sa masse */
int occurence; /* le nombre d'occurence (ou coefficient)
dans une molecule */
};
typedef struct Atome Atome;
/* Déterminer le nombre d'atomes dans une molécule.
* - paramètre: la molécule.
*
* Retourne le nombre d'atomes.
**/
size_t nombre_atomes(const char*);
/* Analyser la molécule en la séparant en différents
* atomes qui la constituent.
*
* - paramètre 1: la molécule;
* - paramètre 2: le tableau qui va contenir les différents atomes;
* - paramètre 3: la taille du tableau.
**/
void analyser(const char*, Atome*, size_t);
/* Obtenir la masse d'un atome.
* - paramètre 1: le nom de l'atome;
* - paramètre 2: le nom (ou chemin) du fichier dans
* lequel se trouve les atomes.
*
* Retourne la masse de l'atome.
**/
float valeur_masse(const char*, const char*);
/* Calculer la masse molaire moléculaire.
* - paramètre 1: tableau des atomes constituant la molécule;
* - paramètre 2: la taille de ce tableau.
*
* Retourne la masse de la molécule.
**/
float masse_molaire(Atome*, size_t, int);
/* Déterminer la valeur du coefficient.
* - paramètre 1: la molécule à traiter;
* - paramètre 2: le tableau qui contiendra les atomes;
* - paramètre 3: la taille du tableau.
*
* Retourne la valeur du coefficient.
**/
int traite(const char*, Atome*, size_t);
/* Vérifier si une phrase est bien parenthésée.
* - paramètre: la phrase à traiter.
*
* Retourne: 0 si oui et 1 si non.
**/
int zbrace(const char*);
/* (But de la fonction ici)
* - paramètre 1: la molécule à traiter;
* - paramètre 2: le nom du fichier dans lequel
* se trouve les atomes.
*/
void zmol(const char*, const char*);
int main(int argc, char * argv[])
{
if(argc >= 3){
zmol(argv[1], argv[2]);
}
else{
printf("\n***** Trop peu d'arguments reçus *****\n\n");
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
void zmol(const char * molecule, const char * fichier)
{
Atome * atomes = NULL;
size_t i, n;
float masse, temp;
int coeff;
n = nombre_atomes(molecule);
atomes = malloc(n * sizeof(*atomes));
if(atomes == NULL){
printf("\nErreur d'allocation du tableau d'atomes !\n");
exit(EXIT_FAILURE);
}
coeff = traite(molecule, atomes, n);
for(i = 0; i < n; i++){
temp = valeur_masse(atomes[i].nom, fichier);
if(temp)
atomes[i].masse = temp;
else{
printf("\nL'atome %s n'est pas dans le fichier !\n", atomes[i].nom);
exit(EXIT_FAILURE);
}
}
masse = masse_molaire(atomes, n, coeff);
printf("\nLa masse molaire du %s est: %.3f %s\n", molecule, masse, unite);
free(atomes);
}
void analyse(const char * molecule, Atome * atomes, size_t n)
{
size_t i, j, k, l;
for(i = j = 0; i < strlen(molecule) && j < n; i++){
if(isupper(molecule[i])){
if(islower(molecule[i + 1])){
strncpy(atomes[j].nom, &molecule[i], 2);
if(isdigit(molecule[i + 2]))
atomes[j].occurence = atoi(&molecule[i + 2]);
else
atomes[j].occurence = 1;
}
else if(isdigit(molecule[i + 1])){
strncpy(atomes[j].nom, &molecule[i], 1);
atomes[j].occurence = atoi(&molecule[i + 1]);
}
else{
strncpy(atomes[j].nom, &molecule[i], 1);
atomes[j].occurence = 1;
}
j++;
}
}
}
float masse_molaire(Atome * atomes, size_t n, int coeff)
{
size_t i;
float masse = 0.0;
for(i = 0; i < n; i++)
masse += atomes[i].masse * atomes[i].occurence;
return masse * coeff;
}
size_t nombre_atomes(const char * molecule)
{
size_t i, n = 0;
for(i = 0; i < strlen(molecule); i++){
if(isupper(molecule[i]))
n++;
}
return n;
}
float valeur_masse(const char * atomeAChercher,
const char * nomFichier)
{
FILE * fichier = NULL;
char atome[3];
float masse;
fichier = fopen(nomFichier, "r");
if(fichier == NULL){
printf("\nErreur d'ouverture du fichier !\n");
exit(EXIT_FAILURE);
}
else{
while(fscanf(fichier, "%s %f", atome, &masse) != EOF){
if(strcmp(atome, atomeAChercher) == 0){
fclose(fichier);
return masse;
}
}
fclose(fichier);
return 0;
}
}
int traite(const char * mol, Atome * atomes, size_t n)
{
size_t i;
char * p_ouverte = NULL;
char * p_fermee = NULL;
int coeff = 1;
if(zbrace(mol) == 0){
p_ouverte = strchr(mol, '(');
if(p_ouverte == NULL)
analyse(mol, atomes, n);
else{
p_fermee = strchr(mol, ')');
if(isdigit(mol[p_fermee - mol + 1])){
coeff = atoi(&mol[p_fermee - mol + 1]);
analyse(++mol, atomes, n);
}
else
analyse(++mol, atomes, n);
}
}
else{
printf("\nExpression mal parenthesee ! \n");
exit(EXIT_FAILURE);
}
return coeff;
}
int zbrace(const char * str)
{
int i;
int p_ouverte, p_fermee; /* pour parenthèses ouvertes
et fermées */
for(i = 0; str[i] != '\0' && str[i] != '(' && str[i] != ')'; i++)
;
p_ouverte = p_fermee = 0;
if(str[i] == ')')
return -1;
else{
for(; str[i] != '\0'; i++){
if(str[i] == '(')
p_ouverte++;
else if(str[i] == ')')
p_fermee++;
}
return p_ouverte - p_fermee;
}
}
En attendant vos remarques/critiques pour l'amélioration du code, merci
En TI-BASIC c'est encore plus simple qu'en C (si tu choisis la solution facile) : le parser est intégré de base. Il suffit juste de donner les bonnes valeurs aux variables :
1->H
12->C
etc...
- A demander une chaine sous une forme légèrement différente... (exemple : )
C+O+(C+H2+O+H)2
- Et à l'évaluer l'expression.
Input Chaîne1 // Demande à rentrer une chaine (Chaîne1, ou Str1 en Anglais, se trouve en appuyant sur 'Var' -> '7' (sur TI-82))
expr(Chaîne1)->R // La fonction expr évalue la chaine. On stocke le résultat dans R.
Disp R
Après si tu veux conserver le format d'entrée en respectant la norme d'affichage des molécules, effectivement c'est plus dur.
Edit : Et aussi ça peut poser problème pour les molécules à plusieurs caractères.
$ ./a.out
Atomes connus :
C 12.011000
O 15.999000
H 1.007900
He 4.002600
Li 6.941000
Cl 35.453000
Na 22.989000
> NaSO4
Na : 22.989000 g/mol
S non reconnu
Souhaitez-vous ajouter l'atome S ?
o
Masse molaire ?
32.066
NaS : 55.055000 g/mol
NaSO4 : 119.051000 g/mol
> CH3(CH2)5CH3
C : 12.011000 g/mol
CH3 : 15.034700 g/mol
C : 12.011000 g/mol
CH2 : 14.026800 g/mol
CH3(CH2)5 : 85.168700 g/mol
CH3(CH2)5C : 86.176600 g/mol
CH3(CH2)5CH3 : 89.200300 g/mol
> exit
$ ./a.out
Atomes connus :
C 12.011000
O 15.999000
H 1.007900
He 4.002600
Li 6.941000
Cl 35.453000
Na 22.989000
S 32.066000
> exit
$
Tu peux tout rassembler dans un seul ? Comme ça si l'on veut le tester ou l'analyser, on a juste à le copier ou à le lire d'un bloc. On perds en lisibilité paradoxalement en divisant.
"If debbugging is the process of removing bugs, then programming must be the process of putting them in." (Edsger Dijkstra)
Tu peux tout rassembler dans un seul ? Comme ça si l'on veut le tester ou l'analyser, on a juste à le copier ou à le lire d'un bloc. On perds en lisibilité paradoxalement en divisant.
J'ai édité mon message précédent pour ajouter un bloc où on a tout le code.
EDIT : d'ailleurs, l'exemple de la molécule NaSO4 n'existe pas. En effet, Na peut faire 1 liaison (<math>\(Na^+\)</math>) tandis que <math>\(SO_4\)</math> doit en faire 2. En effet, je ne connais pas l'ion <math>\(SO_4^-\)</math> mais connais l'ion <math>\(SO_4^{2-}\)</math>
Un petit exemple avec un ion existant :
$ ./a.out
Atomes connus :
C 12.011000
O 15.999000
H 1.007900
He 4.002600
Li 6.941000
Cl 35.453000
Na 22.989000
S 32.066000
> H2SO4
H2 : 2.015800 g/mol
H2S : 34.081800 g/mol
H2SO4 : 98.077800 g/mol
> exit
$
L'étape suivante de mon code pourrait consister à trier le tableau pour que la recherche soit plus rapide. Cependant, l'ajout en deviendrait plus lent.
D'ailleurs, l'exemple de la molécule NaSO4 n'existe pas. En effet, Na peut faire 1 liaison (<math>\(Na^+\)</math>) tandis que <math>\(SO_4\)</math> doit en faire 2. En effet, je ne connais pas l'ion <math>\(SO_4^-\)</math> mais connais l'ion <math>\(SO_4^{2-}\)</math>
En revanche, <math>\(\text{Na$_2$SO$_4$}\)</math> existe. (oui je sais je suis très utile)
Je tente de faire l'exercice 1 seulement j'ai un soucis sur la récup' de texte.
Une fois que je rentre ma lettre et fais entrée Windows me met un rapport d'erreur.
Je crois que j'ai quelques confusions entre là et ce que je fais à l'IUT en Ada.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define LECT carAct = fgetc(fichier);
void lectureFichier (FILE **fichier, char c, double *m)
{
char carAct = 0; // Caractère parcourant le fichier.
int trouve = 0, fact = 10;
LECT
while (carAct != EOF && trouve != 2) // Tant que l'on a pas fini et pas trouvé.
{
if (trouve)
{
if (carAct == ' ') // Si le caractère est suivi d'un espace.
trouve = 2; // C'est le bon élément : on sort de la boucle.
else
trouve = 0;
}
if (carAct == c) // Si le caractère lu est égal à celui trouvé,
trouve = 1;
LECT
}
if (trouve == 2) // Si on a trouvé la bonne ligne.
{
while (carAct != '\n')
{
if(carAct != '.') // Si ce n'est pas la virgule,
{
*m = *m + ((carAct - '0') * fact); // On ajoute à la masse molaire le chiffre * le facteur,
fact /= 10; // que l'on divise par 10 à chaque fois.
}
LECT
}
}
}
int main()
{
char c; // Caracère lu.
double m = 0; // Masse molaire.
FILE *fichier = NULL;
if(fichier = fopen("zMol.txt", "r") == NULL)
printf("Erreur lors de l'ouverture de zMol.txt");
printf("Entrez une molecule :\n--> ");
c = getchar();
while (c != EOF && c != '\n')
{
c = toupper(c);
lectureFichier(&fichier, c, &m);
c = getchar();
}
printf("\n\nLa masse molaire de cette molecule est %f g.mol-1", m);
fclose(fichier);
return 0;
}
Les rapports d'erreur de Windows sont des segfault.
Ton compilateur ne râle pas ? Pourtant, fgetc attend un FILE*, pas un FILE**.
Les formats sont utiles pour ne pas se compliquer la vie.
fscanf, sscanf,...
Ah oui merci ! Avec #define LECT carAct = fgetc(*fichier); ça va mieux.
Sinon problème pour les calculs. Comme par exemple C ça me met 12.000, ça vient de là :
if (trouve == 2) // Si on a trouvé la bonne ligne.
{
while (carAct != '\n')
{
if(carAct != '.') // Si ce n'est pas la virgule,
{
*m = *m + ((carAct - '0') * fact); // On ajoute à la masse molaire le chiffre * le facteur,
fact /= 10; // que l'on divise par 10 à chaque fois.
}
LECT
}
}
Voilà je me lance donc dans ce défi - que j'ai découvert grâce à mon cher Sabeurre que je remercie énormément pour ses conseils - en vous donnant mon code (niveau 5), et oui après en avoir suer sang et eau et avoir crier quelques fois je suis enfin arrivé à faire un programme qui fonctionne parfaitement Enfin parfaitement ... tout semble fonctionnait pour ma part.
Vous le remarquerez aussi j'ai quasiment concentrer tout mon programme dans une seule fonction donc c'est normale si vous la trouvez un peu longue
M'enfin trêves de bavardages et place au code, le voici donc :
Main.c :
#include <stdio.h>
#include <stdlib.h>
#define TAILLE_MOLECULE 20
#include "lecture.h"
int main(int argc, char* argv[])
{
char Molecule[TAILLE_MOLECULE] = {0};
double resultat = 0;
int mode = 0;
printf("Salut et bienvenue dans ce calculateur de masse molaire !\n");
printf("Choisissez votre mode :\n 1 - Calculer la masse molaire d'une molecule\n 2 - Ajouter un atome dans la liste de donnees\n ===> ");
scanf("%d", &mode);
viderBuffer();
if (mode == 1)
{
printf("Entrez une molecule => ");
lireCaractere(Molecule, TAILLE_MOLECULE);
resultat = calcul(Molecule);
printf("\n\nLa masse molaire de votre molecule est de %f g.mol-1", resultat);
}
else if (mode == 2)
{
ajouter();
}
else
{
printf("\nMauvais choix de mode, le programme va fermer.");
exit(0);
}
return 0;
}
lecture.h
#ifndef DEF_LECTURE
#define DEF_LECTURE
void viderBuffer();
int lireCaractere(char *Molecule, int taille);
double calcul(char *Molecule);
void ajouter();
typedef struct
{
char symbole[3];
double masse;
long coefficient;
}Element;
#endif
lecture.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "lecture.h"
void viderBuffer()
{
int c = 0;
while (c != '\n' && c != EOF)
{
c = getchar();
}
}
int lireCaractere(char *Molecule, int taille)
{
char *Position = NULL;
if (fgets(Molecule, taille, stdin) != NULL)
{
Position = strchr(Molecule, '\n');
if (Position != NULL)
{
*Position = '\0';
}
else
{
viderBuffer();
}
return 1;
}
else
{
viderBuffer();
return 0;
}
}
double calcul(char *Molecule)
{
Element Element[10];
int i = 0, j = 0, m = 0, n = 0;
long x = 1;
FILE* fichier = NULL;
char liste[200] = {0};
char test[15] = {0};
char masse[10] = {0};
char* position = NULL;
double resultat = 0;
while (i < strlen(Molecule))
{
if (Molecule[i] == '(')
{
x = strtol(strchr(Molecule, ')') + 1, NULL, 10);
i++;
}
else if (Molecule[i] == ')')
{
x = 1;
i+=2;
}
if (isupper(Molecule[i]) != 0 && islower(Molecule[i+1]) != 0 && isdigit(Molecule[i+2]) != 0)
{
Element[j].symbole[0] = Molecule[i];
Element[j].symbole[1] = Molecule[i+1];
Element[j].symbole[2] = '\0';
Element[j].coefficient = strtol(Molecule + i + 2, NULL, 10) * x;
i+=3;
}
else if (isupper(Molecule[i]) != 0 && isdigit(Molecule[i+1]) != 0)
{
Element[j].symbole[0] = Molecule[i];
Element[j].symbole[1] = '\0';
Element[j].coefficient = strtol(Molecule + i + 1, NULL, 10) * x;
i+=2;
}
else if (isupper(Molecule[i]) && islower(Molecule[i+1]) != 0)
{
Element[j].symbole[0] = Molecule[i];
Element[j].symbole[1] = Molecule[i+1];
Element[j].symbole[2] = '\0';
Element[j].coefficient = 1 * x;
i+=2;
}
else if (isupper(Molecule[i]) != 0)
{
Element[j].symbole[0] = Molecule[i];
Element[j].symbole[1] = '\0';
Element[j].coefficient = 1 * x;
i++;
}
else if (Molecule[i] == ')' || Molecule[i] == '\0')
{
Element[j].symbole[0] = '\0';
Element[j].masse = 0;
Element[j].coefficient = 0;
}
else
{
printf("Votre molecule n'est pas ecrite de facon correcte.\n");
exit(0);
}
j++;
}
fichier = fopen("mm_molecule.txt", "r");
if (fichier == NULL)
{
printf("Impossible d'ouvrir le fichier mm_molecule.txt\n");
exit(0);
}
while (!feof(fichier))
{
fgets(test, 200, fichier);
strcat(liste, test);
}
m = j;
for (j = 0; j < m; j++)
{
if(strstr(liste, Element[j].symbole) != NULL)
{
while (n < 10)
{
position = strstr(liste, Element[j].symbole) + 2 + n;
masse[n] = *position;
n++;
}
Element[j].masse = strtod(masse, NULL) * Element[j].coefficient;
resultat+= Element[j].masse;
}
else
{
printf("\nVotre symbole n'est pas repertorie dans notre liste d'elements chimiques.");
exit(0);
}
n = 0;
}
fclose(fichier);
return resultat;
}
void ajouter()
{
char Atome[3];
double masse = 0;
FILE* fichier = fopen("mm_molecule.txt", "r+");
printf("\nRentrez le symbole de l'atome : ");
lireCaractere(Atome, 3);
printf("Rentrez sa masse molaire : ");
scanf("%lf", &masse);
viderBuffer();
fseek(fichier, 0, SEEK_END);
fprintf(fichier, "\n%s %f", Atome, masse);
fclose(fichier);
printf("\nL'atome a ete correctement ajoute dans la liste.");
}
Etant donné que je viens de le finir à l'instant et qu'il est un peu tard je ne l'ai pas commenté, s'il faut le faire merci de me le dire et je m'en chargerai de suite
Et aussi, ce programme est mon premier programme après le pendu proposé par M@teo21 dans son tutoriel sur l'apprentissage en C donc n'hésitez pas à me traîner dans la boue et à bien critiquer mon code sur les erreurs ou détails à ne pas faire, je suis ici pour apprendre après tout
Je commence zmol et je rencontre un petit soucis:
je voudrais lire mon fichier et mettre ces données dans un tableau: pour cela j'ai créé une fonction get_Tab qui doit me renvoyer le nombre d'éléments de la table et une structure Element composée de deux variables char nom_Atome et double masse_Atome.
Mais voilà ça ne fonctionne pas comme je voudrais. Je suis sûre que la solution est sous mes yeux, cependant...
voici le code:
/*********************************************************************
* *
* Ce programme permet le calcul des masses molaires moléculaires *
* *
**********************************************************************/
int main(int argc, char *argv[])
{
char molecule[100] = "";
int nbElement = 0;
int atomeTabValid = 0;
Element Element[112];
/************************************************************
* *
* Recuperation de la molecule saisie par l'utilisateur *
* *
************************************************************/
/*******************************************************************
* *
* Recuperation des donnees du fichier fileElement dans un tableau *
* La fonction retourne le nombre d'element: nbElementTab *
* *
*******************************************************************/
int get_Tab(Element Element[])
{
int nbElementTab = 0;
FILE *pfichier = fopen("fileElement.txt", "r");
if(pfichier != NULL){
printf("ouverture reussi\n\n");
while(fgetc(pfichier) != EOF){
fscanf(pfichier, "%s %lf", Element[nbElementTab].nom_Atome, &Element[nbElementTab].masse_Atome);
nbElementTab++;
}
fclose(pfichier);
printf("Premier element %s a une masse de %f\n\n", Element[0].nom_Atome, Element[0].masse_Atome);
}
else{
printf("Fichier fileElement.txt introuvable\n\n");
return 0;
}
return 0;
× 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.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.
" Celui qui aime à apprendre est bien près du savoir " Confucius