Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

warning: function returns address of local variable

65 réponses
Avatar
pere.noel
à la compile d'un ensemble de fonctions + main, j'ai le message de
warning :
function returns address of local variable
pour la fonction "target_path_normalize"

le but de cette fonction :
si j'ai en entrée :

target_path_checked =
////Users////yvon/./////////////////////work/C/../.headers
toto/CFArray.h

elle retourne ce path normalisé :
target_path_normalized = /Users/yvon/work/.headers toto/CFArray.h

cette fonction "marche" mais je me demande quel risque je prends en
laissant trainer ce warning

le contexte : avant l'utilisation de cette fonction, j'en utilise une
autre "target_path_check" qui retourne NULL si le path n'est pas absolu
et accessoirement supprime le "/" en fin de chaîne s'il existe.

--- target_path_normalize ---------------------------------------------
char* target_path_normalize(const char* target_path)
{
int trente_deux = 32; /* maximum de répertoires traversés */
int mille_vingt_quatre = 1024; /* taille maximum d'un path */
char p[mille_vingt_quatre]="";
char *q;
char *token;
const char needle[] = "/";
const char *dot = ".";
const char *dotdot = "..";
int j;
q = strdup(target_path);
j = 0;
char *pieces[trente_deux];
// initialisation des éléments du tableau à NULL
while(j < trente_deux) {
pieces[j] = NULL;
j++;
}

// démarrage du découpage de q (target_path)
token = strtok(q, needle);
j = 0;

// découpage de q (target_path)
while(token != NULL) {
// si ".." on décrémente j equivalent à cd ..
// si "." on ne fait rien
// si différent de ".." et de "." on enregistre token dans
pieces[j] et on incrémente j
if(strcmp(token, dotdot) == 0) {
j--;
} else if(strcmp(token, dot) != 0) {
pieces[j]=token;
j++;
}
token = strtok(NULL, needle);
}
j = 0;

// concaténation de "/" (needle) et de pieces[j] jusqu'à épuisement
(quand pieces[j] == NULL)
while(pieces[j] != NULL) {
strcat(p, needle);
strcat(p, pieces[j]);
j++;
}
return p;
}
-----------------------------------------------------------------------
donc c'est le "return p" qui pose pb à la compil mais pas à
l'utilisation.
--
une bévue

10 réponses

1 2 3 4 5
Avatar
Harpo
Une bévue wrote:

voilà, merci, ou peut donc faire qqc du genre :

---------------------------------
char * ma_fonction(...) {

char * ptr;
ptr=malloc(...);

[...]

return ptr;
}

int main(...) {
//l'appel de la fonction :

char * mon_ptr=ma_fonction(...);


Là il faut mttre quelque chose avant le printf parce que le premier
peut se trouver 3 km plus loin et ça va t'afficher du garbage pendant
ce temps là si ça ne se plante pas avant.

printf("mon_ptr=%sn", mon_ptr);

// plus besoin de mon_ptr on libère

free(mon_ptr);
mon_ptr=NULL;

return EXIT_SUCCESS;
}


Benissimo!

---------------------------------

donc, si j'ai bien compris (je commence à me faire à C, ça commence à
devenir amusant) :


Excellent!

--
http://patrick.davalan.free.fr/

Avatar
pere.noel
Harpo wrote:


S'il doit retourner de la mémoire allouée, il vaut mieux qu'il ne la
libère pas avant de retourner, hein.


ben dam !


char* target_path_dirname(const char* target_path) {
[...]
p = (char *) malloc (PATH_SIZE_MAX * sizeof (char));


Je crois que sizeof(char) vaut toujours 1, à vérifier.


oui, mais je laisse tel quel car je passerai en utf8 et là
sizeof(<charUTF8>) != 1


if (p == NULL)
{ /* l'allocation a echoué: */
/* message d'erreur et arrêt du programme */
printf ("Malloc failed !n");
return NULL;


Cool !

}
[...]
return p;
}

je ne vois pas trop comment m'en sortir sinon en définissant p à
l'extérieur en ajoutant un paramètre à la function qqc dans ce goût là


p est retourné par valeur, comme toujours, ce qui fait que la fonction
appelante aura l'adresse de la mémoire allouée.
Je ne vois pas ce qui pose problème à moins que j'ai loupé un truc.


c'est moi qui n'avais pas vu que je peut libérer la mémoire EN DEHORS de
la fonction :

char * ma_fonction(...) {
char * ptr;
ptr = malloc(...)
[...]
return ptr;
}

// appel de ma_fonction

char * bidule = ma_fonction(...)
[...]
// plus besoin de bidule
free(bidule);
bidule=NULL;
[...]

la libération de bidule entraine la libération de la mémoire allouée à
ptr aussi car tout deux pointent la même adresse !

CQFD ;-)

c'est ce que je n'avais pas pigé...
Ta fonction m'a l'air bonne.
Ce n'est pas comme si t'avais mis
char p[] = "blah";
(blah étant alloué dans la pile)
D'ailleurs je me demande même si
char * p = "blah";
(blah étant alloué ailleurs que dans la pile)
ne serait pas valide

Sinon, target_path n'est pas utilisé dans la fonction, de bonnes options
de warning auraient du te le signaler.


si je n'ai pas tout donné du code...

--
une bévue


Avatar
pere.noel
Harpo wrote:

oui, mais c'est plus zoli )))


J'ai parfois vu ça dans des programmes écrits par des dandies.


pour moi, c'est un "pense-bête" : me rappeller que je dois passer en
UTF8...
--
une bévue


Avatar
Jean-Marc Bourguet
Harpo writes:

Je crois que sizeof(char) vaut toujours 1, à vérifier.


Confirmé.

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Eric Levenez
Le 7/09/06 18:33, dans
<1hlb4dj.19eot8n17t0kgwN%, « Une bévue »
a écrit :

Harpo wrote:

Je crois que sizeof(char) vaut toujours 1, à vérifier.


oui, mais je laisse tel quel car je passerai en utf8 et là
sizeof(<charUTF8>) != 1


Il faut comprendre que l'UTF-8 c'est un encodage sur plusieurs octets
(jusqu'à 5 je crois). Chaque octet est codé dans un char (donc le sizeof
vaut 1 par définition). Si tu utilises une machine avec des char de 32 bits,
alors il te faudra des types de 160 bits... Tout l'intérêt de l'UTF-8, c'est
qu'on le traite comme des chaînes de caractères normales.

Je n'arrive toujours pas à comprendre pourquoi tu persistes à figer ton code
avec des constantes sur la taille max d'un path, la nombre max de caractères
ou d'octet dans un nom, le nombre de "/" dans un path... Tu ne devrais
jamais avoir à faire cela. Jamais.

c'est moi qui n'avais pas vu que je peut libérer la mémoire EN DEHORS de
la fonction :

char * ma_fonction(...) {
char * ptr;
ptr = malloc(...)
[...]
return ptr;
}

// appel de ma_fonction

char * bidule = ma_fonction(...)


Ne pas oublier que bidule peut être NULL.

[...]
// plus besoin de bidule
free(bidule);


Il se trouve que tu as du pot car si bidule est NULL, alors free ne plantera
pas (il a été blindé à cause de programmeurs qui ne testaient pas le code de
retour de malloc).

bidule=NULL;


Ça c'est une bonne habitude.

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.


Avatar
pere.noel
Harpo wrote:

Là il faut mttre quelque chose avant le printf parce que le premier
peut se trouver 3 km plus loin et ça va t'afficher du garbage pendant
ce temps là si ça ne se plante pas avant.


attends dans mes fonctions justement j'ai un ptr qui se balade de
caractère en caratère ET quand il a trouvé ce qu'il cherche (par ex un
"/") il fait par exemple :
q += target_path_length - 1;
// supress all final "/" if any
if(target_path_length != 1) {
while(*q == '/') {
*q = 0;
q--;
}
}
return p;

ce qui fait que p pointe sur le début de la chaîne "target_path" (p = q
au départ) avec un au bon dendroit...

ce que je trouve "génial" là-dedans c'est les lignes :
*q = 0;
q--;

j'arrive avec des trucs de ce genre à nettoyer un path qui serait donné
comme ça :
%> ./get_basename_dirname_test
////Users////yvon/./////////////////////work/C/../.headers
toto/CFArray.h////

(un peu tordu l'exemple))))

target_path_checked ////Users////yvon/./////////////////////work/C/../.headers
toto/CFArray.h

target_path_normalized = /Users/yvon/work/.headers toto/CFArray.h

et finalement ce qui est recherché :
basename = CFArray.h
dirname = /Users/yvon/work/.headers toto

--
une bévue

Avatar
Eric Levenez
Le 7/09/06 19:46, dans
<1hlb7ln.upahxn1n1jy8lN%, « Une bévue »
a écrit :

ce que je trouve "génial" là-dedans c'est les lignes :
*q = 0;
q--;



*q-- = 0;

Si tu voulais dans l'autre sens :

q--;
*q = 0;


*--q = 0;


Cela peut, au début te sembler dur à lire, cela te deviendra aussi naturel
que le classique :

*p++ = 0;

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.

Avatar
pere.noel
Eric Levenez wrote:


Il faut comprendre que l'UTF-8 c'est un encodage sur plusieurs octets
(jusqu'à 5 je crois). Chaque octet est codé dans un char (donc le sizeof
vaut 1 par définition).


aille aille aille, bizarre cette convention, pourquoi garder le nom char
alors ???

Si tu utilises une machine avec des char de 32 bits,
alors il te faudra des types de 160 bits... Tout l'intérêt de l'UTF-8, c'est
qu'on le traite comme des chaînes de caractères normales.


en C tu veux dire ?
c'est pas très chouette côté occupation mémoire quand la machine a des
mots de 32 bits. ça me surprend il doit y avoir un quiproquo.

si une machine a des mots de 32 bits on met quand même (avec C) 4 octets
dans un mot machine non ?

je n'ai pas pigé ce que tu veux dire...

Je n'arrive toujours pas à comprendre pourquoi tu persistes à figer ton code
avec des constantes sur la taille max d'un path, la nombre max de caractères
ou d'octet dans un nom, le nombre de "/" dans un path... Tu ne devrais
jamais avoir à faire cela. Jamais.


ben là le nom d'un fichier et au max Apple, je peux mettre moins et
réallouer après oui, je commence par du fixe c'est plus didactique pour
moi. maintenant que mon test me semble OK sans réalloc je vais pouvoir
passer à la réalloc. j'ai justemebt mis à part ces petites fonctions :
char* target_path_check(const char* target_path);
char* target_path_normalize(const char* target_path);
char* target_path_basename(const char* target_path);
char* target_path_dirname(const char* target_path);

pour les mettre au point "black et d'équerre" je les teste avec un
"get_basename_dirname_test.c" quand c'est OK je peux utiliser
directement les fichier "get_basename_dirname.h" et
"get_basename_dirname.c" dans mon RAliasFile|Record...


c'est moi qui n'avais pas vu que je peut libérer la mémoire EN DEHORS de
la fonction :

char * ma_fonction(...) {
char * ptr;
ptr = malloc(...)
[...]
return ptr;
}

// appel de ma_fonction

char * bidule = ma_fonction(...)


Ne pas oublier que bidule peut être NULL.

[...]
// plus besoin de bidule
free(bidule);


Il se trouve que tu as du pot car si bidule est NULL, alors free ne plantera
pas (il a été blindé à cause de programmeurs qui ne testaient pas le code de
retour de malloc).


je teste ptr = malloc (c'est dans le [...] tout le code n'est pas
donné), un exemple :
p = (char *)calloc(PATH_SIZE_MAX, sizeof(char));
if(p == NULL)
{ /* l'allocation a echoué: */
/* message d'erreur et arrêt du programme */
printf ("Calloc failed !n");
return NULL;
}

bidule=NULL;


Ça c'est une bonne habitude.



--
une bévue


Avatar
pere.noel
Eric Levenez wrote:

ce que je trouve "génial" là-dedans c'est les lignes :
*q = 0;
q--;



*q-- = 0;


à droite (les "--") : post-[in|dé]crémentation
à gauche (les "--") : pre-[in|dé]crémentation

oui, la symbolique est logique.

Si tu voulais dans l'autre sens :

q--;
*q = 0;


*--q = 0;


ok, c'est marrant coom ça ))
--
une bévue


Avatar
Eric Levenez
Le 7/09/06 20:13, dans
<1hlb8lp.3iyknltjxyi8N%, « Une bévue »
a écrit :

Eric Levenez wrote:


Il faut comprendre que l'UTF-8 c'est un encodage sur plusieurs octets
(jusqu'à 5 je crois). Chaque octet est codé dans un char (donc le sizeof
vaut 1 par définition).


aille aille aille, bizarre cette convention, pourquoi garder le nom char
alors ???


"char" est le type le plus petit adressable en mémoire. Beaucoup de CPU
actuels ont des char de 8 bits, mais les DSP utilisent typiquement des char
de 16, 24 ou 32 bits. Sur ces CPU il n'est pas possible d'adresser plus
petit : le mot machine n'est pas 8 bits.

Le C définit différentes types, mais ne fixe pas précisément les tailles de
ces types ainsi :

char <= short <= int <= long <= long long

Sur ton Mac OS X :

8 <= 16 <= 32 <= 32 <= 64

Mais sur un DSP 32 bits :

32 <= 32 <= 32 <= 32 <= 64

Si tu utilises une machine avec des char de 32 bits,
alors il te faudra des types de 160 bits... Tout l'intérêt de l'UTF-8, c'est
qu'on le traite comme des chaînes de caractères normales.


en C tu veux dire ?


Le type 160 bits n'existe pas en C.

c'est pas très chouette côté occupation mémoire quand la machine a des
mots de 32 bits. ça me surprend il doit y avoir un quiproquo.


Oui. Mais sur un DSP 32 bits, on utilise rarement des char : ces CPU sont
fait pour faire de gros calculs rapidement, pas pour traiter du texte car un
simple "hello word" prend 4 fois plus de place en mémoire que sur un Cpu 32
bits traditionnel

si une machine a des mots de 32 bits on met quand même (avec C) 4 octets
dans un mot machine non ?


Il y a 4 octets sur 32 bits oui, et comme un char est 32 bits alors le
craactère 'a' fait 4 octet et la chaîne "hello world" en fait 48 octets
(avec le 0 final).

je n'ai pas pigé ce que tu veux dire...


Sur un CPU traditionnel si tu as une adresse mémoire 0x1000, alors tu
peut y accéder en 8, 16 ou 32 bits. Ceci permet de stocker par exemple un 32
bits (de 0x1000 à 0x1003). Sur un DSP 32 bits, l'adresse mémoire 0x1000
contient un 32 bits, l'adresse 0x1001 contient un autre 32 bits...

je teste ptr = malloc (c'est dans le [...] tout le code n'est pas
donné), un exemple :
p = (char *)calloc(PATH_SIZE_MAX, sizeof(char));


On ne caste pas en C le retour de calloc ou de malloc.

On ne fait jamais sizeof(char) car cela vaut 1 par définition.

Quand tu veux mettre dans la variable n le nombre de 1000 carottes, tu ne
fais pas...

n = 1000 * 1;

...pour indiquer que c'est 1000 fois 1 carotte.

Si tu veux marquer ton code pour y revenir plus tard (traitement UTF-8 comme
tu le disais), alors mets des commentaires du type :

// TODO : passer en UTF-8

Après tu rechercheras les TODO.

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.


1 2 3 4 5