Langage C

Discutez d'informatique ici !
Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 09 Déc 2013, 10:28

Salut désolé pour le temps de réponse j'ai eu une coupure sur ma fibre; ou plutôt une mise à jour hors comme c'était la première fois je n'ai pas pu me débloquer avant d'avoir eu l'assistance ce matin...

Bref de retour à la civilisation ;)




Vous me conseiller donc de stocker mes valeurs de structure dans un tableau pour être sur de pouvoir les retrouver afin de ne lire le registre qu'une seule fois c'est ça ?


J'ai toujours du mal à comprendre comment on peut "demander" une variable avec fscanf ou toute autre fonction (cela dit je vous accorde je viens de récupérer ma connexion donc pour le coup j'ai pas vraiment chercher).


Si je prend un fichier qui contient les lignes suivantes:

Je suis
un imbécile.

Comment je procède pour récupérer chacun des mots tour à tour ?

Je suppose que l'on a deux boucles imbriqué.

Tant que non fin du fichier / Tant que non fin de ligne / stockage mot

Aucune idée pour le moment de comment l'on parcourt le dossier; j'ai compris comment écrire en effaçant ou en concaténant avec w et a; mais pour ce qui est d'une demande en lecture avec r ... je vois pas désolé.
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !



Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 09 Déc 2013, 10:54

Bonjour,

Tout simplement :

Code: Tout sélectionner
char mot1[20 + 1] = {0};
char mot2[20 + 1] = {0};
char buffer[255 + 1] = {0};
int nb = 0;
FILE *file = NULL;

file = fopen(PATH, "r");

while (fgets(buffer, 255, file) != NULL) {
    nb = sscanf(buffer, "%s %s", mot1, mot2);
    printf("%s %s\n", mot1, mot2);
}

fclose(file)


N'oublie pas de vérifier 2 choses :

1) L'ouverture du fichier
2) Le nombre de paramètre nb récupéré si c'est différent de 2, alors il y a une erreur

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 09 Déc 2013, 11:04

D'accord mais dans cet exemple on sait que nb=2; mais il se peut que pour une ligne ce soit 2 et pour une autre 5. Il se peut que l'utilisateur voir le programmeur ne sache pas combien de mot seront contenus sur une ligne. Dans ce cas là le test ne peut se faire.


Pour l'ouverture du fichier ok; je l'ai aussi dans mon pseudo mémo du tp, mais je ne comprends pas ce que l'on teste quand on met NULL. NULL ce serait la fin du fichier ?
Autre chose dans cet exemple comment tu différencies par la suite mot1 de la première ligne et mot2 de la seconde ligne.


Et enfin ultime question car c'est ainsi que c'est écrit dans mon sujet (comme tu l'as fait toi)

Pourquoi écrire mot1[20 + 1] au lieu de mot[21]

N'est ce pas la même chose ?
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 09 Déc 2013, 11:24

Rockleader a écrit:D'accord mais dans cet exemple on sait que nb=2; mais il se peut que pour une ligne ce soit 2 et pour une autre 5. Il se peut que l'utilisateur voir le programmeur ne sache pas combien de mot seront contenus sur une ligne. Dans ce cas là le test ne peut se faire.


Ce n'est plus le même problème à ce moment là, tout dépend de ce que tu veux. Si tu ne connais pas le nombre de mot, tu vas devoir traiter la chaine de caractère toi-même ou utiliser un séparateur (';' ':') pour séparer tes champs.

La fonction strtok pourrait t'être d'une grande aide.

Pour l'ouverture du fichier ok; je l'ai aussi dans mon pseudo mémo du tp, mais je ne comprends pas ce que l'on teste quand on met NULL. NULL ce serait la fin du fichier ?
Autre chose dans cet exemple comment tu différencies par la suite mot1 de la première ligne et mot2 de la seconde ligne.

Pour répondre à cette question, il te suffit de faire un man fgets et de regarder valeur de retour :

src : http://www.linux-kheops.com/doc/man/manfr/man-ascii-0.9/man3/fgets.3.txt.html
fgets() renvoient le pointeur s si elles
réussissent, et NULL en cas d'erreur, ou si la fin de
fichier est atteinte avant d'avoir pu lire au moins un
caractère.



Et enfin ultime question car c'est ainsi que c'est écrit dans mon sujet (comme tu l'as fait toi)

Pourquoi écrire mot1[20 + 1] au lieu de mot[21]

N'est ce pas la même chose ?


C'est exactement la même chose, ce n'est qu'une notation. Cela me permet de voir rapidement qu'on attribue une taille de 20 caractères pour mot + 1 caractère du '\0'.

Libre à toi d'utiliser ou non cette notation.

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 09 Déc 2013, 12:07

Oki; je verrais plus tard strtok; en attendant sachant que j'ai moi même initialisé le fichier réptertoire.



LE but de ce sous programme est de déterminé au final si une chaine apparaît dans le fichier.


Voici les déclarations:

Code: Tout sélectionner
FILE *registre =NULL;
   registre=fopen(LISTE,"r");
   char pays[21] ={0};
   char capi[21]={0};
   int indi=0;
   char buffer[256];
   char paysCherche[21];
   printf("Entrez un nom de pays (en majuscule) :\n");
   scanf("%s",paysCherche);
   char test='n';


Suivi du corps du programme:
A noter que je n'ai pas testé le nombre avec sscanf puisque j'ai obligatoirement un fichier de cette forme avec 2 champ texte et un entier après avoir initialisé.
Code: Tout sélectionner
while (fgets(buffer, 255, registre) != NULL)
   {
       sscanf(buffer, "%s %s %d", pays, capi, &indi);
       if (paysCherche == pays)
       {
          test='o';
       }
   }



Affichage du résultat:

Code: Tout sélectionner
   if (test=='o') /*affichage résultat*/
   {
      printf("Le pays est dans la base de donnée\n");
   }
   else
   {
      printf("Le pays n'est pas dans la base de donnée\n");
   }
   fclose(registre);
}


Toutefois; l'on m'affiche toujours le résultat négatif.

En admettant que mon fichier contienne:

FRANCE PARIS 33
puis une autre série de pays capitale nuéro n fois etc etc


Lorsque je rentres dans paysCherche FRANCE; il devrait être capable d'effectuer la comparaison à moment donné et de trouver que les deux chaines sont similaire lorsque j'écris paysCherche=pays.

A moins que je ne doivent obligatoirement passé par une fonction supplémentaire du style strcpy (pas sur de la syntaxe).
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 09 Déc 2013, 12:13

Tu oublies tout simplement qu'en langage C tu ne peux pas comparer 2 chaines de caractères de cette manière chaine1 == chaine2.

Tu as besoin d'utiliser la fonction strcmp(chaine1, chaine2) == 0 alors identique sinon différent (pour plus d'info je te laisse faire un man strcmp).

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 09 Déc 2013, 12:20

ampholyte a écrit:Tu oublies tout simplement qu'en langage C tu ne peux pas comparer 2 chaines de caractères de cette manière chaine1 == chaine2.

Tu as besoin d'utiliser la fonction strcmp(chaine1, chaine2) == 0 alors identique sinon différent (pour plus d'info je te laisse faire un man strcmp).


Effectivement je savais qu'il y avait une fonction pour cela mais je ne me rappelais plus laquelle exactement. Effectivement maintenant j'ai le bon résultat.

L'on peut donc comparer 2 caractères (car sa revient à comparer des nombres en réalité); mais pas deux chaines sans fonctions.


Une question quand même; pourquoi à la compilation j'ai un warning qui me dit implicit declaration de strcmp. Ne devrait elle pas être connu dans une librairie ? D'ailleurs elle l'est forcement sinon le langage ne pourrait pas l'interpréter.

Merci bien.
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

joel76
Membre Relatif
Messages: 230
Enregistré le: 11 Fév 2013, 15:31

par joel76 » 09 Déc 2013, 12:48

strcmp est sans doute déclarée dans string.h.
Tu as raison, strcmp est définie dans une des lib incluses par défaut lors de la liaison des bibliothèques.
" implicit declaration" signifie que si tu ne déclares pas strcmp quelque part, pour le compilo, le retour de strcmp est un int, or, dans le .h strcmp retourne un char *, ce n'est pas grave si tu n'utilises pas le retour de strcmp, sinon, "y'en a qui ont eu des problèmes" !
[edit] C'est une grosse co****ie, strcmp renvoie un int[/edit]

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 09 Déc 2013, 13:25

"y'en a qui ont eu des problèmes" !


Peut être mais pour ça il faut essayer ! ;)

Le retour est un int puisqu'on compare avec 0.

Si je voulais la déclarer pour enlever ce warning je mettrais quoi du coup ? Et à ce moment là n'y aurait il pas un "conflit" de déclaration ?
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 09 Déc 2013, 13:30

Pour pouvoir utiliser strcmp, tu dois inclure

Rajoute simplement cette ligne :
Code: Tout sélectionner
#include


Tu as également une autre possibilité, utiliser la fonction memcmp incluse dans qui compare deux zones mémoires, mais un peu plus délicate à utiliser pour toi pour le moment. Je te la donne quand même pour ton apprentissage.

joel76
Membre Relatif
Messages: 230
Enregistré le: 11 Fév 2013, 15:31

par joel76 » 09 Déc 2013, 13:41

Rockleader a écrit:Le retour est un int puisqu'on compare avec 0.
j'ai dit une bétise, strcmp renvoie effectivement un int !

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 09 Déc 2013, 14:23

Hello; l'inclusion de la biblio a bien enlevé le warning.

Après avoir réussi à manipuler ces chaines de caractères dans des voids j'ai voulu retourner la chaine de caractère avec une fonction; mais je retombe sur la fameuse erreur de segmentation


cela n'est il pas la bonne méthode de faire :

Code: Tout sélectionner
char* fonction (void)
{
   char* c=NULL; /*j'aurais pu mettre un c[]*/
   printf("Chaine à traiter : ");
   scanf("%s",c);
   return c;
}

int main()
{
char* a=NULL;
*a=fonction();
printf("%s",a);
}
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 09 Déc 2013, 14:29

Bonjour,

Tu as besoin d'alloué de l'espace mémoire pour traiter ta chaine.

Par exemple :

Code: Tout sélectionner
#include
#include
#include

#define TBUFFER 1024
char* fonction (void) {
     char* c=NULL; /*j'aurais pu mettre un c[]*/
     c = calloc(TBUFFER + 1, sizeof(char));
     if (c == NULL) {
         printf("error : calloc : %s\n", strerror(errno));
         return NULL;
     }
     printf("Chaine à traiter : ");
     scanf("%s",c);
     return c;
}

int main() {
    char* a=NULL;
    a=fonction();
    if (a != NULL) {
       printf("%s",a);
    }
    free(a);
    a = NULL;
    return 0;
}

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 09 Déc 2013, 14:37

ok; là encore c'était bien cela qui bloquait il fallait rajouter ce calloc.


Prochaine étape man calloc ;)

Je suppose qu'il n'y a pas trop de différences avec malloc/calloc; je vais regarder ça.

Ensuite tu utilises free (je suppose que cela permet de "libérer" l'espace mémoire; mais cela n'a d’intérêt que si l'on remodifie pas la chaine ? Concrètement que peut il se passer si l'on ne libère pas l'espace alloué pour la variable ?
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 09 Déc 2013, 14:50

calloc : initialise la variable.

malloc ne le fait pas.

Pour résumer calloc = malloc + memset (pour faire gros)

A l'époque malloc + memset était ce qu'il y avait de plus rapide, l'utilisation d'un calloc pouvait faire perdre un peu de temps.

Maintenant c'est quasiment pareil, d'où je préfère l'utilisation du calloc.

Après une allocation mémoire, il est toujours nécessaire de faire un free de ta variable pour libérer la mémoire allouée.

Lorsqu'une quantité de mémoire est allouée, elle est reservée par ton programme et n'est donc pas accessible par d'autres programmes. Lorsque tu fais un free, la zone redevient utilisable par n'importe quel autre programme.

Actuellement, certains os font le ménage de la mémoire à ta place, c'est à dire que si tu oublies de désallouer la zone mémoire, l'os le fera (ou pas, cela dépend vraiment de ton os et du programme).

Concrètement, gros ralentissement de ton pc car n'importe quel programme ne pourra plus accéder à suffisemment de mémoire pour continuer.

Supposons que ton programme utilise de grosse chaine de caractère et que tu utilises 1Mo de mémoire non libéré.

Au bout de 100 utilisations de ton programme, 100Mo de mémoire ne sera plus disponible.

Au bout de 20000 utilisations de ton programme 2Go de mémoire ne sera plus disponible. Comprends-tu le problème que cela implique ?

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 09 Déc 2013, 15:05

Et comment; c'est un truc à flinguer son pc ça O_o

Je n'oublierais plus de mettre un free désormais è_é


Sa veut dire qu tout à l'heure lorsque j'ai testé ma chaine avec un calloc à 1024 sans mettre de free après j'ai "perdu" un octet de mémoire utilisable. Perdu définitivement ou dès a fermeture du programme en question cela libère l'espace alloué ?
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 09 Déc 2013, 15:33

Comme expliqué cela dépend de ton os, mais actuellement la plus part des os font un nettoyage de la mémoire à la fin d'un programme.

Je te conseille de le voir en effet comme une perte seche c'est à dire tu as perdu (non pas 1 octet) mais 1024 :D.

Cela te permettra d'éviter par la suite d'omettre la libération de la mémoire allouée. Par ailleurs, il existe des outils permettants de vérifier qu'il n'y a pas de perte de mémoire ou de fuite (valgrind par exemple).

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 09 Déc 2013, 18:34

J'ai donc perdu 1Mo...bon sur 900 Go pas très grave mais quand même heureusement que j'ai pas fait boucler le programme è_é.

Je n'oublierais plus le free ça c'est sur !

Après la séance d'aujourd'hui; j'ai un peu plus progressé dans mes fichiers je comprends de mieux en mieux le mécanisme je pense, par contre j'ai encore pris une erreur de segmentation sur mon dernier programme j'y réfléchis encore un peu, puis je vous remontre ça si je n'arrive pas à trouver la solution.

Merci une nouvelle fois de votre aide !
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 09 Déc 2013, 19:37

Attention on parle pas de mémoire espace disque mais de mémoire ram, je doute que tu ais 900Go de ram :D

Pour déboguer tu peux regarder du côté de gdb. Cela te permettra de voir où il y a un problème.

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 09 Déc 2013, 19:40

Attention on parle pas de mémoire espace disque mais de mémoire ram, je doute que tu ais 900Go de ram

Ah d'accord. Au pire si la ram vient à manquer on devrait pouvoir désallouer de l'espace de la mémoire vive pour la renvoyer vers la ram nan ?
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

 

Retourner vers ϟ Informatique

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 5 invités

Tu pars déja ?



Fais toi aider gratuitement sur Maths-forum !

Créé un compte en 1 minute et pose ta question dans le forum ;-)
Inscription gratuite

Identification

Pas encore inscrit ?

Ou identifiez-vous :

Inscription gratuite