Forum Programmation.c concatenation de chaine

Posté par  .
Étiquettes : aucune
0
29
juin
2007
Bonjour,

Je débute en C et J'essaie de faire un programme qui lance une commande OS et qui récupère la sortie de cette commande dans une variable.

J'ai un debut de programme qui marche mais il me reste 2 problèmes
1) j'arrive à lire la sortie de la commande caractère par caractère, mais quand je les concatene, j'ai une chaine de la bonne longueur mais tous les caracteres sont vides !

2) Il y a apparemment un problème dans mon utilisation de realloc car le programme se termine par un problème de mémoire

J'ai essayé pas mal de chose mais je ne vois vraiment pas de solution.
Quelqu'un pourrait il m'aider?

Merci d'avance

Voici mon programme:

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

int
main (void)
{
FILE *output;
char vc_car;
char *vc_str = NULL;
int vn_size;

// Execution de la commande OS
output = popen ("echo sortie_commande", "r");
if (!output) {
fprintf (stderr, "incorrect parameters or too many files.\n");
return EXIT_FAILURE;
}

vc_car = getc(output);
while (vc_car != EOF) {
if (!vc_str) {
// premiere allocation de memoire pour vc_str
vn_size = sizeof(vc_str);
vc_str = (char *) malloc (vn_size);
}

else {
// on augmente la taille de vc_str au fur et a mesure des caracteres lus
//
// vn_size = taille + 1 pour le caractere \0 indiquant la fin de la chaine
vn_size = sizeof(vc_str) + sizeof(vc_car) + 1;

vc_str = realloc (vc_str, vn_size);
if (vc_str == (char *)NULL) {
printf("Cannot allocate memory.\n");
}
}

vc_str = strcat(vc_str, &vc_car);

// Affichage
fprintf (stdout, "%c\n", vc_car);
fprintf (stdout, "x%sx\n", vc_str);
fprintf (stdout, "--------------\n");

vc_car = getc(output);
}

if (pclose (output) != 0)
{
fprintf (stderr, "Could not run more or other error.\n");
}
return EXIT_SUCCESS;
}



..... et la sortie a l'exécution :

vc_car : s
vc_str : x�x
--------------
vc_car : o
vc_str : x��x
--------------
*** glibc detected *** realloc(): invalid next size: 0x0804a0b8 ***
Abandon
  • # ...

    Posté par  . Évalué à 2.

    strcat(vc_str, &vc_car);
    La fonction strcat() ajoute la chaîne src à la fin de la chaîne dest en

    Or tu utilises un charactere en second argument.



    // vn_size = taille + 1 pour le caractere \0 indiquant la fin de la chaine


    vn_size = sizeof(vc_str) + sizeof(vc_car) + 1;

    Ca fait beaucoup de "\0 indiquant la fin de la chaine" en comptant tout les tours de boucle.
  • # Hum, réfléchis

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

    Bon déjà tu as un soucis d'algorithme tout bête :
    if (!vc_str) // !null
    {
    sizeof(vc_str); // sizeof(null)
    }

    Je pense pas que ça soit voulu...
    Dégage ton sizeof(null) qui sert a rien et met direct :
    vc_str = (char *) malloc (char);

    Ensuite pour ton realloc arrête les bêtises :
    vc_str = realloc (vc_str, vn_size); // stupide
    Utilise :
    vc_str = reallow(vc_str, strlen(vc_str+2)); // longueur vc_str+\0+prochain caractère.

    Ensuite le test :
    if (vc_str == (char *)NULL)

    Le cast explicite est stupide, un NULL, restera TOUJOURS un NULL !
    • [^] # Re: Hum, réfléchis

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

      Whoops je viens de me rendre compte que j'ai fait des petites erreur aussi (en relisant le commentaire au dessus).

      Pas :
      vc_str = (char *) malloc (char);
      Mais :
      vc_str = (char *)mallow(2*sizeof(char));

      Et au lieu de strcat utilise ça :
      vc_str[strlen(vc_str)] = vc_car;
      vc_str[strlen(vc_str)] = '\0';
      Ça permettra de copier le caractère a la place du \0 de la chaîne (strlen renvoie la taille totale, l'indexation commence a 0, donc tu tombe sur le \0 de fin de chaîne pile)

      Bon après tu remplace le dernier caractère de la chaîne par un caractère nul, c'est une bonne idée je pense, car ça évite les ennuis (par exemple si ton système initialise pas la zone de mémoire malloqué à 0)
      • [^] # Re: Hum, réfléchis

        Posté par  . Évalué à 4.

        Whoops je viens de me rendre compte que j'ai fait des petites erreur aussi (en relisant le commentaire au dessus).

        Pas :
        vc_str = (char *) malloc (char);
        Mais :
        vc_str = (char *)mallow(2*sizeof(char));


        C'est vrai que les char mallow(), c'est bien meilleur. Surtout autour d'un feu de camp ! :-)
        • [^] # Re: Hum, réfléchis

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

          Ah ah ah, effectivement elle est belle ;)

          Bah, c'est comme tout, on fait toujours de erreurs en codant quoique ce soit.

          Après tout dépend la proportion, est-ce 1/10 000 comme les pro ou plus.

          A savoir que j'ai pas fait de C depuis 2ans.
  • # merci...

    Posté par  . Évalué à 1.

    Merci beaucoup à vous deux, vos réponses m'ont vraiment dépanné. J'ai réussi à faire fonctionner mon programme mais il y a quelque chose qui m'étonne un peu : quand je fais le realloc, je prend uniquement strlen(vc_str) + 1 et pourtant ça ne plante pas. J'avais pourtant lu qu'il fallait toujours réserver un caractère en fin de chaine pour le caractere null (qui indique la fin de la chaine). Le nouveau code source:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int
    main (void)
    {
       FILE *output;
       char vc_car;
       char *vc_tmp = NULL;
       char *vc_str = NULL;
    
       // Execution de la commande OS
       output = popen ("echo sortie_commande", "r");
       if (!output) {
           fprintf (stderr, "incorrect parameters or too many files.\n");
           return EXIT_FAILURE;
       }
    
       vc_tmp = (char *) malloc (sizeof(vc_car));
    
       vc_car = getc(output);
       while (vc_car != EOF) {
             if (vc_str == NULL) {
                // premiere allocation de memoire pour vc_str
                vc_str = (char *) malloc (sizeof(vc_car));
                if (vc_str == NULL) {
                   printf("Cannot allocate memory.\n");
                }
             }
    
             else {
                // on augmente la taille de vc_str au fur et a mesure des caracteres lus
                vc_str = realloc (vc_str, strlen(vc_str) + 1);
                if (vc_str == NULL) {
                   printf("Cannot allocate memory.\n");
                }
             }
    
             *vc_tmp = vc_car;
             vc_str = strncat(vc_str, vc_tmp, 1);
    
             // Affichage
             fprintf (stdout, "vc_car : %c\n", vc_car);
             fprintf (stdout, "vc_str : x%sx\n", vc_str);
             fprintf (stdout, "--------------\n");
    
             vc_car = getc(output);
      }
    
      if (pclose (output) != 0)
        {
          fprintf (stderr, "Could not run more or other error.\n");
        }
      return EXIT_SUCCESS;
    }
    
    • [^] # Re: merci...

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

      Regarde mon commentaire plus haut :
      vc_tmp = (char *) malloc (sizeof(vc_car));
      A mettre a la place :
      vc_tmp = (char *) malloc (2*sizeof(char));
      
      Ton code deviendrais :
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      
      int main (void)
      {
      	FILE *output;
      	char vc_car;
      	char *vc_str = NULL;
      	// Execution de la commande OS
      	output = popen ("echo sortie_commande", "r");
      	if (!output)
      	{
      		perror("erreur popen");
      		return EXIT_FAILURE;
      	}
      
      	vc_car = getc(output);
      	while (vc_car != EOF)
      	{
      		if (!vc_str)
      		{
      			// premiere allocation de memoire pour vc_str
      			vc_str = (char *) malloc (2*sizeof(char));
      			if (!vc_str)
      			{
      				perror("erreur malloc");
      				return EXIT_FAILURE;
      			}
      		}
      		else
      		{
      			// on augmente la taille de vc_str d'un caractère
      			vc_str = (char *)realloc (vc_str, strlen(vc_str)+2*sizeof(char));
      			if (!vc_str)
      			{
      				perror("erreur realloc");
      				return EXIT_FAILURE;
      			}
      		}
      		vc_str[strlen(vc_str)] = vc_car;
      		vc_str[strlen(vc_str)] = '\0';
      		// Affichage
      		printf("%c\n", vc_car);
      		printf("x%sx\n", vc_str);
      		printf("--------------\n");
      
      		// Nouveau caractère
      		vc_car = getc(output);
      	}
      
      	if (pclose (output) != 0)
      	{
      		perror("erreur pclose");
      		return EXIT_FAILURE;
      	}
      	return EXIT_SUCCESS;
      }
      
      • [^] # Re: merci...

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

        Il manque un :
        #define _GNU_SOURCE

        Avant l'include de stdio.h sinon gcc te sortira une erreur stricte comme quoi il est pas définis.

        ps : pense a compiler tes programmes comme ceci :
        $ gcc -Wall -str=c99 ton_fichier.c
    • [^] # Re: merci...

      Posté par  . Évalué à 3.

      Ca ne plante pas parce que tu es chanceux(le byte apres l'allocation est dans une page memoire valide et pas utilise).

      Une chose a comprendre c'est que ce ne'st pas parce que ton code ne plante pas qu'il est correct. Il pourrait crasher sur un systeme different, avec une configuration differente, si tu changes qqe chose ailleurs dans ton code (car le byte que tu ecrases apres le buffer y est utilise, ...)

      Et en passant, si ton realloc rate, tu ne fais qu'afficher un message d'erreur, ton code continuera a s'executer et il plantera.
  • # getc renvoie un int

    Posté par  . Évalué à 1.

    getc() renvoie un int que tu met dans un char et que tu compare à EOF.

    chez moi EOF est un nombre négatif égal à -1, ça veut dire que si jamais la commande renvoie le caractère 255 alors le programme va considérer ça comme la fin du fichier.

    chez d'autres ça peut avoir d'autres effets.

Suivre le flux des commentaires

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