Forum Programmation.c Pointeur et chaines de caractères...

Posté par  .
Étiquettes : aucune
0
29
août
2005
Bonjour,

J'essayes de renvoyer un chaine de résultat, qui est de taille variable.
Le pointeur est initialisé avec la valeur de getenv, si getenv ne renvoie pas de valeur, le pointeur de retour doit contenir NULL, dans le cas contraire il doit contenir le résultat entre guillemets : 'resultat'

Je comprend bien que dans mon exemple, si getenv renvoi une valeur, et que je veux moi insérer dans le même pointeur cette valeur + quelquechose, il faudrait que je l'agrandisse... j'ai essayé avec realloc, mais ca n'a pas marché (je ne sais pas utiliser cette fonction peut-etre)
Ce qui me perturbe, c'est que j'ai essayé de créer une variable
char buf[100];
et que la aussi j'ai une erreur à la ligne 11 modifiée comme suit :
buf = sprintf("%s",ptr_env);

Si quelqu'un pouvait me dire comment écrire cette fonction proprement,
ET SURTOUT m'expliquer quelle est l'erreur de compréhension qui me poursuit avec ces pointeurs !! :'(


1 #include <stdio.h>
2 #include <stdlib.h>
3
4
5 char *get_env(char * ptr_string){
6 char *ptr_env;
7 ptr_env = getenv(ptr_string);
8 if (ptr_env == NULL)
9 ptr_env = "NULL";
10 else{
11 ptr_env=sprintf("'%s'",ptr_env);
12 }
13 return(ptr_env);
14 }
15
16 /*
17 int main(){
18 printf("%s\n",get_env("TS_VERSIOdN"));
19 }
20 */
  • # Le C et la gestion des chaines de caractères ...

    Posté par  . Évalué à 3.

    Tout d'abord, sache que gérer des chaines de caractères en C n'est pas une mince affaire, et qu'il vaut mieux avoir lu quelques docs dessus avant de se lancer (j'ai pas de liens en tête sur le moment).

    Ensuite, pour ton problème :

    En ce qui concerne le redimensionnement d'une chaine, cela n'est (généralement) possible que sur les chaine que tu a alloué toi-même (ou alors si tu est vraiment sur que la chaine qu'on te renvoie a été allouée avec malloc) sinon un realloc ne marchera pas. Et de toutes facons, quand une fonction te renvoie un pointeur sur un truc du système ou de l'environnement, il ne vaut mieux pas y toucher et plutot faire une copie. Ca pourra aussi t'etre utile si t'es ammené à la modifier après.

    Pour le sprintf(), deux problèmes :
    - il n'alloue pas tout seul la mémoire, donc c'est à toi de le faire (malloc)
    - tu as mal utilisé sprintf : le premier argument est le buffer dans lequel tu vas écrire, le deuxième est le format, et les suivants les arguments du format. Donc ca devrait etre quelques chose comme : sprintf(ptr_env, "'%s'", ptr_env); bien que ce soit une très mauvaise idée d'utiliser le même pointeur; comme ça je crois que ca fout ta chaine en l'air...

    Une remarque également sur ton essai avec buff[100] (en plus du problème de l'ordre des arguments) : ceci déclare un buffer statique (contrairement au malloc(), dynamique) qui pointera donc toujours vers la meme zone mémoire. Donc si tu fais deux appels à ta fonction, le deuxième renverra le meme pointeur, certes avec la bonne chaine, mais à ce moment là la première aura été remplacée par la deuxième ... (idem pour le "NULL" : tu n'as pas intéret à le modifier après)

    Bon, tout ca pour finir avec ce bout de code la (non testé):

    char *get_env(char * ptr_string){
    char *ptr_env, *quoted_env;
    ptr_env = getenv(ptr_string);
    if (ptr_env == NULL) {
    quoted_env = strdup("NULL");
    else{
    quoted_env=malloc(strlen(ptr_env)+3);
    sprintf(quoted_env, "'%s'", ptr_env);
    }
    return(quoted_env);
    }

    Tout ca sans oublier de free() le résultat une fois fini.
    Remarque ici que strdup() renvoie une chaine allouée par malloc(), comme décrit dans la doc (man strdup), tu pourra donc le realloc si tu veux (tu va me dire qu'après ta fonction ca sert plus a rien, ok ...).
    Autre détail : le malloc() qui prend la taille de la chaine + 2 pour les deux quotes et + 1 pour le "null terminator", soit le terminateur de chaine en C (qui est 0).
    De plus, il est généralement mieux d'utiliser snprintf() que sprintf() afin d'éviter de déborder du buffer ...

    Bref, tout ca pour dire que la gestion des chaines en C c'est galère, et je ne sais pas pourquoi tu veux faire ca mais je te conseillerai d'utiliser la glib qui contient pas mal de fonctions pour gérer tout ca plus facilement. Ou alors de changer de langage ...
    Je ne veux pas te décourager, moi j'ai commencé par le C et je trouve ca assez ... "instructif"
    • [^] # Correction

      Posté par  . Évalué à 1.

      ... j'ai oublié une accolade avant le else ...
      • [^] # Re: Correction

        Posté par  . Évalué à 1.

        Encore une fois merci pour ton aide... :p Je recois un message d'erreur comme quoi il y a un problème de compatibilité avec le type du pointeur à la ligne :
        quoted_env = strdup("NULL");
        Je ne comprend pas trop, tu me dis qu'il est mieux d'utiliser glib pour manipuler ce genre de chose, je pensais qu'en programmant en c j'utilisait automatiquement glib ? Quel language est selon toi plus adapté ? C++ ? Vu que c'est pour un client léger, il faut qu'il y ait le moins de librairies exterieures possibles... C++ est-il à certains égards plus simple ou est-ce que c'est purement du c avec les objets en plus ?
        • [^] # Re: Correction

          Posté par  . Évalué à 3.

          Pour le pb du pointeur, j'avais oublié un petit include (pourtant évident ...) en début de fichier:
          #include <string.h>

          Pour la glib, je parle de celle de GTK (http://www.gtk.org/(...) ). Tu confonds avec la libc, qu'on utilise effectivement pour faire du C, et dont la version utilisée sous linux est celle du projet GNU, d'où son nom: glibc. Et les confusions qui vont avec à propos de son nom.

          Pour le C++ moi je le trouve pas plus simple, mais je doit pas etre super objectif ... mais oui, c'est uniquement du c avec des objets en +.

          Sinon pour te conseiller un langage .... bah si tu nous disais ce que tu veux faire d'abord ?
          Je sais pas trop mais a vue de nez je te conseillerai python si t'es pas encore super calé dans les détails bas-niveau. C'est mon langage de référence pour quasi tous mes développements (comme quoi on peut aimer le C mais pas pratiquer très souvent ...)
          • [^] # Re: Correction

            Posté par  . Évalué à 1.

            Merci, ca marche ! J'ai juste un avertissement, je ne sais pas à cause de quoi c'est... :
            getenv.c:9: Warnung: implicit declaration of function `strdup'
            getenv.c:9: Warnung: Zuweisung erzeugt Zeiger von Ganzzahl ohne Typkonvertierung

            Avec python, le programme que tu généres à besoin de librairies de python pour fonctionner sur le poste client, non ?
            Est-ce que tu peux utiliser toutes les librairies du système aussi ?
            • [^] # Re: Correction

              Posté par  . Évalué à 1.

              Encore une question où placer le free ?
              -après le return dans la fonction
              -dans la fonction appelante, une fois que le pointeur n'est plus utilisé ?

              Est-ce qu'il libere la mémoire de toutes les variables crées avec malloc, ou est-ce qu'on peut faire free(variable ou pointeur); ?
              • [^] # Re: Correction

                Posté par  . Évalué à 1.

                free() libère la mémoire... donc tu l'appelle ou tu veux mais a condition de ne plus utiliser le pointeur ensuite.
                et on fait un free sur un pointeur qui a été initialisé avec malloc ou realloc... free ne vide pas toute la mémoire, en C on gère la mémoire soit même, pointeur par pointeur.
                Je ne saurais trop te conseiller de lire le man à ce sujet:
                >man malloc
            • [^] # Re: Correction

              Posté par  . Évalué à 0.

              Le warning c'est a cause de l'include string.h que tu n'as pas rajouté.
              Aux vues de tes questions, je te conseille de commencer par un autre langage que le C, sinon tu va vraiment galérer ...

              Pour python, c'est un langage interprété et non compilé, donc tu as besoin de l'interpréteur sur le poste client. Enfin client de quoi ? On sait toujours pas (a peu près) ce que tu veux faire ... Mais pour les librairies systèmes, oui yen a un paquet fournit dans les libs pythons.
  • # Pointeurs, chaînes de caractères

    Posté par  . Évalué à 3.

    Salut,

    Je vois plusieurs problèmes dans ton programme :

    1) à la ligne :
    ptr_env=sprintf("'%s'",ptr_env);
    Il manque comme premier argument un pointeur sur une zone tampon (avant la chaîne de format).

    2) Ce tampon est obligatoire, n'essaye pas de modifier directement la zone pointée par ptr_env. De même, il n'y a aucune raison que realloc marche, car il n'y a aucune raison que la zone mémoire pointée par ptr_env ait été allouée par malloc. Bref : tout ce qui est renvoyé par getenv, c'est lecture seule (si tu veux modifier l'environnement => setenv, putenv....).

    3) Je ne sais pas ce que tu as essayé de faire avec char buf[100]; et malloc. Mais en tout cas, si tu déclare une variable "tampon", fais le EN DEHORS de la fonction get_env.
    En effet, si tu mets buf[100]; DANS la fonction, tu crées une tableau de caractères, certes, mais il s'agit d'une variable locale à ta fonction qui disparaît dès la sortie. Gênant pour récupérer la valeur.
    Avec malloc, en revanche, c'est possible de faire l'allocation à l'intérieur de la fonction en conservant la valeur renvoyée par malloc dans ptr_env, qui est alors renvoyé. A charge pour le programme appelant de libérer ensuite la mémoire.

    Voilà, j'espère que ça aide.

    A+
    • [^] # Re: Pointeurs, chaînes de caractères

      Posté par  . Évalué à 1.

      Oups, ton commentaire me fais remarquer que je me suis trompé pour le buf[100], il est effectivement alloué sur la pile, donc "libéré" au retour de la fonction (mais comme la mémoire n'est pas (toujours) écrasée les débutants croient parfois que ca roule ... he paf, un bug caché)

      Je plussoie
  • # sprintf est dangereux

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

    L'utilisation de sprintf peut mener à des erreurs de débordement de tampon. Que se passe-t-il si la variable d'environnement est trop grande ?
    Il est toujours préférale d'utiliser snprintf.
    snprintf (dest, sizeof(dest) , "%s", src);

Suivre le flux des commentaires

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