Forum Programmation.c Tableau dynamique de pointeur vers char

Posté par  .
Étiquettes : aucune
0
7
avr.
2006
Voila mon probleme j'ai un tableau de ce type :

char *message[1];

et je voudrai que ça taille augmente dynamiquement au fûr et à mesure que je trouve des nouveau mot dans le fichier texte que je parcours. Pour stocker un nouveau pointeur vers une chaine.

j'ai essayé ça mais il prend pas :

message = realloc(message, (count + 1) * sizeof(char *));

Il doit y avoir quelque chose que j'ai pas compris je vous met aussi le code en entier, plz soyez cool niveau critique c'est mon 1er prog en C.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>


int main(void)
{

/* Ouverture du fichier de configuration pour y récupérer la liste de processus */
FILE *fp;

if ((fp = fopen("proc_liste.conf", "r")) == NULL)
{
fprintf(stderr, "\nErreur à l'ouverture du fichier");
exit(1);
}


/* Lecture du contenu du fichier caractère par caractère et stockage en mémoire du fichier */
char now[2] = "a";
char prec = '\0';
char *message[1];
int count = -1;

while ((now[0] = fgetc(fp)) != EOF)
{

/* Vérifie si c'est un nouveau mot pour stocker, sinon complete le mot avec la nouvelle lettre */
if (isalnum(now[0]) != 0 && isalnum(prec) == 0)
{
count++;
if (count > 0)
message = realloc(message, (count + 1) * sizeof(char *));
message[count] = malloc(sizeof(char) * 2);
strcat (message[count], now);
}
else if (isalnum(now[0]) != 0 && isalnum(prec) != 0)
{
message[count] = realloc(message[count], (strlen(message[count]) + strlen(now) + 1));
strcat (message[count], now);
}
prec = now[0];

}

/* affichage du fichier maintenant contenu en mémoire */
int e;
for (e = 1; e <= count; e++)
puts(message[e]);

/* liberer la mémoire utilisée */
int i;
for (i = 0; i <= count; i++)
free(message[i]);

return(0);
}

  • # c'est plus amont

    Posté par  . Évalué à 1.

    cette ligne
    char *message[1];
    doit etre remplacer par
    char *message=NULL;
    et le code ce compileras et fonctionneras.
    Je pense que ce que tu voulais initialiser etait un pointeur vers un tableau de 1 caractere mais la ligne rentrer créait en fait un tableau de 1 pointeur sur un char.
    • [^] # Re: c'est plus amont

      Posté par  . Évalué à 0.

      je voulais bien créé un tableau de 1 pointeur sur un char, pour stocker un mot dedans (trouvé dans le fichier).

      mais quand il découvre un deuxième mot il faut que le tableau permette d'accueillir un nouveau pointeur vers la chaine qui contiendra le mot...

      Le programme fonctionne impect si je met char *message[2000];
      alors il pourrra stocker 2000 mot que je trouve dans le fichier mais je veux que il soit adapté si il n'y a que 1 mot ou s'il en trouve 5000...

      C'est pour ça que j'ai besoin que le tableau s'agrandisse pour met un pointeur char de plus dedans...
      • [^] # Re: c'est plus amont

        Posté par  . Évalué à 2.

        il ne faut pas figer la taille lors de la déclaration.
        il faut faire :

        char **message;
        message = (char **)calloc(2000, sizeof(char *));

        et ensuite le realloc fonctionnera.

        (comment on fait le surlignage du code dans le message ?)
    • [^] # man realloc

      Posté par  . Évalué à 1.

      un extrait du manuel de realloc:

      void * realloc (void * ptr, size_t size);
      [...]
      Si ptr est NULL, l'appel de realloc() est équivalent à malloc(size).
      Si size vaut zéro, l'appel est équivalent à free(ptr). Si ptr n'est
      pas NULL, il doit avoir été obtenu par un appel antérieur à malloc(),
      calloc() ou realloc().




      char *message[1]; n'est pas issu d'une fonction d'allocation au départ, realloc ne peut pas marcher avec.
  • # Les tableaux c'est pas beau...

    Posté par  . Évalué à -1.

    Bonjour.

    Ton code suggere implicitement ta connaissance des problèmes d'allocation mémoire et de destruction, et c'est pour cela que je te conseille TRES vivement d'utiliser des listes chainées, ou au pire des Vectors (Ca existe en C ca?).
    Ci je te dis cela c'est pour deux raisons:
    La premiere c'est que niveau sécurité et stabilité de ton programme, ton utilisation d'un tableau indique une taille prédéfinie en mémoire. Un buffer-Overflow est à craindre. Enfin, même si tu réalloue de la mémoire, es-tu sur de ne pas copier tes informations dont certains vont rester inutilisé apres dans ta pile? Au vu et au su de tous...

    La seconde est la perte enorme de temps CPU que tu passe a recreer tes objects proprement, à les détruire etc...

    Prends l'habitude dés maintenant d'utiliser des liste chainés, tu me remerciera dans ton fort interieur plus tard.
    Tu trouveras plein de tuto sur le net et même des librairies, certaines avec des itérateurs intégrés! Alors pourquoi s'embeter avec des tableaux static que tu veux rendre par un astuce horrible dynamique?

    Allez, bon courage en tout cas, quelque soit ton choix.

    Thomas
    • [^] # Re: Les tableaux c'est pas beau...

      Posté par  . Évalué à 0.

      je crois que j'ai plus ou moins compris ce que tu voulais dire thomas.

      Je connais pas la technique buffer-Overflow mais je vais me renseigner la dessus le code fonctionne mais maintenant il me renvoie segmentation fault quand il y a plus de 19 mots dans la liste j'y comprends rien...



      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <ctype.h>


      int main(void)
      {

      /* Ouverture du fichier de configuration pour y récupérer la liste de processus */
      FILE *fp;

      if ((fp = fopen("proc_liste.conf", "r")) == NULL)
      {
      fprintf(stderr, "\nErreur à l'ouverture du fichier");
      exit(1);
      }


      /* Lecture du contenu du fichier caractère par caractère et stockage en mémoire du fichier */
      char now[2] = "a";
      char prec = '\0';
      char **message;
      long count = -1;

      message = (char **)calloc(1, sizeof(char *));

      while ((now[0] = fgetc(fp)) != EOF)
      {

      /* Vérifie si c'est un nouveau mot pour stocker, sinon complete le mot avec la nouvelle lettre */
      if (isalnum(now[0]) != 0 && isalnum(prec) == 0)
      {
      count++;
      if (count > 0)
      message = (char **)realloc(message, (count + 1) * sizeof(char *));

      message[count] = malloc(sizeof(char) * 2);
      strcat (message[count], now);
      }
      else if (isalnum(now[0]) != 0 && isalnum(prec) != 0)
      {
      message[count] = realloc(message[count], (strlen(message[count]) + strlen(now) + 1));
      strcat (message[count], now);
      }
      prec = now[0];

      }

      /* affichage du fichier maintenant contenu en mémoire */
      long e;
      for (e = 1; e <= count; e++)
      puts(message[e]);

      /* liberer la mémoire utilisée */
      long i;
      for (i = 0; i <= count; i++)
      free(message[i]);

      fclose(fp);
      return(0);
      }


      quand il y a que 19 mot dans le fichier ça fonctionne plus le prog me fait des problemes.
    • [^] # Re: Les tableaux c'est pas beau...

      Posté par  . Évalué à 0.

      ok j'ai compris l'interrêt des listes chainée je vais refaire mon code en utilisant les listes chainée. Ce sera mieux. Merci du conseil. Si t'en as d'autres c'est le bienvenue pour un débutant en C comme moi mais qui as déjà utilisé d'autre langages.
    • [^] # Re: Les tableaux c'est pas beau...

      Posté par  (site web personnel) . Évalué à 1.

      Les listes chaînées c'est bien mais pas toujours.

      Quand on a besoin d'allouer quelque chose dont on peut connaître la taille totale (ce qui éviterait de réallouer) alors autant utiliser un tableau. L'acces à une donnée du tableau se fait en complexité O(1)

      Alors que pour une liste chaînée, c'est en O(n).

      Maintenant, c'est sûr que les liste chaînées sont très performantes pour ajouter ou supprimer un élément, quelqu'en soit la position.

      Je conseil donc de toujours bien réfléchir : tableau ou liste ?
  • # Petits problèmes

    Posté par  . Évalué à 1.

    char now[2] = "a";te>
    char *message[1];
    /* ... */
    message[count] = malloc(sizeof(char) * 2);
    strcat (message[count], now);

    Comme il a été dit plus haut, la définition de tes données ne correspond pas au traitement que tu en fais: actuellement tu définis message comme un pointeur sur tableau(x) de un caractère, alors que tu l'utilises comme un pointeur sur tableau(x) de deux caractères (strcat inclut le '\0' final)...

    Par ailleurs, sizeof(char) vaut 1 par définition, tu peux donc simplifier ton code.

    char now[2] = "a";
    /* ... */
    while ((now[0] = fgetc(fp)) != EOF)
    /* ... */
    Ta boucle peut s'arrêter avant la fin du fichier, car fgetc() renvoie autre chose qu'un char: un int qui contient soit un caractère valide sous forme d'unsigned char, soit EOF. Or, tu convertis implicitement cette valeur int en un char, et si la valeur n'est pas représentable directement, alors il y peut y avoir "collision", et un caractère valide sera vu comme EOF (cf. http://c-faq.com/stdio/getcharc.html ).

    message = realloc(message, (count + 1) * sizeof(char *));

    Attention à l'utilisation de realloc(): si la fonction ne peut allouer de mémoire, elle renvoie NULL sans forcément libérer l'ancienne zone mémoire. Dans ton cas, ça reviendrait à mettre message à NULL sans faire le free(), d'où une fuite mémoire.

    De plus, au lieu de faire un realloc() à chaque étape, ce qui peut faire perdre du temps (il peut y avoir des appels système derrière et différents traitements plus ou moins lourds), il peut être préférable de le faire en doublant la taille du vecteur à chaque appel (en gardant un paramètre size qui contient la taille réelle du vecteur, et si count > size, alors on fait un realloc avec 2*size).

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.