[C] malloc

Fermé
Onde2Choc Messages postés 299 Date d'inscription vendredi 6 août 2004 Statut Membre Dernière intervention 24 février 2006 - 30 août 2004 à 08:23
 Jolkdarr - 2 sept. 2004 à 20:19
Salut à tous !
Dans mon pèlerinage vers la fin de mon bouquin, me voila rendu au chapitre 15/21 (j'en suis maintenant au 16). Il s'agit d'un retour sur les pointeurs, avec une bonne partie consacrée aux listes chaînées. Voila mon problème : lors de la déclaration d'un nouvel élément d'une liste chaînée, les exemples du livres utilisent malloc comme ceci :
new = (person*)malloc( sizeof(person));

Person étant le nom de la structure et new un pointeur vers le nouvel élément. Mais à quoi peut bien servir le (person*) devant malloc ? Jusqu'ici j'aurais procédé comme ça :
new= malloc( sizeof(person));

Mais où est la différence entre mon code et la version du livre ?
De plus le livre évoque une nouvelle fonction, calloc, qui contrairement à malloc, "nitialise" la mémoire. Qu'est-ce que cela veut dire, "initialiser la mémoire" ?
Merci d'avance !


BOOM !
Laissez se propager l'onde de choc...

19 réponses

Hello !

Ecrire :
mon_type* X = (mon_type*) malloc(sizeof(mon_type));

n'est plus nécessaire depuis le C standard puisque celui-ci spécifie qu'un compilateur peut convertir un pointeur void* en un autre pointeur. Cependant, le code donné est plus portable puisqu'il fonctionne avec :
- un compilateur standard C,
- un compilateur non standard C,
- un compilateur non standard C qui déclare char* malloc(),
- un compilateur C++, cerise sur le gâteau ;)

Il est à noter qu'un compilateur C++ standard refuse une conversion de void* vers un pointeur typé.

A propos de la conversion de pointeurs, il ne faut pas en sous-estimer les dangers. Les conversions de pointeurs demandent beaucoup de prudence car un compilateur C ne fera aucun contrôle.

Exemple 1 : bug1.c

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

typedef struct t
{
int X[10];
} t;

t T0 = { { 9 } };

int main()
{
char* P1 = (char*) malloc(sizeof(char));
char* P2 = (char*) malloc(sizeof(char));

/* conversion incorrecte */
t* Q = P1;

printf("%d\n", *P1 = 1);
printf("%d\n", *P2 = 1);

*Q = T0; /* BUG */

printf("%d\n", *P1);
printf("%d\n", *P2);

free(P2);
free(P1);

return 0;
}

---
Dans cet exemple, on convertit un char* en t* ce qui entraîne une catastrophe au niveau de la mémoire...
---

Exemple 2 : bug2.c

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

int main()
{
char* Cp = (char*) 1;;
int* Ip = Cp;

printf("Cp = %p\n", Cp);
printf("Ip = %p\n", Ip);

printf("*Cp = %d\n", *Cp);
printf("*Ip = %d\n", *Ip);

return 0;
}

---
Dans cet exemple, on convertit un (char*) en (int*) ce qui provoque un problème d'alignement et de la même manière, la sanction ne se fait pas attendre...
---

En résumé, quand on fait une conversion de pointeur en pointeur, il faut se demander :
- si il n'y a pas une solution plus élégante et moins dangereuse,
- si le pointeur non typé (void*) est réellement convertible en un pointeur typé. Il se peut que le programme n'ait pas les éléments pour le déterminer.

C++ est beaucoup plus contraignant sur la question des conversions. Par exemple :

int main()
{
char(*P10) [10];
char(*P5) [5];

P5 = P10; // NOT OK => erreur de compilation

return 0;
}

// Dans cet exemple, le compilateur refuse de convertir un pointeur sur un tableau de char en un pointeur de chars uniquement parce que les tableaux n'ont pas la même taille.

Take care !
1
(person*) est un cast. Tu devrais retrouvé cela dans ton livre.

Sinon pour calloc, il initialise la mémoire, càd qu'il met à zéro les octets qu'il a alloué.
0
Onde2Choc Messages postés 299 Date d'inscription vendredi 6 août 2004 Statut Membre Dernière intervention 24 février 2006 4
30 août 2004 à 11:24
AAAaaah je comprends... On caste le pointeur pour qu'il pointe sur une structure de type person... Oki merci...
Quant à calloc, tu veux dire qu'il attribue à chaque octet la valeur 0 ?

BOOM !
Laissez se propager l'onde de choc...
0
oui, c'est ça. Il attribue à chaque octet la valeur 0.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Hello !

Les fonctions d'allocation mémoire du C retournent toutes un pointeur non typé (void*). Il te faut à chaque fois, le convertir en pointeur typé de la manière suivante :

mon_type* X = (mon_type*) malloc(sizeof(mon_type));

calloc alloue de la mémoire pour un tableau de n éléments qu'il initialise à 0. Exemple :

mon_type* A = (mon_type*) calloc(sizeof(mon_type), 10);
/* allocation pour 10 éléments mon_type */

Take care !
0
Mauvaise utilisation du cast. Quelque soit le type une adresse est une adresse. Le cast sert à convertir des types mais que quand cela engendre un dépassement mémoire.

exemple:

int x = 15;
char c;

c = (char)x;

Convertir un pointeur en pointeur est trivial.
0
Onde2Choc Messages postés 299 Date d'inscription vendredi 6 août 2004 Statut Membre Dernière intervention 24 février 2006 4
31 août 2004 à 08:38
Hum... Et est-ce qu'on peut caster une variable en pointeur ?


BOOM !
Laissez se propager l'onde de choc...
0
Oui on peut "caster" un char int etc en pointeur car en réalité un pointeur est équivalent à un unsigned int.
0
Onde2Choc Messages postés 299 Date d'inscription vendredi 6 août 2004 Statut Membre Dernière intervention 24 février 2006 4
1 sept. 2004 à 08:39
Le C++ est un langage chieur ! :-D Mais j'ai compris, j'éviterais la conversion de pointeurs...

BOOM !
Laissez se propager l'onde de choc...
0
Canard007 Messages postés 5929 Date d'inscription mercredi 26 mai 2004 Statut Contributeur Dernière intervention 18 septembre 2009 215
1 sept. 2004 à 10:18
Quel debat pour une simple alocation

COIN!
0
Onde2Choc Messages postés 299 Date d'inscription vendredi 6 août 2004 Statut Membre Dernière intervention 24 février 2006 4
1 sept. 2004 à 12:31
Ben, au début je pensait mettre ce post dans le café mais comme on n'y boit pas et que il y a de la prog dedans alors je l'ai mis ici...


BOOM !
Laissez se propager l'onde de choc...
0
Je dois avouer que Jolkdarr s'enflamme souvent quand ça cause C/C++.

;-)
0
Hello !

Bin, je m'enflammerais volontiers pour Ada 95 aussi, mais faut reconnaître qu'à moins de travailler pour les militaires ou les transports, ce langage n'a plus la cote.

Pour en revenir à C++, qui connait et utilise les pointeurs automatiques (auto_ptr<>) ?
0
Canard007 Messages postés 5929 Date d'inscription mercredi 26 mai 2004 Statut Contributeur Dernière intervention 18 septembre 2009 215
2 sept. 2004 à 10:36
J'ai bossé un peu pour les militaires ... et même chez eux sa tombe un peu un desuetude...^^

COIN!
0
Onde2Choc Messages postés 299 Date d'inscription vendredi 6 août 2004 Statut Membre Dernière intervention 24 février 2006 4
2 sept. 2004 à 08:14
Ada 95 fait quoi comme langage ? J'en ai entendu parler sans jamais en voir ni en lire...


BOOM !
Laissez se propager l'onde de choc...
0
Onde2Choc Messages postés 299 Date d'inscription vendredi 6 août 2004 Statut Membre Dernière intervention 24 février 2006 4
2 sept. 2004 à 13:52
Mais on peut faire quoi avec Ada95 ? En quoi est-ce que ce langage est spécialisé ?


BOOM !
Laissez se propager l'onde de choc...
0
Hello !

Ada 95 est un langage général comme C ou C++. Il prend en charge la mémoire (comme Java) et possède des mécanismes pour gérer le multitâches (type rendez-vous). Il est très utilisé pour les gros systèmes car très fiable et très sécurisé. Il existe des compilateurs gratuits (sur Linux : GNAT par exemple).

T'en a jamais vu ?
Tiens, un exemple, rien que pour toi :


generic
type T is private;
package gestion_de_liste is
-- type acces pour le chainage :
type noeud;
type acces_noeud is access Noeud;

-- type pour définir un noeud (élement d'une liste) :
type noeud is record
Suivant : Acces_noeud := null; -- acces au noeud suivant
Donnee : T; -- donnée utile
end record;

-- type pour définir un objet liste gérant une liste d'éléments de type T :
type Liste is record
Tete : acces_noeud := null;
Queue : acces_noeud := null;
Nombre_elements : natural := 0;
end record;

-- type pour accéder à un objet liste :
type acces_liste is access Liste;

-- exceptions :
liste_non_vide : exception;

-- constructeur/destructeur :
procedure creer_liste(Une_liste : out acces_liste);
procedure supprimer_liste(Une_liste : in out acces_liste);

-- gestion de la liste :
procedure inserer(Une_liste : in out acces_liste; Element : in T);
procedure extraire(Une_liste : in out acces_liste; Element : out T);
function est_vide(Une_liste : in acces_liste) return boolean;
end;

package body gestion_de_liste is
procedure creer_liste(Une_liste : out acces_liste) is
begin
Une_liste := new Liste;
end;

procedure supprimer_liste(Une_liste : in out acces_liste) is
begin
if Une_liste.Tete /= null then
-- raise liste_non_vide;
null;
end if;
Une_liste := null;
end;

procedure inserer(Une_liste : in out acces_liste; Element : in T) is
Nouveau_noeud : acces_noeud := new noeud'(Suivant => null, Donnee => Element);
begin
if Une_liste.Tete = null then
Une_liste.Tete := Nouveau_noeud;
Une_liste.Queue := Une_liste.Tete;
else
Une_liste.Queue.Suivant := Nouveau_noeud;
Une_liste.Queue := Nouveau_noeud;
end if;
Une_liste.Nombre_elements := Une_liste.Nombre_elements + 1;
end;

procedure extraire(Une_liste : in out acces_liste; Element : out T) is
begin
-- ### A COMPLETER
if Une_liste.Nombre_elements = 0 then
null;
else
Element := Une_liste.Queue.Donnee;
end if;
end;

function est_vide(Une_liste : in acces_liste) return boolean is
begin
return Une_liste.Nombre_elements = 0;
end;
end;

package exemple is
generic
type T is private;
procedure swap(V1, V2 : in out T);
end;

package body exemple is
procedure swap(V1, V2 : in out T) is
Temporaire : T := V1;
begin
V1 := V2;
V2 := Temporaire;
end swap;
end;

with text_io;
with exemple;
with gestion_de_liste;

procedure main is

X1 : integer := 1;
X2 : integer := 2;

procedure swap_integer is new Exemple.swap(integer);
package int_io is new text_io.integer_io(integer);

package liste_integer is new gestion_de_liste(integer);
package liste_float is new gestion_de_liste(float);

Une_liste_entiers : liste_integer.acces_liste;

begin

liste_integer.creer_liste(Une_liste_entiers);
liste_integer.inserer(Une_liste_entiers, 10);
liste_integer.supprimer_liste(Une_liste_entiers);

text_io.put("X1 = ");
int_io.put(X1);
Text_io.new_line;
text_io.put("X2 = ");
int_io.put(X2);
Text_io.new_line;

swap_integer(X1, X2);
text_io.put_line("SWAP");

text_io.put("X1 = ");
int_io.put(X1);
Text_io.new_line;
text_io.put("X2 = ");
int_io.put(X2);
Text_io.new_line;
end;
end package;
0
Manque plus que la mise en page pour la lisibilité du code.

;-)
0
blurk Messages postés 486 Date d'inscription vendredi 16 avril 2004 Statut Membre Dernière intervention 15 mars 2009 160
2 sept. 2004 à 20:10
new = (person*)malloc( sizeof(person));

Person étant le nom de la structure et new un pointeur vers le nouvel élément. Mais à quoi peut bien servir le (person*) devant malloc ? Jusqu'ici j'aurais procédé comme ça : new= malloc( sizeof(person));

c'est new le nom du pointeur sur structure. On dit aussi l'instance sur structure de type person (attention, new est un mot réservé pour le c++ et il est à éviter)
person c'est le type de la structure, et même le type de variable,
au même titre que char ou int.
ce n'est pas un cast, il n'est pas question d'attribuer le conternu d'une variable à une variable d'un autre type. (d'accord avec guki)
dans un malloc, on précise toujours l'instance et le type, c'est le strict minimum pour distinguer une variable de manière unique.
exemple "la voiture immatriculée 999 xxx 99" où voiture est le type et 999 xxx 99 est l'instance de type voiture, c'est à dire son nom.
Impossible de simplifier plus !

¤
0
Hello !

Les vieux "malloc" retournaient un (char*), donc il fallait convertir en (mon_type*). Avec le C standard, (void*) peut être converti en tout pointeur. Il n'est plus utile de convertir sauf que le code pert en portabilité.
0