Forum Programmation.c valeur NULL d'un tableau de pointeur

Posté par  .
Étiquettes : aucune
0
18
sept.
2006
Salut

Voila j'ai un bête tableau de chaîne de caractère 'char **tab'
dont chaque ligne contient une chaîne de caractères.
J'utilise une boucle while pour en afficher le contenue :

while(tab[n] != NULL)
{
printf("%s\n", tab[n]);
n++;
}

Mais non, la boucle continue et comme il n'y a rien après la dernière chaîne le programme plante lamentablement.

Comment je fais pour tester que je suis bien a la dernière valeur du tableau ?
  • # Re

    Posté par  . Évalué à 4.

    Autant les chaines de caractères sont "Null terminated", autant rien n'indique dans ton tableau que l'adresse juste après soit nulle (en gros ça marche pas comme les chaines).

    Il faut que tu connaisses la taille de ton tableau pour itérer dedans, ou que tu implémente une liste chainée dont le dernier chainon pointera vers nul...
  • # ?

    Posté par  . Évalué à 4.

    Tu es sûr qu'il existe un n pour lequel tab[n] est NULL ?

    Tu le remplis comment ton tableau ?
  • # beh euh...

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

    Si j'essais de respecter ton style, ca donne un truc du genre :

    int main(int argc, char **argv){
    char tab[5][255];

    int i;
    for (i = 0; i< 5; i++)
    tab[i][0] = NULL;

    strcpy(tab [0],"plop");
    strcpy(tab [1],"poulpe");

    int n = 0;

    while (tab[n][0] != NULL){
    printf("%s\n",tab[n]);
    n++;
    }

    return 0;

    }

    Pas testé, mais bon, ca devrait tourner (à caster si tu veux pas de warning...)
  • # Réponses

    Posté par  . Évalué à 1.

    Merci

    Pour répondre aux deux premières question, je pensais a tord que le dernier elemment du tableau n'ayant pas était initialiser par un malloc et ne contenant rien, serais automatiquement mis a NULL, ce qui n'était pas le cas, voila maintenant j'alloue de la mémoire pour cette elemment et je le mets à NULL , et la boucle fonctionne correctement .

    Pour la troisieme question voila comment je fais:

    (Je poste le code pour avoir des remarques, savoir si c'est une bonne manière de faire, si je peut améliorer, bref si j'ai des critiques constructive c'est cool. Même pas peur :)

    char ** get_fortune(void)
    {
    char **text;
    FILE *file;
    char line[128];
    int n = 0;

    text = malloc(sizeof(char*));

    file = popen("/usr/games/fortune", "r");

    while(fgets(line, 127, file) != NULL)
    {
    char *ptr;
    if(n != 0) {
    text = realloc(text, (sizeof(char*)*(n+1))); }

    ptr = strchr(line, '\n');
    *ptr = '\0';
    text[n] = malloc(sizeof(char*)*strlen(line)+1);
    strcpy(text[n], line);
    n++;
    }
    text = realloc(text, (sizeof(char)*(n+1)));
    text[n] = NULL;
    pclose(file);
    return text;
    }

    Rapide les réponses, merci encore, j'y galère depuis hier.

    Allez tous vous faire spéculer.

    • [^] # Re: Réponses

      Posté par  . Évalué à 1.

      De mon avis , ca fais beaucoup de realloc, un part boucle, est-ce que je peut pas allouer un gros bloc de mémoire d'un coup, et juste verifier
      à chaque tour que j'en ai assez ?

      Allez tous vous faire spéculer.

      • [^] # Re: Réponses

        Posté par  . Évalué à 2.

        Moui, c'est pas mal. Juste pour info, malloc et realloc te renvoie un bout de mémoire NON initialisé. Ha, ha, moi aussi étant jeune padawan, je suis tombé souvent dans le piège plus d'une fois. Sinon en plus efficace, tu lit le fichier d'un coup, tu comptes les lignes et assignes à ton tableau du genre :
        char ** get_fortune(void)
        {
        	char ** text;
        	char *  content;
        	char *  p;
        	FILE *  file;
        	int     n, sz;
        
        	file = popen("/usr/games/fortune", "r");
        
        	if (file == NULL) return NULL;
        
        	// Lit d'un bloc le fichier
        	fseek(file, 0, SEEK_END);	sz = ftell(file);
        	fseek(file, 0, SEEK_SET);
        
        	if (sz == 0) return NULL;
        
        	content = malloc(sz + 1);
        	sz = fread(content, 1, sz, file);
        	content[sz] = 0;
        	fclose(file);
        
        	// Compte les lignes
        	for (p = content, n = 0; *p; p ++)
        		if (*p == '\n') n ++;
        
        	// Construit le tableau
        	text = malloc((n + 1) * sizeof *text);
        
        	for (p = content, n = 0; p; p = strchr(p, '\n'), n ++) {
        		if (p > content) *p++ = 0;
        		text[n] = p;
        	}
        
        	text[n] = NULL;
        
        	return text;
        }
        
        Faudra penser à libérer text[0] et text (la valeur de retour). Disclaimeur : pas testé :-(
        • [^] # Re: Réponses

          Posté par  . Évalué à 2.

          Merci de ta réponse,

          C'est interessant de voir une autre personne faire la même chose que soi, ca donne une autre perspective.

          Je n'ai pas testé ta façon, mais elle mets bien utile pour comprendre d'autres petites choses :), notemment l'allocation d'un seul coup du tableau de pointeur,

          Entre temps ma fonction bugguan 1 fois sur trois j'ai changé de méthode pour passer par des structures chainé, et la ca marche correctement ( cad à chaque fois :)
          Reste plus qu'a voire quel technique est la plus adapté.

          Allez tous vous faire spéculer.

          • [^] # Re: Réponses

            Posté par  . Évalué à 2.

            Oulala, sauf que mon programme est complètement faux X-(

            J'avais pas vu que tu faisais un popen() sur un programme (j'étais persuadé que c'était un fichier). Du coup le fseek va échouer lamentablement et la fonction va te renvoyer systématiquement NULL.

            Bon, c'est pas demain que je deviendrais C lead architect moi :-(
    • [^] # Re: Réponses

      Posté par  . Évalué à 1.

      if(n != 0) {
      text = realloc(text, (sizeof(char*)*(n+1))); }
      
      ptr = strchr(line, '\n');
      *ptr = '\0';
      text[n] = malloc(sizeof(char*)*strlen(line)+1);
      strcpy(text[n], line);
      n++;
      }
      Vu le coût d'un realloc(), il vaut mieux l'utiliser pour doubler la taille du tableau à chaque appel (pseudo-code non testé) :
      size_t capacity = 1;
      size_t n = 0;
      char **text = malloc (capacity * sizeof(char*));
      char *ligne = NULL;
      if (text == NULL)
      {
          return NULL;
      }
      while (lire_ligne(ligne, file) != NULL)
      {
           if (n == capacity)
          {
              char **tmp = NULL;
              capacity *= 2;
              tmp = realloc(text, capacity * sizeof(char*));
              if (tmp == NULL)
              {
                  /* free(text) et tout ce qui précède */
                  return NULL;
              }
              text = tmp;
          }
          text[n] = ligne;
          n++;
      }
      Où la fonction lire_ligne est un wrapper autour de fgets() qui ne tronque pas les lignes (cf. https://linuxfr.org/comments/713347.html#713347 pour un de mes messages à ce sujet). De plus, comme dans mon pseudo-code, il faut tester le retour de realloc(), pour éviter les fuites de mémoire.

Suivre le flux des commentaires

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