[phpBB Debug] PHP Warning: in file [ROOT]/includes/functions.php on line 4980: session_start(): Write of lock failed
[phpBB Debug] PHP Warning: in file [ROOT]/includes/functions.php on line 4980: session_start(): Unable to clear session lock record
Langage C [395 réponses] : ϟ Informatique - Page 11 - 144358 - Forum de Mathématiques: Maths-Forum

Langage C

Discutez d'informatique ici !
Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 07 Déc 2013, 22:21

pourquoi déclares-tu des pointeurs de T_pays?
la vie est une fête :)



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

par Rockleader » 07 Déc 2013, 22:24

En remontant plus haut dans nos discussions; il m'avait semblé voir que c'était ainsi que l'on déclarait les structures.

Si j'enlève le pointeur à la déclaration je me prend toute une série d'erreur à la compilation.
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 07 Déc 2013, 22:28

Si j'enlève le pointeur à la déclaration je me prend toute une série d'erreur à la compilation.

ben fais un truc simple dans un premier temps.
Code: Tout sélectionner
struct A{
 int val;
};
int main(){
 struct A a;
 a.val=0;
 return a.val;
}
la vie est une fête :)

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

par Rockleader » 07 Déc 2013, 22:35

fatal_error a écrit:ben fais un truc simple dans un premier temps.
Code: Tout sélectionner
struct A{
 int val;
};
int main(){
 struct A a;
 a.val=0;
 return a.val;
}


Ceci marche; l'erreur de segmentation vient de la chaine de caractère pas de l'int

J'ai donc modifié en conséquence:

Code: Tout sélectionner
typedef struct
{
char* nom[21] ;
char* capitale[21] ;
int indicatif ;
} T_pays ;

void initRep(void)
{
   T_pays france ,italie,espagne; /*seuls ces 3 pays figureront dans l'archive de départ*/
   FILE *registre;
   registre=fopen(LISTE,"w"); /* "w" on crée ou efface le fichier puis on le remplit*/
   printf("test1\n");
      italie.nom[21]="ITALIE";italie.capitale[21]="ROME";italie.indicatif=39;
      espagne.nom[21]="ESPAGNE";espagne.capitale[21]="MADRID";espagne.indicatif=34;
      france.nom[21]="FRANCE";france.capitale[21]="PARIS";france.indicatif=33;
      fprintf(registre,"%s    %s    %d",italie.nom[21],italie.capitale[21],italie.indicatif); /*pour seulement 3 pays on ne surcharge pas avec un tableau*/
      fprintf(registre,"%s    %s    %d",espagne.nom[21],espagne.capitale[21],espagne.indicatif);
      fprintf(registre,"%s    %s    %d",france.nom[21],france.capitale[21],france.indicatif);
   fclose(registre);
}


Cela dit; l'erreur de segmentation est toujours là.
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 07 Déc 2013, 22:53

es-tu sur de la déclaration de ta chaine de caractères?
la vie est une fête :)

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

par joel76 » 07 Déc 2013, 22:55

Il faut faire strcpy(italie.nom, "ITALIE"), etc, etc, italie.nom est l'adresse d'un tableau dans la structure T_Pays.
Le code d'avant plantait car les pointeur *italie etc étaient à NULL, il faut les allouer par un malloc

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

par Rockleader » 07 Déc 2013, 22:56

fatal_error a écrit:es-tu sur de la déclaration de ta chaine de caractères?



Et bien écoute; j'ai testé ceci :

Code: Tout sélectionner
struct A{
 char* val[10];
};
int main()
{
 struct A a;
 a.val[10]="blabla";
 printf("%s\n",a.val[10]);
 return 0;
}


Qui me retourne bien blabla

Donc; je ne vois pas pourquoi sur ma fonction plus haut ça ne fonctionne pas; c'est exactement la même syntaxe si ce n’est la structure défini autrement mais les deux façons sont équivalente il me semble.
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 » 07 Déc 2013, 23:00

joel76 a écrit:Il faut faire strcpy(italie.nom, "ITALIE"), etc, etc, italie.nom est l'adresse d'un tableau dans la structure T_Pays.
Le code d'avant plantait car les pointeur *italie etc étaient à NULL, il faut les allouer par un malloc
Je n'avais pas vu que c'était un char* nom[21], pourquoi ce tableau de 21 pointeurs vers des chaînes de caractères ???
Pourquoi pas char nom[21] comme cela (me) semble plus simple ?
En plus en C, pour un tableau de 21 cases on va de 0 à 20 donc nom[21] est une adressse incorrecte.
italie.nom[21]="ITALIE" va faire des dégats en mémoire si ce n'est celui-la ce sera les suivants.

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

par Rockleader » 07 Déc 2013, 23:10

joel76 a écrit:Je n'avais pas vu que c'était un char* nom[21], pourquoi ce tableau de 21 pointur faire des chaînes de caractères ???
Pourquoi pas char nom[21] comme cela (me) semble plus simple ?
En plus en C, pour un tableau de 21 cases on va de 0 à 20 donc nom[21] est une adressse incorrecte.
italie.nom[21]="ITALIE" va faire des dégats en mémoire si ce n'est celui-la ce sera les suivants.


J'ai enlevé le char* et remis un simple char comme tu sembles le conseiller; mais ça continue à merder. Je n'arrive vraiment pas à le débugguer.
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 07 Déc 2013, 23:48

peux-tu montrer un code qui reproduit ton problème et le plus minimaliste/simplifié possible?
la vie est une fête :)

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

par Rockleader » 08 Déc 2013, 00:17

fatal_error a écrit:peux-tu montrer un code qui reproduit ton problème et le plus minimaliste/simplifié possible?


Plus simple que ça je ne pourrais pas faire:

Code: Tout sélectionner
typedef struct
{
char* nom[21] ;
char* capitale[21] ;
int indicatif ;
} A ;

int main()
{
 A a;
 a.nom[21]="blabla";
 a.capitale[21]="blabla2";
 a.indicatif=5;
 printf("%s %s %d\n",a.nom[21],a.capitale[21],a.indicatif);
 return 0;
}


Avec ce code là je compile sans erreur; mais je plante avec une erreur de segmentation à l'exécution.

Si avec la structure j'enlève le char* comme conseillé; je prends les erreurs suivantes:

Code: Tout sélectionner
test.c: In function ‘main’:
test.c:14:11: warning: assignment makes integer from pointer without a cast [enabled by default]
  a.nom[21]="blabla";
           ^
test.c:15:16: warning: assignment makes integer from pointer without a cast [enabled by default]
  a.capitale[21]="blabla2";
                ^
test.c:17:2: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
  printf("%s %s %d\n",a.nom[21],a.capitale[21],a.indicatif);
  ^
test.c:17:2: warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘int’ [-Wformat=]



Sur ce; je vais stopper là pour ce soir, à demain ;)

Merci encore du temps que vous passer sur mes problèmes farfelus ^^
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 » 08 Déc 2013, 00:52

Ton code corrigé
Code: Tout sélectionner
typedef struct
{
char nom[21] ;
char capitale[21] ;
int indicatif ;
} A ;

int main()
{
 A a;
 strcpy(a.nom, "blabla");
 strcpy(a.capitale, "blabla2");
 a.indicatif=5;
 printf("%s %s %d\n",a.nom,a.capitale,a.indicatif);
 return 0;
}

char* nom[21] ; declare un tableau de 21 pointeurs vers des chaînes de caractères, donc tu peux faire sans problème a.nom[0]="blabla"; a.nom[1]="blabla"; ... a.nom[20]="blabla"; si tu le désires.
Par contre lorsque tu fais a.nom[21] = "blabla" tu écris dans une zone qui n'a pas été réservée pour le tableau ce qui fait qu'on se trouve dans le cas typique de C, ça peut fonctionner comme ça peut ne pas fonctionner le célèbre undefined bahaviour

char nom[21]; déclare un tableau de 21 caractères dans la structure, tu peux y copier ce que tu veux en particulier la chaine de caractères "blabla", il faut la copier à l'adresse 0 du tableau donc on fait un strcpy(a.nom, "blabla"). Le strcpy copie le 0 final de la chaine, donc pour copier "blabla" il faut avoir un tableau d'au moins 7 caractères (6 de blabla plus le 0), on l'oublie souvent.

Merci encore du temps que vous passer sur mes problèmes farfelus ^^
Non, les problèmes habituels des débutants en C !

[EDIT] modification d'explications, mes idées étaient confuses à 1 h du matin :dodo: [/EDIT]

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 08 Déc 2013, 08:49

je laisse l'explication à Joel, je reviens juste sur la reproduction de l'erreur.
Plus simple que ça je ne pourrais pas faire:

Si, tu peux faire plus simple, on a mis en exergue que le problème venait de la gestion des chaines, à partir de là:
1) tu n'as pas besoin d'utiliser ET nom ET capitale, simplement un exemple juste avec la chaine nom
2) il n'y a pas de problèmes de structures, donc autant directement déclarer char* nom[21] dans main()
Code: Tout sélectionner
#include "stdio.h"
int main(){
 char* nom[21];
 nom[21]="blabla";
 printf("%s",nom);
 return 0;
}


parenthèses, les warning ne sont pas des erreurs, mais c'est bien de les considérer comme telles. :lol3:
la vie est une fête :)

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

par joel76 » 08 Déc 2013, 09:49

Code: Tout sélectionner
#include "stdio.h"
int main(){
 char* nom[21];
 nom[21]="blabla";
 printf("%s",nom);
 return 0;
}

Code faux, on est exactement dans le cas décrit plus haut : nom[21] se situe juste à coté de la zone réservée du tableau dont les cases sont numérotées de 0 à 20.

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

par Rockleader » 08 Déc 2013, 10:02

Le soucis fatal c'est que je n'étais pas sur que le problème vienne ou non de la structure donc j'ai préféré la garder !


Je m'en vais de ce pas voir à quoi sert la fonction strcpy; enfin j'ai compris à quoi elle sert mais j'aimerais bien voir comment elle fonctionne en détail ;)

Code: Tout sélectionner
Non, les problèmes habituels des débutants en C !


Peut être; mais pour vous, cela doit vous sembler bien embêtant. Donc merci encore.

il faut la copier à l'adresse 0 du tableau


C'est à dire; après avoir réalisé l'affectation ainsi, pour retrouver la chaine de caractère je dois faire un a.nom[0] ? Cela ne me semble pas correct.



Ensuite pour le char* si je te suis bien; j'aurais pu m'en sortir de cette façon là en évitant la zone '21' je suis sur qu'il y aurait eu un moyen.

Dans ma tête la chaine aurait marché comme ça:

a.nom[0] = 'b'
a.nom[1] = 'l'
a.nom[2] = 'a'
a.nom[3] = 'b'
a.nom[4] = 'l'
a.nom[5] = 'a'

Une chaine n'est elle pas un tableau de caractère au final ? Pour ça que je ne comprends pas pourquoi a.nom[10]="blabla" ne peut pas marcher.
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 » 08 Déc 2013, 10:41

il faut la copier à l'adresse 0 du tableau
imprécisition de ma part, je m'excuse : j'aurais du écrire dans la case 0 du tableau
Lorsqu'on déclare le tableau char *nom[21] on déclare un tableau de 21 case où se trouvent des adresses de chaînes de caractères, donc pas les chaines mais des adresses
par exemple lorsqu'on fait nom[20] = "blabla", le compilateur crée la chaine de caractères "blabla"' quelque part en mémoire (souvent en mémoire non modifiable) et écrit l'adresse du premier caractère de la chaine dans la case nom[0] (cette case contient en fait 4/6/8 octets selon les OS).

Maintenant si on déclare char nom[21], on dit que nom est un tableau de 21 caractères, nom[0] = "blabla" sera refusé à la compilation, car nom[0] d'après la déclaration est un caractère.

Que fait strcpy(dest, src) ? il suppose que son premier argument est une adresse valide où il pourra écrire une chaîne dont on lui donne l'adresse (en fait l'adresse du premier caractère). Cette copie s'effectuera jusqu'à ce que strcpy rencontre le caractère 0, il faut donc que la zone libre dont le premier caractère est donné par dest soit assez longue, on retrouve ce problème de undefined behaviour : si la zone est assez longue, OK pas de problème sinon, des fois ça marche des fois pas ! c'est pour ça qu'on dit qu'en C le programmeur doit savoir ce qu'il fait !

Dernier problème, celui des déclaration :
on peut déclarer et définir en même temps par
char toto[] = "blabla";
Le compilateur va réserver une zone en mémoire de 7 caractères et y écrira la chaine "blabla" en mettant au bout le zéro terminal.
Et donc tu aurais pu faire
A a = {"un", "deux", 5};

N'hésite pas à poser des questions, ce sont des questions essentielles pour bien comprendre le C.
Réponses ce soir !

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 08 Déc 2013, 10:45

Dans ma tête la chaine aurait marché comme ça:

a.nom[0] = 'b'
a.nom[1] = 'l'
a.nom[2] = 'a'
a.nom[3] = 'b'
a.nom[4] = 'l'
a.nom[5] = 'a'

Une chaine n'est elle pas un tableau de caractère au final

oui

Pour ça que je ne comprends pas pourquoi a.nom[10]="blabla" ne peut pas marcher.

"blabla", c'est un array de 7char, et tu récupères l'adresses du premier avec un const char* a="blabla" (a[0]=='b', a[1]=='l',...)

maintenant cque t'essaies de faire c'est
nom[10]<= addresse du tableau.
alors que tu t'attends à avoir nom[10]<='b'

Ton code équivaut à
Code: Tout sélectionner
int main(){
 char nom[1];
 const char* b="blabla";
 char test=(char)b;
 nom[0]=b;//nom[0] contient test, à savoir l'addresse du tableau b tronquée dans un char
 return 0;
}


Code: Tout sélectionner
nom[0] = "blabla" sera refusé à la compilation

non. voir au juste au dessus.

ps:
Code faux

remarque rassurante, le but était de reproduire l'erreur. :lol3:
la vie est une fête :)

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

par Rockleader » 08 Déc 2013, 13:23

Merci.


J'ai à présent un code fonctionnel qui m'initialise un fichier.

Code: Tout sélectionner
void initRep(void)
{
   FILE *registre;
   registre=fopen(LISTE,"w"); /* "w" on crée ou efface le fichier puis on le remplit*/
   T_pays france = {"FRANCE" , "PARIS" , 33};
   T_pays italie = {"ITALIE","ROME",39};
   T_pays espagne = {"ESPAGNE","MADRID",34}; /*seuls ces 3 pays figureront dans l'archive de départ*/
      fprintf(registre,"%s    %s    %d\n",italie.nom,italie.capitale,italie.indicatif); /*pour seulement 3 pays on ne surcharge pas avec un tableau*/
      fprintf(registre,"%s    %s    %d\n",espagne.nom,espagne.capitale,espagne.indicatif);
      fprintf(registre,"%s    %s    %d\n",france.nom,france.capitale,france.indicatif);
   fclose(registre);
}


C'est donc la base de donnée de départ (j'étais pas censé la créer directement avec le programme mais l'écrire en toute lettre moi même; mais je trouve tout de même plus utile de l'avoir fait comme ça.


Je me confronte maintenant au problème suivant.

Vérifier si un pays est dans la base de donnée.

La première solution serait de rentrer mes élément de structure du fichier dans un tableau; mais je me l'interdit car ce serait à mon avis "contourner" le problème et ce n'est pas le but de l'exercice.



Je veux donc réellement parcourir un fichier et faire des comparaisons à l'intérieur de celui ci.



J'ai produit le code de base suivant.
Code: Tout sélectionner
void verification()
{
   FILE *registre;
   registre=fopen(LISTE,"r"); /*on ouvre le fichier en lecture; on ne veut pas le modifier*/
   char pays[21];
   printf("Entrez un nom de pays (en majuscule) :\n");
   scanf("%s",pays);
   char test='n';
   do /*ce do while parcourt bien le fichier du début à la fin ??? */
   {
      /*le corps de la fonction doit comparer pays avec ce qui est déjà écrit dans le fichier ligne par ligne
et accessoirement mot par mot*/

   } while(!feof(registre));
   fclose(registre);
}


C'est donc pour écrire ce corps de fonction que je ne sais pas trop procéder; comment lire et stocker dans une variable une chaîne de caractère d'un fichier lu ?
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
fatal_error
Membre Légendaire
Messages: 6610
Enregistré le: 22 Nov 2007, 12:00

par fatal_error » 08 Déc 2013, 15:16

tu pourrais utiliser fscanf un peu comme fprintf pour écrire..

La première solution serait de rentrer mes élément de structure du fichier dans un tableau; mais je me l'interdit car ce serait à mon avis "contourner" le problème et ce n'est pas le but de l'exercice.

(c'est ce qu'on fait généralement, on lit tout le fichier en mémoire, puis on travaille sur la mémoire après).
la vie est une fête :)

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

par joel76 » 08 Déc 2013, 19:15

Personnellement, je ne suis pas favorable à l'utilisation de fscanf, car on ne sait pas exactement pourquoi le fscanf échoue : http://www.linux-france.org/article/man-fr/man3/scanf-3.html section "valeur renvoyée".
A mon avis, il vaut mieux utiliser un fgets (avec un buffer assez grand il est vrai, mais on déjà vu comment savoir si la lecture a entièrement réussi) qu'on teste à NULL pour savoir si on est arrivé en fin de fichier. Ensuite on utilise un sscanf dont on teste le retour : il renvoie le nombre de conversions réussies.

pour ce qui concerne ta fonction initRep, voici une méthode qui peut-être utile à connaître :
Code: Tout sélectionner
void initRep(void)
{
   size_t i;
   A T[] =    {{"FRANCE" , "PARIS" , 33},
         {"ITALIE","ROME",39},
         {"ESPAGNE","MADRID",34}};
   FILE *registre;
   registre=fopen(LISTE,"w"); /* "w" on crée ou efface le fichier puis on le remplit*/

   // il faut toujours tester le retour de fopen, on ne sait jamais ce qui peut se passer
   if (registre != NULL)
   {
      // sizeof(T)/sizeof(*T) donne le nombre d'élément du tableau
      for(i = 0; i
}

 

Retourner vers ϟ Informatique

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité

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
[phpBB Debug] PHP Warning: in file Unknown on line 0: Unknown: Failed to write session data (memcached). Please verify that the current setting of session.save_path is correct (172.16.100.103:11211)