7
votes

Memcpy, string et terminateur

Je dois écrire une fonction remplissant un tampon Char * pour une longueur assignée avec le contenu d'une chaîne. Si la corde est trop longue, je dois juste la couper. Le tampon n'est pas attribué par moi mais par l'utilisateur de ma fonction. J'ai essayé quelque chose comme ceci:

int writebuff(char* buffer, int length){
    string text="123456789012345";
    memcpy(buffer, text.c_str(),length);
    //buffer[length]='\0';
    return 1;
}


int main(){
    char* buffer = new char[10];
    writebuff(buffer,10);
    cout << "After: "<<buffer<<endl;
}


4 commentaires

Si vous utilisez C ++ Strings, utilisez une chaîne plutôt que de char * et utilisez la copie plutôt que MemCy


Si vous essayez d'écrire un fichier source multilingue, vous devez rester à partir de "C ++ isms": no std :: , no nouveau , non <<< / code> (Sauf peut-être peut-être si vous voulez dire que vous voulez dire Bitwise Shift), ...


Writebuff devrait faire ce qu'il est annoncé de faire. Si l'appelant attend un terminateur, alors WritBuff doit le fournir. Si l'appelant n'attend aucun terminateur, alors WritBuff ne doit pas le fournir. Dans ce cas particulier, l'appelant attend clairement un terminateur ( Opérateur << (ostream, char *) attend un terminateur).


Donc, c'est essentiellement strlcpy (3) ou je manque quelque chose?


10 Réponses :


0
votes

Il devrait être le plus défiant *, cela empêche les cordes trop longues que le tampon du tampon de la remplit complètement et de faire déborder plus tard lorsque son accès. Bien que iMo, strncpy doit être utilisé au lieu de Memcpy , mais vous devrez toujours le résilier NULL. (Votre exemple de votre exemple fuit).

* Si vous avez déjà un doute, allez la route la plus sûre!


0 commentaires

0
votes

Ma question concerne le terminateur: devrait-il être là ou non?

Oui. Ça devrait être là. Sinon, comment sauriez-vous plus tard où la chaîne se termine? Et comment cout saurait-il savoir? Il continuerait à imprimer des ordures jusqu'à ce qu'il rencontre une poubelle dont la valeur se trouve \ 0 . Votre programme pourrait même s'écraser.

comme Sidenote, votre programme fuit la mémoire. Cela ne libère pas la mémoire qu'il attribue. Mais puisque vous sortez du principal () , cela n'a pas beaucoup d'importance; Après tout, une fois que le programme se termine, toute la mémoire reviendrait au système d'exploitation, que vous l'iez ou non. Mais sa bonne pratique en général, si vous n'oubliez pas vous-même la mémoire (ni toute autre ressource) vous-même.


0 commentaires

10
votes

Une chaîne de style C doit être terminée avec un caractère zéro '\ 0' .

En plus, vous avez un autre problème avec votre code - cela peut essayer copier d'au-delà de la fin de votre chaîne source. C'est un comportement classique non défini. Il peut sembler que cela fonctionne, jusqu'à ce que la seule fois que la chaîne soit allouée à la fin d'un bloc de mémoire en tas et que la copie s'éteigne dans une zone de mémoire protégée et échoue de manière spectaculaire. Vous devez copier uniquement jusqu'au minimum de la longueur du tampon ou de la longueur de la chaîne.

P.s. Pour une exhaustivité, voici une bonne version de votre fonction. Merci à Naveen pour indiquer l'erreur obsolète dans votre terminaison nul. J'ai pris la liberté d'utiliser votre valeur de retour pour indiquer la longueur de la chaîne renvoyée ou le nombre de caractères requis si la longueur passée était <= 0. xxx


0 commentaires

0
votes

Si vous devriez ou non mettre fin à la chaîne avec un \ 0 dépend de la spécification de votre weblebuff fonction. Si ce que vous avez dans tampon doit être une chaîne de style C valide après avoir appelé votre fonction, vous devez le terminer avec un \ 0 . .

note, cependant, que c_str () se termine avec un \ 0 pour vous, donc vous pourrait utiliser . Taille () + 1 comme taille de la chaîne source. Notez également que si longueur est plus grand que la taille de la chaîne, vous copierez plus loin que ce que texte fournit avec votre code actuel (vous pouvez utiliser min (longueur - 2, Text.Size () + 1 / * Trailing \ 0 * /) Pour éviter cela, et définir la mémoire tampon [longueur - 1] = 0 pour le captiver). < / p>

Le tampon alloué dans Main est divulgué, BTW


0 commentaires

8
votes

Si vous souhaitez traiter le tampon comme une chaîne, vous devez le terminer null. Pour cela, vous devez copier longueur-1 caractères à l'aide de memcpy et définir le caractère longueur-1 comme \ 0 .


2 commentaires

Inversement, si vous ne voulez pas traiter le tampon comme une chaîne, vous ne devez pas la résilier Nul.


Il est correct de copier longueur au lieu de longueur-1 caractères et à moitié évite un bogue lorsque vous passez une longueur de tampon de 0 .



1
votes

Char * Les tampons doivent être résiliés NULL à moins que vous n'ayez expressément expressément la longueur avec elle partout et en disant que le tampon n'est pas terminé null.


0 commentaires

0
votes

Je suis d'accord avec Necrolis que Strncpy est la voie à suivre, mais il ne recevra pas le terminateur NULL si la chaîne est trop longue. Vous avez eu la bonne idée dans la mise en place d'un terminateur explicite, mais comme écrit votre code le pose un après la fin. (Ceci est en C, puisque vous sembliez faire plus de c que c ++?) XXX


0 commentaires

0
votes

Tout d'abord, je ne sais pas si écrivainbuff devrait terminer la chaîne ou non. C'est une question de conception, à répondre par la personne qui a décidé que Writbuff devrait exister du tout.

second, prenant votre exemple spécifique dans son ensemble, il y a deux problèmes. On est que vous transmettez une chaîne non définie à opérateur << (OStream, char *) . Deuxièmement, la ligne commentée écrit au-delà de la fin du tampon indiqué. Ces deux ont invoqué un comportement non défini.

(troisième est une faille de conception - pouvez-vous savoir que est toujours inférieur à la longueur du texte ? )

Essayez ceci: xxx


0 commentaires

2
votes

Il semble que vous utilisiez C ++ - étant donné que, l'approche la plus simple est (en supposant que la résiliation NUL soit requise par la spécification d'interface)

int writebuff(char* buffer, int length)
{
  string text = "123456789012345";
  std::fill_n(buffer, length, 0); // reset the entire buffer
  // use the built-in copy method from std::string, it will decide what's best.
  text.copy(buffer, length);
  // only over-write the last character if source is greater than length
  if (length < text.size())
    buffer[length-1] = 0;
  return 1; // eh?
}


0 commentaires

0
votes
  1. dans principale () , vous devriez Supprimer le tampon que vous avez attribué avec neuf. ou l'affecte statiquement ( Char buf [10] ). Oui, ce n'est que 10 octets et oui, c'est une mémoire "piscine", pas une fuite, car il s'agit d'une allocations ponctuelles et oui, vous avez besoin de cette mémoire pour toute la durée de fonctionnement du programme. Mais c'est toujours une bonne habitude d'être dans.

  2. en C / C ++ Le contrat général avec des tampons de caractères est qu'ils soient résolus, donc je l'inclurais à moins d'avoir été explicitement dit de ne pas le faire. Et si je l'ai fait, je le commenterais, et peut-être même utiliser un paramètre typlef ou nom sur le paramètre char * indiquant que le résultat est une chaîne qui n'est pas terminée null.


0 commentaires