C - Malloc et memcpy (gestion de la mémoire)
Je suis un peu novice en C et je vais avoir du mal à comprendre comment la mémoire fonctionne, notamment intégré des fonctions comme memcpy
.
Voici un struct
je suis en utilisant
struct data_t {
int datasize;
void *data;
};
Et voici une fonction auxiliaire que je suis de l'utiliser avec:
struct data_t *data_create(int size)
{
struct data_t *dt=malloc(sizeof(struct data_t)+size);
dt->datasize=size;
dt->data="1234567890a";
return dt;
}
Maintenant dans le main
fonction je n'ai aucun problème à faire cela:
struct data_t *data = data_create(1024);
data->data="123456a";//just an example
Mais cela jette un Seg Fault:
memcpy(data->data,"123456a",strlen("1234567890a")+1);
Ma question est pourquoi? Et comment puis-je l'éviter?
Veuillez garder à l'esprit que je suis novice en C alors comment C traite de la mémoire est un peu nouveau pour moi
Merci.
Edit: Ça fonctionne! Je vous remercie beaucoup. Complètement raté le pointeur de données. Maintenant tout fonctionne bien selon valgrind.
OriginalL'auteur PTdude | 2011-10-08
Vous devez vous connecter pour publier un commentaire.
memcpy(data->data,"123456a",strlen("1234567890a")+1);
échoue parce que
data->data
unvoid *
type de points de certains déchets/adresse non valide qui n'est pas allouée.data
a l'adresse de la chaîne littérale qui est stocké dans le readonly section (comme dans le.rodata
de l'exécutable et chargé dans la mémoire, ce qui n'est pas accessible en écriture. Aussi, si vous n'avez pas céder une chaîne de caractères de l'adresse du pointeur de variable, alors il faudrait tenir des invalides/ordures de la valeur de l'adresse ce qui n'est pas attribué ou initialisé avec certains valide permis emplacement. Alors d'abord allouer de la mémoire tampon.La
malloc
sera de retour la première adresse de l'emplacement d'un bloc d'adresse de atleastsize * sizeof (char)
octets. Vous pouvez maintenant copiersize
octets à cet emplacement mémoire pointé pardata->data
.N'oubliez pas de libérer la mémoire allouée bloquer lorsque vous avez fini de travailler avec cette mémoire bock avec la
free (addr)
appel.Je vois que vous avez tenté d'attribuer
data
tampon avec une manière bien étrange (?):pour laquelle supplémentaires alloués
size
octets avec lastruct data_t
. Mais qu'est-ce déjà le cas,data
composant encore des points à un endroit qui ne peut pas être modifié.Veuillez utiliser:
gratuit premier à faire:
puis
oui, le demandeur a alloué un peu plus d'espace lors du début de l'affectation, il doit avoir initialisé au point. Je préfère encore l'appel explicite, si il n'y a pas besoin d'allouer à la fois.
cela vous donnera une erreur : "invalid conversion from ‘void*’ to ‘data_t*’ [-fpermissive]" pour résoudre "vous devez convertir explicitement le pointeur retourné par malloc".
Vous avez raison, mais c'est en C++. La question a été marqué C, pour lequel une conversion explicite n'est pas nécessaire. Voir C99 Section 6.3.2.3 Paragraphe 1. Alors qu'en C++, il n'est pas clairement mentionné (ou je ne suis pas au courant).
OriginalL'auteur phoxis
Votre première erreur est: est-ce
Cela va créer un morceau de la mémoire de la taille de la structure data_t + taille. Je pense que ce que vous attendiez, votre champ de données à l'intérieur de data_t pourrait utiliser cette mémoire, mais il ne peut pas parce que les données ne sont pas titulaires d'une adresse de ce mémoire.
Votre deuxième erreur a été de supposer que vous en cas de copie la valeur de la chaîne suivante dans "données":
Ce qui en fait, s'est passé ici est qu'il existe une chaîne de caractères en mémoire "123456a" qui existe pour l'ensemble de la durée de vie de votre programme. Lorsque vous affectez "123456a" data->données de ce qui se passe réellement est que vous prenez l'adresse de cette chaîne "123456a" et de le mettre dans le data->data vous n'êtes pas de la copie de la valeur ("123456a"), mais le lieu ou l'adresse (0x23822...) de "123456a" .
Votre dernière erreur était:
Vous avez essayé de copier la valeur "123456a" dans la mémoire pointé par les données. Qu'est-ce que les données de pointage? Elle est pointée en lecture seule zone de mémoire contenant vos précédemment affecté à la chaîne "123456a". En d'autres mots, vous avez dit à votre programme d'écrire à l'adresse de "123456a".
Voici un programme que va faire ce que vous attendez:
OriginalL'auteur megazord
Avis
void *data
est un pointeur,data_create
, vous n'avez pas à allouer de l'espace pour cela, vous venez de faire le point sur une constante de chaîne"1234567890a"
qui est en lecture seule.Dans
main
, vous créez une autre chaîne de caractères constante"123456a"
, puis vous faitesvoid *data
point de la chaîne constante, qui est en lecture seule.Ainsi, lorsque vous appelez
memcpy
à écrire à l'adresse mémoire qui n'est pas accessible en écriture(ou sans initialisé), vous avez eu une erreur.OriginalL'auteur lostyzd
de données->data est un pointeur. Et ce pointeur point de nulle part. Avant de faire memcpy vous devez allouer de l'espace et des données->données de point sur cet espace.
et puis memcpy ne manquera pas tant que données->data != NULL
faire
data->data = "123"
est ok, parce que "123" est attribuée au moment de la compilation, de sorte que les données->points de données au début de la chaîne "123", mais en l'appelant
memcpy(data->data,"123",4)
sera un échec, car pointeur vers les données-les données sont non initialisée et de pointer du doigt un endroit aléatoire dans la mémoire qui ne peut pas être lu.memcpy
est encore invalide, il s'essaie à copier plusieurs octets à partir de la source de la source, ce qui est le cas ici.Oui, il y a deux erreurs dans son code
OriginalL'auteur Luka Rahne