# [C] S'éxecute mal avec GCC, mais pas avec MINGW (Résolu)

## Animatrix

Salut à tous !!

J'essaye de créer un identifiant à partir de la première lettre du prénom et du reste du nom (7 caractères max).

Les 7 caractères n'est pas le souci pour l'instant. En fait, une fois la procédure exécutée, il me modifie ma liste chainée nom, alors que je n'y touche pas !

Cela se produit uniquement avec GCC. S'agit-il d'un bug, ou de mon code ?

```
#include <stdio.h>

#include <stdlib.h>

#include <stdbool.h>

#include <string.h>

#include <ctype.h>

 

void identifiant (const char p[], const char n[], char id[]);

 

int

main (void)

{

 

  const int max = 30;

  char nom[max], prenom[max], id[8];

  int lp, ln;

 

  // On saisie le prénom

  printf ("Entrez le prénom (maximum %d caractères): ", max);

  fgets (prenom, max, stdin);

  // Et le nom

  printf ("et le nom : ");

  fgets (nom, max, stdin);

 

  // Après le dernier caractère, on met \0

  lp = strlen (prenom);

  ln = strlen (nom);

  prenom[lp - 1] = '\0';

  nom[ln - 1] = '\0';

 

  // On s'assure qu'il y ai un prénom et un nom

  if (prenom[0] != '\0' && nom[0] != '\0')

    {

 

      printf ("Données :\tPrénom = %s\t--\tNom = %s\n", prenom, nom); // Affichage du résultat

 

      identifiant (prenom, nom, id);

      printf ("Identifiant :\t%s\n", id);       // Affichage du résultat

      printf ("Test de nom :%s\n",nom);

 

    }

    else printf("Merci d'écrire un prénom et un nom.");

 

  return EXIT_SUCCESS;

}

 

void

identifiant(const char p[], const char n[], char id[])

{

  int i, j;

        id[0] = p[0];

        i=1;j=0;

        while (i < 8)

        {

        id[i] = n[j];

        i++;j++;

        }

        id[i] = '\0';

}
```

Je n'ai aucune erreur, mais regardez le résultat :

```
Entrez le prénom : Jean-François XYZ

et le nom : Jeannette Andrée 

Données :        Prénom = Jean-François XYZ        --        Nom = Jeanne Andrée

Identifiant :        JJeannet

Test de nom : (*des caractères spéciaux ici, je ne peux pas les copier, bug avec le forum*)
```

Il renvoi un nom différent, alors qu'il devrait m'afficher la même chose que dans Données.

Comment cela se fait-il, sachant qu'avec Mingw je n'ai pas ce soucis ?

MerciLast edited by Animatrix on Sat Feb 09, 2008 8:43 pm; edited 1 time in total

----------

## GentooUser@Clubic

Ça marche chez moi (gcc 4.2.2)

```

% ./a.out

Entrez le prénom (maximum 30 caractères): Jean-François XYZ

et le nom : Jeannette Andrée

Données :       Prénom = Jean-François XYZ      --      Nom = Jeannette Andrée

Identifiant :   JJeannet

Test de nom :

[kraft:pts/1] [maxime] [/home/maxime]

% ./a.out

Entrez le prénom (maximum 30 caractères): Marie

et le nom : De Magdala

Données :       Prénom = Marie  --      Nom = De Magdala

Identifiant :   MDe Magd

Test de nom :

[kraft:pts/1] [maxime] [/home/maxime]

```

----------

## sno35

Ouch, en gcc 4.2.2 sur ppc, ça passe tranquille, malgré les maladresses de C.  :Wink: 

Notamment, strlen calcule la longueur justement en cherchant le premier '\0', donc pas besoin de le rajouter à cet endroit là (man fgets).

Mais si vraiment ton gcc produit un résultat comme tu le relates avec le code que tu nous montres, tu es bon pour le chopper en binaire, à moins de disposer d'une version qui montre de meilleures dispositions.

Eqça.

Edit: et le 

```
id[i] = '\0';
```

 à la fin est un dépassement (bénin, mais bon, quand les bornes sont dépassées ...)

car i == 8 à ce moment là.Last edited by sno35 on Tue Feb 05, 2008 10:23 pm; edited 1 time in total

----------

## Animatrix

Je vais voir ca pour le strlen.

Je viens de tester avec gcc-3.3.6 et magique ca marche !

Ne s'agirait-il pas d'un de mes USE ?

```
(fortran gcj gtk mudflap nls openmp -altivec -bootstrap -build -doc -hardened -ip28 -ip32r10k -multilib -multislot -n32 -n64 -nocxx -objc -objc++ -objc-gc -test -vanilla)
```

Edit : Question en C (je suis nouveau  :Smile:  )

```
void

fonction (const char p[], const char n[], char mail[])

{

  int i;

   char pbis[30], nbis[30];

  /* Optionnel : écriture du prénom sous la forme Prénom 

  (via une chaîne locale, car on ne peut pas écrire sur p) */

  sprintf(pbis, presentation(p));

  /* Optionnel : écriture du nom sous la forme Nom

  (via une chaîne locale, car on ne peut pas écrire sur n) */

  sprintf(nbis, presentation(n));

[...]

}

void

presentation (char t[])

{

  int i;

  t[0] = toupper (t[0]);

  for (i = 1; t[i]; i++)

    t[i] = tolower (t[i]);

}
```

J'aimerias copier p dans pbis et n dans nbis, mais j'ai cette erreur :

 *Quote:*   

> attention : passing argument 1 of ‘presentation’ discards qualifiers from pointer target type
> 
> erreur: utilisation invalide d'expression void
> 
> attention : passing argument 1 of ‘presentation’ discards qualifiers from pointer target type
> ...

 

----------

## xaviermiller

salut,

les USE et CFLAGS ne sont utilisés que par Portage  :Wink: 

----------

## Animatrix

 *XavierMiller wrote:*   

> salut,
> 
> les USE et CFLAGS ne sont utilisés que par Portage 

 Je le sais, mais est-ce que je n'aurais pas emergé GCC avec un mauvais USE ou j'en aurais oublié un, c'est ce que je voulais dire  :Smile: 

----------

## sno35

Euh, on va dire que c'est une histoire de goût de ma part, mais quand il y a des pointeurs en jeux, ça ne sert qu'à aller dans le mur de se les masquer. Les paramètres formels tu devrais les passer sous forme 'pointeur' :

```
const char *p
```

au lieu de

```
const char[]
```

sinon, strdup est plus économique que sprint pour ce que tu veux faire.

Et tu annonces que presentation renvoie void et tu essaies de passer ça à sprint. Le compilo te dit à juste titre que ce n'est pas ce type qu'il attendait comme 2ème argument à sprintf.

Déjà le premier avril ?? /o\

Edit : ceci doit ressembler à ce que tu voulais, non ? :

```
#include <stdio.h>

#include <stdlib.h>

#include <stdbool.h>

#include <string.h>

#include <ctype.h>

 

void identifiant (const char p[], const char n[], char id[]);

 

int main (void)

{

   const int max = 30;

   char nom[max], prenom[max], id[9];

   int lp, ln;

   // On saisie le prénom

   printf ("Entrez le prénom (maximum %d caractères): ", max);

   fgets (prenom, max, stdin);

   // Et le nom

   printf ("et le nom : ");

   fgets (nom, max, stdin);

   // On s'assure qu'il y ai un prénom et un nom

   if (prenom[0] != '\0' && nom[0] != '\0')

   {

      printf("n:%p, %p, %p,%p\n", nom, &nom, id, &id);

      printf ("Données :\tPrénom = %s\t--\tNom = %s\n", prenom, nom); // Affichage du résultat

      identifiant (prenom, nom, id);

      printf ("Identifiant :\t%s\n", id);       // Affichage du résultat

      printf ("Test de nom :%s\n",nom);

   }

   else printf("Merci d'écrire un prénom et un nom.");

   return EXIT_SUCCESS;

}

 

void

identifiant(const char p[], const char n[], char id[])

{

   int i;

   id[0] = toupper(p[0]);

   i = 1;

   while (i < 8)

   {

      /* la lisibilité est meilleure en gardant i-1 plutôt que

       * de manipuler une variable en parallèle. Et pas moins efficace.

       * Et quand bien même laisse faire le compilo. Si jamais il se trompe,

       * tu y reviendra et le règlera plus tard ;-) */

      id[i] = tolower(n[i-1]);

      i++;

   }

   id[i] = '\0';

}

```

----------

## Magic Banana

Lorsque tu as des problèmes de portabilité il est bon de rendre gcc plus exigeant et de regarder de près chaque avertissement :

```
$ gcc -Wall -Wextra -ansi -pedantic main.c
```

----------

## Temet

Mouais, rien que revoir des chaines de caractères surdimensionnées, je me dis que le C c'est pas la panaC.

... si vous me cherchez :  :Arrow: 

----------

## Animatrix

Merci beaucoup.

Pour l'utilisation des deux variables, je suis obligé.

Par ex : si il y a un tiret dans une chaine, je dois avancer sur l'une et non sur l'autre.

Même avec la commande donné, rien d'anormal (certes il gueule pour tout), il me dit même que c'est de type void.

----------

## xaviermiller

 *Animatrix wrote:*   

> rien d'anormal (certes il gueule pour tout)

 

 :Shocked: 

----------

## Magic Banana

 *XavierMiller wrote:*   

>  *Animatrix wrote:*   rien d'anormal (certes il gueule pour tout) 
> 
> 

 

 :Shocked:   :Shocked: 

Tu peux peut-être nous donner tous ces avertissements (j'ai pas trop envie de jouer au compilateur aujourd'hui  :Laughing:  ).

----------

## Animatrix

 *Magic Banana wrote:*   

>  *XavierMiller wrote:*    *Animatrix wrote:*   rien d'anormal (certes il gueule pour tout) 
> 
>  
> 
>  
> ...

 QUand je dis ca, par exemple c'est pour un commentaire (//) si je met : il me met un msg d'erreur, alors que ce n'en ai pas un et vu que j'ai bcp de comms...

----------

## GentooUser@Clubic

Le C n'accepte que la forme /* ... */ pour les commentaires !

A moins que ça ai changé.

----------

## YetiBarBar

 *GentooUser@Clubic wrote:*   

> Le C n'accepte que la forme /* ... */ pour les commentaires !
> 
> A moins que ça ai changé.

 

Ca a changé !

Plus exactement, le C99 tel que préconisé par l'ISO accepte // (en autres trucs ...)

mais pour celà, il faut dire à GCC que tu fais du C dans cette norme (-std=c99 en paramètre ou quelquechose du genre, pas envie de me faire mon petit man gcc non plus ...)

EDIT : en fait, GCC accepte les commentaires en // depuis un bail, sauf si tu forces le C ANSI (avec un -ansi)

----------

## Animatrix

Voila ce que sa donne sans ainsi.

```
courriel.c:21:32: attention : Les commentaires à la C++ ne sont pas permis en C89 ISO

courriel.c:21:32: attention : (ceci sera rapporté une seule fois seulement par fichier d'entrée)

courriel.c: In function ‘main’:

courriel.c:29: attention : ISO C90 forbids variable-size array ‘nom’

courriel.c:29: attention : ISO C90 forbids variable-size array ‘prenom’

courriel.c:29: attention : ISO C90 forbids variable-size array ‘mail’
```

Donc rien d'annormal :'([/quote]

----------

## xaviermiller

Essaie de remplacer ta constante par un #define : rien ne dit que toutes les implémentations supportent C99. 

Et change les commentaires : tu fais du C, pas du C++

Ou alors, force la compilation en C99 !

A moins que tu ne refuses de faire du code portable  :Wink: 

----------

## Animatrix

Alors, j'ai remplacé tous les commentaires et même utilisé un -std=c99 et aucune erreur de la part de gcc.

```
gcc -Wall -Wextra -ansi -pedantic -std=c99 main.c -o main
```

Le problème persiste, alors qu'avec les versions précédentes de ce même compilateur ca marche  :Sad: Last edited by Animatrix on Fri Feb 08, 2008 8:46 am; edited 1 time in total

----------

## xaviermiller

et à l'exécution ?

J'ai pas trop le temps de regarder ça maintenant (à la bourre au boulot et à la maison), mais peut-être dimanche  :Wink: 

----------

## YetiBarBar

 *Animatrix wrote:*   

> Alors, j'ai remplacé tous les commentaires et même utilisé un -std=c99 et aucune erreur de la part de gcc.
> 
> ```
> gcc -Wall -Wextra -ansi -pedantic -std=c99 main.c -o main
> ```
> ...

 

Tu passes 2 paramètres auto-exclusifs à gcc :

-ansi (strictement identique à -std=c89 ou -std=c90, à voir avec man gcc)

-std=c99

Je ne sais pas trop comment gcc fait sa sauce en interne, mais je pense qu'une fois défini ...

En relisant le man, j'ai vérifie que le mode C "par défaut" de gcc est gnu90 (enfin un numéro du genre) : du C ansi avec des extensions extraites du C99

PS : +1 avec XavierMiller pour les commentaires, le // est vraiment rarement indispensable

EDIT : pour ton problème, en C ANSI, tu es bien obligé de définir des constantes avec un #define si tu veux déclarer des tableaux de cet taille (comme ça a été dit), le compilateur considérant qu'utiliser un int (même constant) ne lui fournit pas la taille des données à allouer. C'est très con (et il me semble que le C99 ne le tolère pas non plus, mais je t'avoue avoir travaillé vraiment trop peu avec ...)

----------

## Animatrix

Je me suis trompé en copiant, je n'ai bien sûr pas fait de -ansi et de -std=c99 à la fois.

Pour les define, on m'a vraiment déconseillé de les utiliser car c'était une méthode "bourrin".

Mais l'étrang"ité" de la chose est que d'autres versions de gcc sur une même machine marchent.

Je ne devrais pas faire un rapport de bug ?

----------

## guilc

 *Animatrix wrote:*   

> Mais l'étrang"ité" de la chose est que d'autres versions de gcc sur une même machine marchent.
> 
> Je ne devrais pas faire un rapport de bug ?

 

Heu, c'est pas pour être méchant, mais avant de faire un rapport de bug, il faudrait peut-être à faire du C non ?

Surtout pour des bugs de "base" comme ça, y a carrément peu de chance que le problème vienne de GCC... La ton code est bourré de débordements de buffers potentiels ou effectifs, donc à partir de la, le comportement sera hératique suivant les compilos et les version de compilos, au grès des différents écrasements de pile et compagnie...

Voici un exemple de code qui marche sans bug et sans débordements de buffers, et quelques allocations dynamiques (les tableaux statique sont à TOTALEMENT proscrire : de telles allocations se font sur la pile, qui est de taille TRES limitée, contrairement aux allocations dynamiques qui se font en RAM).

Attention, j'ai fait l'impasse sur les tests qui pourraient vérifier que les allocations se sont faites correctement par exemple (il faut les faire pour éviter les bugs potentiels lors d'échecs d'allocations)

```
#include <stdio.h>

#include <stdlib.h>

#include <stdbool.h>

#include <string.h>

#include <ctype.h>

#define MAX_STRING 1024

void identifiant (char *p, char *n, char **id);

int main (void)

{

    char *nom = NULL, *prenom = NULL, *id = NULL;

    int lp, ln;

    // On saisie le prénom

    prenom = (char *)malloc ((MAX_STRING + 1) * sizeof (char));

    printf ("Entrez le prénom (maximum %d caractères): ", MAX_STRING);

    fgets (prenom, MAX_STRING, stdin);

    prenom = (char *)realloc (prenom, (strlen (prenom) + 1) * sizeof (char));

    // Et le nom

    nom = (char *)malloc ((MAX_STRING + 1) * sizeof (char));

    printf ("et le nom : ");

    fgets (nom, MAX_STRING, stdin);

    nom = (char *)realloc (nom, (strlen (nom) + 1) * sizeof (char));

    // On s'assure qu'il y ai un prénom et un nom

    if (*prenom != '\0' && *nom != '\0')

    {

        printf ("Données :\tPrénom = %s\t--\tNom = %s\n", prenom, nom); // Affichage du résultat

        identifiant (prenom, nom, &id);

        printf ("Identifiant :\t%s\n", id);       // Affichage du résultat

        printf ("Test de nom :%s\n", nom);

    }

    else

    {

        printf("Merci d'écrire un prénom et un nom.");

    }

    if (nom)

        free (nom);

    nom = NULL;

    if (prenom)

        free (prenom);

    prenom = NULL;

    if (id)

        free (id);

    id = NULL;

    return EXIT_SUCCESS;

}

void identifiant (char *p, char *n, char **id)

{

    int i, j;

    int max = strlen (n);

    *id = (char *)malloc (9 * sizeof (char));

    (*id)[0] = p[0];

    i = 1;

    j = 0;

    while (i < 8 && j < max)

    {

        (*id)[i++] = n[j++];

    }

    (*id)[i] = '\0';

    *id = (char *)realloc (*id, (strlen (*id) + 1) * sizeof (char));

}

```

----------

## Animatrix

En effet plus de problème  :Smile: 

Le tout est que j'apprends le C actuellement, et que les sizeof, malloc, je n'ai pas encore vu.

Définir des char tableau[] sont imposés par le sujet, je ne peux pas faire autrement (quoi que maintenant je sais  :Smile: )

----------

## xaviermiller

 *Animatrix wrote:*   

> Pour les define, on m'a vraiment déconseillé de les utiliser car c'était une méthode "bourrin".

 

Qui t'a dit ça ? un chipoteur C++ ?

 même les gourous C++ disent que les #define ont du sens.

----------

## Animatrix

 *XavierMiller wrote:*   

>  *Animatrix wrote:*   Pour les define, on m'a vraiment déconseillé de les utiliser car c'était une méthode "bourrin". 
> 
> Qui t'a dit ça ? un chipoteur C++ ?
> 
>  même les gourous C++ disent que les #define ont du sens.

 

Tout au moins, apprenant le C depuis très peu de temps, je pense que le prof préfère utiliser l'autre méthode, pour ensuite venir au define  :Smile: 

En tout cas, merci pour votre aide.

----------

## YetiBarBar

Sans rentrer dans des détails trop fastidieux, je vois au moins 2 raisons à utviliser #define au lieu de const int :

- définir un const int va te bouffer quelques octets de plus sur la taille de ton programme (à vrai dire,e sur un PC, on s'en fout un peu mais le C ne sert pas que sous nos machines ...)

- ça va surement te paraitre choquant mais : const int p ne défini pas une valeur constante (contrairement au #define pour lequyel le remplacement est fait par le pré-processeur!!!), un moyen de t'en convaincre :

```
int main(int argc, char **argc)

{

const int a = 10;

int b = &a;

*b=20;

printf("%d\n",a);

return 0;

}
```

----------

## guilc

Tiens au fait.

Une petite lecture instructive sur le pourquoi c'est mal de mettre des tableaux sur la pile, et pourquoi c'est dangereux de déborder de ces tableaux, ayant pour conséquence d'altérer le contenu de la pile là ou il ne faut surtout pas toucher :

http://fr.wikipedia.org/wiki/Dépassement_de_tampon

Et niveau de la taille de la pile, ça va dépendre des architectures ainsi que des systèmes d'exploitation et des version de libc

Ainsi, sur du OpenBSD, ça sera du 64Ko, sur du Solaris8 => 2Mo, sous linux avec une glibc 2.2Pthreads => 2Mo, avec une glibc 2.6NPTL => 8Mo, sur de l'embarqué, ça tourne souvent autour de 4k (par exemple sur du motorolla 68000)

----------

## matlerouge

 *YetiBarBar wrote:*   

> 
> 
> ```
> int main(int argc, char **argc)
> 
> ...

 

Ca a pas l'aire trop légal comme code, il y a une erreur (pas de conversion int* vers const int*). Si on force le cast :

```
int *b = (int*)&a;
```

La ca compile par contre erreur à l'édition de lien (il doit pas trouver de référence à 'a', sûrement par ce que le compilo remplace directement le 'a' par 10 dans le code.)

[/code]

----------

## YetiBarBar

Autant pour moi : la première ligne n'est pas :

```
int main(int argc, char **argc)
```

mais 

```
int main(int argc, char **argv)
```

Sinon je peux t'assurer que ce code compile parfaitement chez moi (modulo un warning vu que gcc se rend quand même compte qu'il y a quelque chose de potentiellement louche), j'utilise gcc-4.2.2 et la glibc-2.7-r1 mais c'est un bout de code que j'ai déjà croisé à maintes reprises pour illustrer le phénomène.

Après, j'accorde que l'exemple est hyper tiré par les cheveux (le but étant juste d'illustrer que le mot clé const, en C, signifie "je n'utiliserai jamais l'identifiant de la variable que je déclare pour la modifier). C'est ce qui fait la force du C : on peut faire (pesque) tout et surtout n'iporte quoi. (faut vraiment être tordu pour chercher à modifier un truc qu'on a défini constant ...)

----------

## matlerouge

J'avais corrigé le code mais compilé dans un .cpp ! Donc en c++ ça passe pas dans gcc.

Et effectivement dans un .c, seulement un warning et ça passe !

Mais attention, en compilant en -00 ca affiche le "20", mais si tu compile en -03 la ça ca prend pas en compte l'affectation par le pointeur et ça affiche le 10.

----------

## YetiBarBar

Rien qu'en -O1, ça marche plus !!

Et là, on commence à toucher au problème des comportements inattendus chez les ricers ... et au pourquoi certains ebuilds filtrent les CFLAGS ! Mais on s'éloigne vraiment du sujet (... le pauvre, on lui a pourri son topic)

----------

## Animatrix

 *YetiBarBar wrote:*   

> Rien qu'en -O1, ça marche plus !!
> 
> Et là, on commence à toucher au problème des comportements inattendus chez les ricers ... et au pourquoi certains ebuilds filtrent les CFLAGS ! Mais on s'éloigne vraiment du sujet (... le pauvre, on lui a pourri son topic)

 Mais non, comme ca j'apprend les subtilités de la programmation  :Smile: 

----------

## Animatrix

Salut à tous !!

C'est à nouveau pour un problème en C.

En fait, j'aimerais utiliser un tableau de mots (strings), sauf qu'en C il n'existe que des tableaux de caractères (de manière native).

J'ai entendu qu'un char *tableau[] pouvait réaliser ce que je voulais.

Sauf que si je fais un :

```
*tableau = "hello";
```

dans tableau[0] ira le mot hello.

Mais comment faire pour mettre dans tableau[1] ?

Sinon, est-ce qu'un tableau multi-dimensionnel peut-être envisageable ?

Merci à tous !

----------

## kwenspc

 *Animatrix wrote:*   

> 
> 
> Sinon, est-ce qu'un tableau multi-dimensionnel peut-être envisageable ?
> 
> 

 

Eh eh oui c'est possible, heureusement. 

Par exemple ton char *tableau est mono-dimension, et tableau[0] ne contient pas "hello" mais 'h', et tableau [1] 'e' et ainsi de suite. (pour être précis: tableau[0] est l'adresse où se situe la donnée 'h')

Tout dépend du besoin, mais ici il te faut un tableau 2 dimensions.

Mais faut vraiment que tu lises ou bouquin ou un bon tuto parce que les "j'ai entendu dire que" non ^^

Par exemple, ton char *tableau[] c'est pareil qu'un char **tableau, avec tout ce que ça suppose: ce sont que des pointeurs, si non initialisés au départ ça veut aussi dire: gérer dynamiquement l'allocation mémoire etc... Si tu comprends pas bien les principes de pointeurs et autres tu vas direct aller dans les segfault, et t'auras une grosse impression de frustration parce que tu ne progresseras pas. En C y a pas de secret: si tu comprends les pointeurs, tu comprends tout. (ou presque)

Il te faut maîtriser les mots clés "*" et "&" et leur contexte d'utilisation, ainsi que les fonctions de bases malloc, calloc, realloc, free. (leurs man pages sont pas trop mal)

Comme livre j'ai ça sinon:

"Le langage C" de Delannoy (éditions Eyrolles, collection Best-of) par exemple (~20 euros), ça parait indigeste comme bouquin mais en fait c'est concis et complet. 

"Programmation Système en C sous Linux" de C. Blaess aussi, une référence. même éditeur mais plus cher.

Après il y a peut-être de bons tutos sur (j'ai pas trop regardé): http://c.developpez.com/cours/

Pour la manipulation des pointeurs ce que je donne à mes étudiants pour que ça rentre c'est: refaites une mini-libc (memset, strstr, etc...). Ils en ont bavés mais à la fin ils ne me faisaient plus les erreurs basiques que tout débutant fait (de toute façon).

Et pour bien renforcer tout ça je leur filais ça à faire: http://www-128.ibm.com/developerworks/linux/library/wa-memmng/

Gardes bien ça en tête: la maîtrise des pointeurs, et donc de la mémoire, te feras passer dans un monde différent  :Smile: 

Je ne réponds pas à ta question première, désolé, mais une bonne connaissance du principe des pointeurs et de la mémoire y répondra.

----------

## Desintegr

Peut-être ça : 

```
#include <stdio.h>

int main() {

      char* tableau[3];

      int i;

      tableau[0] = "hello1";

      tableau[1] = "hello2";

      tableau[2] = "hello3";

      for(i=0; i<3; i++)

         printf("%s\n", tableau[i]);

      return 0;

}
```

----------

## Animatrix

Merci Desintegr, c'est ce que je cherchais.

Par contre, j'aimerais utiliser strcat, stcpy...., c'est-à-dire les outils de string.h.

Seulement je tombe à chaque fois sur un joli segfault.

```
strcpy(tableau[0], "Salut !\0");
```

kwenspc : j'ai déjà le livre pour C++ des éditions Eyrolles.

Mais je vais regarder sur les cours en ligne.

----------

## kwenspc

 *Animatrix wrote:*   

> 
> 
> Seulement je tombe à chaque fois sur un joli segfault.
> 
> 

 

cqfd  :Wink: 

Étudies bien les pointeurs et la gestion de la mémoire, et après tu comprendras pourquoi tu as ce genre d'erreur.

----------

## YetiBarBar

 *Animatrix wrote:*   

> Merci Desintegr, c'est ce que je cherchais.
> 
> Par contre, j'aimerais utiliser strcat, stcpy...., c'est-à-dire les outils de string.h.
> 
> Seulement je tombe à chaque fois sur un joli segfault.
> ...

 

Evidemment !

Pour le coup je plussoie kwenspc, surtout que tu as déjà expérimenté le "piège" : 

Quand tu fais :

```
tableau[0]="hello0";
```

, tu associe à tableau[0] l'adresse mémoire de la chaine statique "hello0"

Pour faire ce que tu veux faire, il faudrait (étudies les pointeurs correctement avant d'expérimentr, sinon tu vas galerer) :

```
tableau[0] = (char *) malloc(sizeof(char) * TAILLEMAXDEMACHAINE);

strcpy(tableau[0], "Salut !\0");

/* A ne pas oublier quand tu n'as plus besoin de la chaine de caractère */

free(tableau[0]);
```

Pour en remettre une couche, si tu ne prends pas le temps de bien comprendre tout ce qui se passe dans ce petit bout de code, tu vas au devant de grosses galère et de "pourquoi ça marche pas?" à répétitions

----------

## Animatrix

Un strcpy doit être de la forme : 

```
char *strcpy (char *dest, const char *src);
```

Donc char *dest, avec tab[0], c'est bon.

Cela viendrait donc de la source ?

Sinon, je dois faire un TP où le but est de récupérer les mots sur une page.

A l'heure actuelle, j'arrive à récupérer tous les mots, en éliminant les espaces, chiffres, caractères spéciaux....

Mais le problème est que le résultat obtenu est simplement une liste de tous les mots qu'il a trouvé.

Or, il se peut qu'il y ai des doublons, est-ce que l'idée du tableau de mots (strings) est une bonne idée, pour corriger ce soucis ?

----------

## guilc

 *Animatrix wrote:*   

> Un strcpy doit être de la forme : 
> 
> ```
> char *strcpy (char *dest, const char *src);
> ```
> ...

 

Non, le segfault ne vient pas de la source.

Le segfault vient du fait que tu copies la chaîne à une adresse où la mémoire n'est pas allouée, ce qui est interdit.

avant de faire ton strcpy, il FAUT allouer l'espace mémoire, comme te l'a montré YetiBarBar. (Et ne pas oublier de libérer la mémoire une fois que tu n'utilises plus la chaine)

il faut VRAIMENT que tu te documentes sur les pointeurs et les allocations mémoire en C, sinon c'est clair que tu vas être complètement largué  :Wink: 

Le C est un langage dit de "bas niveau" : entre autre, il ne fait aucune allocation mémoire pour toi, tu dois tout faire de manière explicite. A l'opposé d'un langage de haut niveau qui va allouer la mémoire dont il a besoin de manière transparente, et la libérer automatiquement quand elle n'est plus nécessaire, souvent via un garbage collector (C++ dans une certaine mesure, avec les fonctions de la STL par exemple), ou des langages comme Java, C# ou les langages de script...

En contre-partie, les aspects bas niveau du C lui permettent d'accéder plus profondément au système, en laissant au programmeur la libre utilisation de l'adressage mémoire et des appels système...

----------

## matlerouge

 *Animatrix wrote:*   

> 
> 
> Mais le problème est que le résultat obtenu est simplement une liste de tous les mots qu'il a trouvé.
> 
> Or, il se peut qu'il y ai des doublons, est-ce que l'idée du tableau de mots (strings) est une bonne idée, pour corriger ce soucis ?

 

Oui c'est bien comme ca, par contre à chaque fois pour voir si le mot existe c'est en O(n) (n taille du tableau)

Moi je prendrait une liste, et je ferait en sorte qu'elle soit toujours triée. Comme ca si tu as un nouveau mot, tu fait une recherche dans ta liste (donc comme c'est trié c'est du log(n) la recherche), et si le mot n'existe pas tu l'insert à la bonne place dans la liste. Chose que tu peux pas faire avec un tableau à part en bricollant avec des realloc... Tu pourras comme ca voir comment on fait une liste chainée en C c'est pas mal je pense après avoir bien compris les pointeurs   :Smile: 

Apres y'a la table de hash aussi mais bon..

----------

## Animatrix

J'ai donc résolu le problème avec un tableau bi-dimensionnel.

J'ai une autre question qui peut paraître bête mais sur laquelle je plante (encore une fois, certes) :

```
if (tableau[k][0] == motCour().tab[1] && tableau[k][1] == motCour().tab[2] && tableau[k][2] == motCour().tab[3] && ...... && tableau[k][50] == motCour().tab[51])
```

Savez-vous comment coder ca ?

Merci

----------

## YetiBarBar

Si motCour().tab est un tableau, je verrai bien quelquechose du genre :

```
#include <string.h>

if(strncmp(tableau[k], motCour().tab + 1, 50) == 0){instruction};
```

Pour savoir ce que fais strncmp, cf man 3 strncmp

(J'ai balancé un peu vite les pointeurs vers les chaînes, je te laisse un peu patauger plus ou moins volontairement : il est tard (pour moi) et tu as encore besoin de bosser les relations entre tableaux, pointeurs et notations)

----------

