Newbie questions sur malloc et sizeof

Quelqu’un peut-il m’expliquer pourquoi mon appel à malloc avec une chaîne de taille 6 renvoie une taille de 4 octets? En fait, tout argument entier que je donne à malloc me donne une taille de 4. Ensuite, j’essaie de copier deux chaînes. Pourquoi ma sortie de la chaîne copiée (NULL)? Voici mon code:

int main() { char * str = "ssortingng"; char * copy = malloc(sizeof(str) + 1); printf("bytes allocated for copy: %d\n", sizeof(copy)); while(*str != '\0'){ *copy = *str; str++; copy++; } copy = '\0'; printf("%s\n", copy); } 

sizeof(str) renvoie la taille d’un pointeur de type char* . Ce que vous devriez faire est de malloc la taille de la chaîne elle-même:

 char * copy = malloc(strlen(str) + 1); 

En outre, ces lignes:

 while(*str != '\0'){ *copy = *str; str++; copy++; } copy = '\0'; 

Peut être facilement réécrit en C comme ceci:

 while(*copy++ = *str++); 

Vous devez d’abord comprendre que sizeof (xxx), où xxx est une expression de valeur gauche (une variable) est toujours équivalente à do sizeof ( type de xxx ). Par conséquent, ce que fait réellement votre tailleof (str) renvoie la taille d’un caractère *, c’est-à-dire la taille de tout autre pointeur. Sur une architecture 32 bits, vous aurez 4, sur une architecture 64 bits, ce sera 8, etc.

Ainsi, comme d’autres l’ont également expliqué, vous devez connaître la longueur de la chaîne que vous souhaitez allouer, puis ajoutez 1 pour stocker le terminal \ 0, que C utilise implicitement pour le placer à la fin des chaînes.

Mais pour faire ce que vous voulez (copier une chaîne et allouer l’espace nécessaire) il sera plus simple et plus efficace d’utiliser strdup , c’est exactement ce qu’il faut: un malloc et une strcopy .

N’oubliez pas non plus de libérer de l’espace que vous avez alloué (à l’aide de malloc, calloc, strdup ou de toute autre fonction d’allocation). En C, elle ne disparaîtra pas lorsque la variable allouée sortira de sa scope Il restra utilisé jusqu’à la fin du programme. C’est ce que vous appelez une fuite de mémoire.

 #include  /* for strdup, strlen */ #include  /* for printf */ int main() { char * str = "ssortingng"; char * copy = strdup(str); printf("bytes at least allocated for copy: %d\n", strlen(copy)+1); printf("%s\n", copy); free(copy); } 

Un dernier point: j’ai changé le message en octets au moins alloué parce que vous ne connaissez pas vraiment la taille allouée lorsque vous appelez malloc. Il alloue assez souvent un peu plus d’espace que ce que vous avez demandé. Une des raisons est que dans de nombreux gestionnaires de mémoire, les blocs libres sont liés entre eux en utilisant une structure de données cachée et que tout bloc alloué doit pouvoir contenir au moins une telle structure. Une autre raison est que les blocs alloués sont toujours alignés de manière à être compatibles avec tout type. alignement.

J’espère que cela vous aidera à comprendre un peu mieux C.

Vous obtenez la taille du pointeur str (4 octets), pas ce à quoi il pointe?

sizeof(str) renvoie l’espace nécessaire pour stocker le pointeur sur la chaîne, pas la chaîne elle-même. Vous pouvez voir la taille de la chaîne avec strlen(str) par exemple.

Ensuite, vous affectez votre pointeur de copy à un entier qui a la valeur 0 (le caractère '\0' ). C’est la même chose que copy = NULL , ce que la fonction printf () vous montre.

Pour répondre à vos deuxièmes questions, en exécutant l’instruction copy++ vous avez modifié la valeur de copy (c’est-à-dire l’adresse en mémoire qui contient un tableau de caractères) de manière à ce que, au moment de l’imprimer, il pointe vers la fin de l’écran. tableau plutôt que le début (la valeur renvoyée par malloc() ). Vous aurez besoin d’une variable supplémentaire pour mettre à jour la chaîne et pouvoir accéder au début de la chaîne:

Modifier pour réparer le problème malloc/sizeof – merci CL.

 char * str = "ssortingng"; /* char * copy = malloc(sizeof(str) + 1); Oops */ char * copy = malloc(strlen(str) + 1); char * original_copy = copy; printf("bytes allocated for copy: %d\n", sizeof(copy)); while(*str != '\0'){ *copy = *str; str++; copy++; } copy = '\0'; printf("%s\n", original_copy); 

sizeof () renvoie la taille du type réel de la variable. Ainsi, lorsque vous définissez votre type en tant que char *, il renvoie la taille d’un pointeur.

Mais si vous faites de votre variable un tableau, sizeof renverra la taille du tableau lui-même, ce qui ferait ce que vous voulez faire:

 char *ptr = "moo to you"; char arr[] = "moo to you"; assert(sizeof(ptr) == 4); // assuming 32 bit assert(sizeof(arr) == 11); // sizeof array includes terminating NUL assert(strlen(arr) == 10); // strlen does not include terminating NUL 
  • sizeof () vous renvoie la taille du pointeur et non la quantité d’octets alloués. Vous n’avez pas besoin de compter les octets alloués, vérifiez simplement si le pointeur renvoyé n’est pas NULL .
  • La ligne copy = '\0' ; réinitialise le pointeur et le rend NULL .

Vous pouvez utiliser:

size_t malloc_usable_size (void * ptr);

au lieu de: sizeof

Mais il retourne la taille réelle du bloc de mémoire alloué! Pas la taille que vous avez passée à malloc!