11
votes

Newbie Questions sur Malloc et Tailleof

Quelqu'un peut-il m'expliquer pourquoi mon appel à malloc avec une taille de chaîne de 6 retourne une taille de 4 octets? En fait, tout argument entier que je donne à Malloc, je reçois une taille de 4. Suivant, j'essaie de copier deux chaînes. Pourquoi mon iPut de la chaîne copiée (NULL)? Voici mon code:

int main()
{
    char * str = "string";
    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);
}


1 commentaires

Copy = '\ 0' devrait être * copier = '\ 0'


8 Réponses :


3
votes

Vous obtenez la taille du pointeur STR (4 octets), pas de quoi il pointe?


2 commentaires

Pourquoi la marque d'interrogation? Vous ne savez pas de votre réponse;) C'est le bon. :)


Pas vraiment. La taille de ce qu'elle pointe (c'est-à-dire caractère ) est de 1, ce qui est encore moins utile. Vous avez besoin de la longueur de la corde comme dans la réponse de @ Arak.



18
votes

Tailleof (Str) code> renvoie la taille d'un pointeur de type char * code>. Ce que vous devriez faire, c'est à MALLOC code> la taille de la chaîne IT SOTE:

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


9 commentaires

Ils peuvent également être réécrites comme Strcpy (copie, str); qui est probablement plus efficace que ce que vous avez.


@Chris oups. J'ai réinventé la roue :)


@Arak: D'accord. Un idiome assez commun en c


@Ed - Je ne dirais pas le commun (pas dans les temps modernes, du moins) mais c'est définitivement largement connu.


Pour l'assurance-santé, il convient de mentionner que cela fonctionne que cela fonctionne parce que les caractères sont un octet, et donc Strlen (Str) donne le Nombre d'octets Le texte nécessite (que vous en ajoutez aussi pour que vous puissiez vous adapter à la Terminator NULL). N'oubliez pas que MALLOC (..) prend la taille (en octets) de l'espace alloué en tas dont vous avez besoin comme un argument.


Le code Idiom commun peut également être facile de se tromper. Je remplacerais l'instruction vide ';' null avec un {} ou, meilleur encore, un continuer; instruction. Et oui, @lutz, Strcpy () est probablement plus efficace et plus lisible.


Steve McConnell (code complet) a utilisé cet exemple très (Orignally de K & R) en tant que code difficile à lire.


Copy = '\ 0' devrait être * copier = '\ 0'


Comme @paranoidCoder suggère, * copy = '\ 0'; est nécessaire pour corriger cette bonne réponse à la autre chose.



3
votes

Tailleof (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 strallen (str) par exemple.

alors vous affectez votre pointeur copier sur un entier qui a la valeur 0 (le caractère '\ 0' ). C'est la même chose que copy = null , qui est ce que la fonction printf () vous montre.


0 commentaires

1
votes

Pour résoudre vos deuxièmes questions, en exécutant la déclaration copie ++ code> Vous avez modifié la valeur de copier code> (c'est-à-dire l'adresse de la mémoire contenant un Code> Array) Pour que, au moment où vous l'imprimez, il pointe à la fin de la matrice plutôt que le début (la valeur renvoyée par malloc () code>). Vous aurez besoin d'une variable supplémentaire pour mettre à jour la chaîne et forte> être capable d'accéder au début de la chaîne:

Modifier strong> pour réparer malloc / taille> code > Problème - Merci CL. P>

char * str = "string";
/*   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);


3 commentaires

Il y a toujours un problème avec malloc (taille de (str) + 1) - Tailleof (STR) est Tailleof (Char *) est 4 sur la plupart plates-formes, et n'est pas liée à la longueur de la chaîne.


Ah! J'avais oublié que depuis que j'ai incrémenté le pointeur Printf imprimait le caractère null que j'ai ajouté à la fin et non la chaîne entière. Merci beaucoup.


Copy = '\ 0' devrait être * copier = '\ 0'



1
votes

Tailleforme () renvoie la taille du type réel de la variable. Donc, lorsque vous définissez votre type comme Char *, il renvoie la taille d'un pointeur.

Mais si vous avez modifié votre variable, Tailleof retournerait la taille de la matrice elle-même, ce qui ferait ce que vous voulez faire: xxx


1 commentaires

Vous devriez inclure Assert (Strlen (PTR) == 10); pour la symétrie et l'exhaustivité.



1
votes
  • Taillef () vous retourne 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 retourné n'est pas null .
  • la ligne copie = '\ 0' ; Réinitialise le pointeur et le fait null .

2 commentaires

Le pointeur a été incrémenté à ce moment-là, alors cela ne fait que faire le dernier octet du point de cordon à NULL?


@unknown - non, vous avez laissé l'opérateur de déséroférences. Ce que vous voulez, c'est * copy = '\ 0' car copy = '\ 0' définit le pointeur sur '\ 0' (qui est null en tant que type int ).



4
votes

Tout d'abord, vous devriez comprendre que TAILLEOF (xxx) où XXX est une expression de valeur gauche (une variable) est toujours équivalente à faire Taillef ( type de xxx ). Par conséquent, qu'est-ce qui fait vraiment votre Tailleof (Str) renvoie la taille d'un char *, c'est la taille de tout autre pointeur. Sur une architecture de 32 bits, vous obtiendrez 4, sur une architecture de 64 bits, ce sera 8, etc.

Donc, comme d'autres ont également expliqué que vous devez connaître la longueur de la chaîne que vous souhaitez attribuer, puis ajouter 1 pour stocker le terminal \ 0, C Utilisez implicitement pour mettre à la fin des chaînes.

mais pour faire ce que vous voulez (copiez une chaîne et allouez l'espace nécessaire), il sera plus simple et plus efficace pour Utilisez STRUP , qui fait exactement que: un malloc et un strculy .

Vous ne devez pas non plus oublier d'espace libre Vous vous êtes alloué (utilisant MALLOC, CALOC, STDUP ou toute autre fonction d'allocation). En C, il ne va pas disparaître lorsque la variable allouée est hors de portée. Il restera utilisé jusqu'à la fin du programme. C'est ce que vous appelez une fuite de mémoire. xxx

un dernier point: j'ai changé de message sur octets au moins alloué parce que vous ne connaissez pas vraiment le Taille allouée lorsque vous appelez MALLOC. Il alloue souvent souvent un espace clarquement plus que ce que vous avez demandé. Une des raisons est que, dans de nombreux gestionnaires de mémoire, les blocs libres sont liés ensemble à l'aide de certaines structures de données cachées et tout bloc attribué doit pouvoir contenir au moins une telle structure, une autre est que les blocs alloués sont toujours alignés de manière à être compatible avec n'importe quel type. Alignement.

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


2 commentaires

Pour ce que ça vaut, STRUP () est une fonction non standard, mais il est si trivialement facile de rouler votre propre que ce n'est pas une grosse affaire.


Oui, vous avez raison, il n'est pas standard avec C, même C99, mais très courant (et vous obtenez _strdup, _wcsdup et d'autres autres dans ISO C ++). D'autre part, la mise en œuvre de la bibliothèque est généralement assez optimisée pas si triviale qu'il semble. J'ai vérifié avec GCC sur Linux STDUP si environ 30% plus rapide qu'une boucle de temps et de près de 8% plus rapide que la deuxième meilleure solution que je puisse penser (Malloc puis Strncpy). C'est aussi plus facile à lire. Le grand inconvénient est que MALLOC est caché, d'où les programmeurs oublient souvent libérer les vars STRDUPED. :-(



-1
votes

Vous pouvez utiliser:

taille_t malloc_usable_size (vide * PTR);

au lieu de: taille de

mais il renvoie la taille réelle du bloc de mémoire alloué! Pas la taille que vous avez transmise à malloc!


1 commentaires

En plus, veuillez arrêter de suggérer des modifications qui défape réponses comme celle-ci: Stackoverflow.com/review/suggested-edits/3830819. Lorsque vous avez la possibilité de commenter, laissez un commentaire si vous êtes en désaccord avec les réponses, mais n'essayez pas de les réécrire vous-même.