Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 07/10/2015, à 21:18

DonutMan75

[RESOLU] [C] Initialiser un tableau de pointeur sur char

Bonsoir à tous,
je me plonge un peu dans les bases du C et j'aimerais réaliser l'exemple (didactique !) suivant : créer un tableau de 4 pointeurs sur char et attribuer à chaque char pointé les lettres 'X', 'Y' et 'Z' (plus le caractère de fin '\0').

J'ai le code suivant qui marche mais qui ne me semble pas très propre :

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

main()
{
char *p[4];

p[0] = (char *) malloc(sizeof(char));
p[1] = (char *) malloc(sizeof(char));
p[2] = (char *) malloc(sizeof(char));
p[3] = (char *) malloc(sizeof(char));

*(p[0]) = 'X';
*(p[1]) = 'Y';
*(p[2]) = 'Z';
*(p[3]) = '\0';

int k;

for(k=0;k<4;k++)
        printf("p[%d] = %p\n", k, p[k]);

for(k=0;k<4;k++)
        printf("*p[%d] = %c\n", k, *(p[k]));

free(p[3]);
free(p[2]);
free(p[1]);
free(p[0]);
}

Ca compile et ça retourne un résultat cohérent. A savoir :

$./test
p[0] = 0xf59008
p[1] = 0xf59018
p[2] = 0xf59028
p[3] = 0xf59038
*p[0] = X
*p[1] = Y
*p[2] = Z
*p[3] =

En revanche, je pense que ce n'est pas très propre car les 4 adresses mémoires p[0], p[1], p[2] et p[3] doivent être contiguës... et rien dans mon code ne me l'assure... En particulier, si je rentre un printf("Chaine : %s\n", p[0]) ça ne me renvoie que le premier caractère (donc "X"), alors que je souhaite avoir "XYZ"... Confirmez-vous mon analyse ?

Ma question est donc la suivante :
comment pourrais-je modifier mon code pour avoir 4 blocs mémoire contigus ?

J'avais pensé à un p = (char *) malloc(4*sizeof(char)); mais j'ai du coup un beau segmentation fault....

Merci d'avance pour vos réponses :)

D.

Dernière modification par DonutMan75 (Le 08/10/2015, à 09:28)

Hors ligne

#2 Le 07/10/2015, à 21:37

alius

Re : [RESOLU] [C] Initialiser un tableau de pointeur sur char

tu as donné toi même la solution :

char * p =  (char*)malloc(4*sizeof(char));

qui te donnera un pointeur p pointant sur zone mémoire alloué pour 4 char.

Ce que tu as fait toi c'est un tableau de pointeur ! donc un pointeur constant de pointeurs de char.
Donc tu as bien tes pointeurs de char qui sont contiguës en mémoire (puisque dans un tableau). En revanche aucun moyen d'en être sur pour les char que tu allous avec malloc.

tu pourras a ta guise accéder à ces char en utilisant :

p[0] = 'X';
p[1] = 'Y';
...

de cette manière tu pourras également libérer la mémoire d'un seul coup avec :

free(p);

edit :
en fait il faut voir une équivalence dans les deux notations suivante :

p[0] = 'X';
p[1] = 'Y';

et

*(p+0) = 'X';
*(p+1) = 'Y'

tu peux utiliser des oparations sur un pointeurs par exemple pour un pointeur  p sur un char, l'expression p+1 donne l'adresse de p + la taille d'un char. Ce qui donne l'adresse du deuxième char du tableau.

Dernière modification par alius (Le 07/10/2015, à 21:43)


Alius

Hors ligne

#3 Le 07/10/2015, à 21:40

pingouinux

Re : [RESOLU] [C] Initialiser un tableau de pointeur sur char

Bonsoir,
Les éléments de ton tableau p sont des pointeurs, qui pointent chacun sur un caractère.
Tu peux faire une indirection de moins, et mettre les caractères directement dans les éléments de ton tableau.
Voici 2 façons de faire :

$ cat x.c
#include <stdio.h>
#include <stdlib.h>

int main(){

char *p = (char *) malloc(4*sizeof(char));
p[0] = 'X';
p[1] = 'Y';
p[2] = 'Z';
p[3] = '\0';
printf("p=%s\n",p);

char *q = "XYZ\0";
printf("q=%s\n",q);
}

qui donne ce résultat

$ make x && ./x
cc     x.c   -o x
p=XYZ
q=XYZ

Ajouté : On se fait souvent griller pendant que l'on répond.

Dernière modification par pingouinux (Le 07/10/2015, à 21:43)

Hors ligne

#4 Le 08/10/2015, à 09:33

DonutMan75

Re : [RESOLU] [C] Initialiser un tableau de pointeur sur char

Hello,
merci beaucoup pour vos réponses, c'est très clair maintenant smile

J'en profite pour une dernière petite question : je souhaite faire une fonction qui en entrée a un int (par exemple 5) et en sortie retourne un pointeur vers un int valant cette valeur.

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

int *appel(int i);

main()
	{
	int *p = appel(5);
	printf("p : %p, *p : %d\n", p, *p);
	}
	
int *appel(int i)
{
int j = i;
return &j; // Mauvais (j est supprimé à la fin de la fonction...), warning mais ça marche...
}

Ici cette solution est très mauvaise : j est une variable LOCALE. On retourne un pointeur vers j. J'ai un warning à la compilation mais ça marche. Le problème : rien ne me garantit que plus tard, cette zone mémoire ne sera pas écrasée par une autre déclaration de variable. Est-ce correct ?

Une version propre de cette fonction serait :

int *appel(int i)
{
int *p = malloc(sizeof(int));
*p = 5;
return p;
}

Ici la variable LOCALE p est bien supprimée à la fin de la fonction, mais ce n'est pas grave puisqu'on la récupére en sortie de fonction. En revanche, la zone mémoire pointée par p est bien toujours réservée.

Qu'en pensez-vous ?

Merci d'avance smile

D.

Dernière modification par DonutMan75 (Le 08/10/2015, à 09:34)

Hors ligne

#5 Le 08/10/2015, à 10:24

pingouinux

Re : [RESOLU] [C] Initialiser un tableau de pointeur sur char

Je pense que ton analyse est bonne. Après les appels à la seconde fonction, il faudra penser ensuite à désallouer la mémoire à un moment ou un autre.
Voici un petit test qui montre que la première fonction n'est pas correcte.

$ cat x.c
#include <stdio.h>
#include <stdlib.h>
	
int *appel(int i)
{
int j = i;
return &j; // Mauvais (j est supprimé à la fin de la fonction...), warning mais ça marche...
}

int *appel2(int i)
{
int *p = malloc(sizeof(int));
*p = i;
return p;
}

main() {
	int *p = appel(5);
	printf("p : %p, *p : %d\n", p, *p);
        appel(50);
	printf("p : %p, *p : %d\n", p, *p);

	int *q = appel2(6);
	printf("q : %p, *q : %d\n", q, *q);
        appel2(60);
	printf("q : %p, *q : %d\n", q, *q);
}

qui donne ce résultat

$ make x && ./x
cc     x.c   -o x
x.c: In function ‘appel’:
x.c:7:1: warning: function returns address of local variable [-Wreturn-local-addr]
 return &j; // Mauvais (j est supprimé à la fin de la fonction...), warning mais ça marche...
 ^
p : 0x7ffca73ca57c, *p : 5
p : 0x7ffca73ca57c, *p : 50
q : 0x19d3010, *q : 6
q : 0x19d3010, *q : 6

Hors ligne

#6 Le 08/10/2015, à 10:36

claudius01

Re : [RESOLU] [C] Initialiser un tableau de pointeur sur char

Bonjour,

DonutMan75 a écrit :

... Qu'en pensez-vous ?

Cela serai encore mieux si tu libérai le pointeur p dès lors qu'il n'est plus utilisé ;-)

main()
{
	int *p = appel(5);
	printf("p : %p, *p : %d\n", p, *p);
        free(p);
}

Edit: Doublé par pingouinux qui a écrit "... il faudra penser ensuite à désallouer la mémoire à un moment ou un autre". Habitude à prendre même si dans la pratique celle-ci sera libérée à la sortie de la fonction main().

Dernière modification par claudius01 (Le 08/10/2015, à 11:03)

Hors ligne