web-dev-qa-db-fra.com

Comment copier une chaîne dans un tableau de caractères en C++ sans passer par le tampon

Je veux copier une chaîne dans un tableau de caractères et ne pas surcharger le tampon.

Donc, si j'ai un tableau de caractères de taille 5, je souhaite y copier au maximum 5 octets d'une chaîne.

quel est le code pour le faire?

20
neuromancer

Tout d’abord, strncpy est presque certainement pas ce que vous voulez. strncpy a été conçu dans un but assez spécifique. C’est dans la bibliothèque standard presque exclusivement parce qu’elle existe déjà, pas parce que c’est généralement utile.

La manière la plus simple de faire ce que vous voulez est probablement:

sprintf(buffer, "%.4s", your_string.c_str());

Contrairement à strncpy, cela garantit que le résultat sera terminé, mais ne remplira pas de données supplémentaires dans la cible si la source est plus courte que celle spécifiée (bien que cette dernière ne soit pas un problème majeur lorsque la longueur cible est 5).

19
Jerry Coffin

C'est exactement ce que fait la fonction de copie de std::string.

#include <string>
#include <iostream>

int main()
{

    char test[5];
    std::string str( "Hello, world" );

    str.copy(test, 5);

    std::cout.write(test, 5);
    std::cout.put('\n');

    return 0;
}

Si vous avez besoin d'une terminaison nulle, vous devriez faire quelque chose comme ceci:

str.copy(test, 4);
test[4] = '\0';
37
CB Bailey

Utilisez la fonction strlcpylien brisé et matériel non trouvé sur le site de destination si votre implémentation en fournit un (la fonction ne se trouve pas dans la bibliothèque standard C), il est cependant plutôt largement accepté comme nom standard de facto pour une fonction de copie de longueur limitée "sûre" pour les chaînes terminées à zéro.

Si votre implémentation ne fournit pas la fonction strlcpy, implémentez-en une vous-même. Par exemple, quelque chose comme ceci pourrait fonctionner pour vous

char *my_strlcpy(char *dst, const char *src, size_t n)
{
  assert(dst != NULL && src != NULL);

  if (n > 0)
  {
    char *pd;
    const char *ps;

    for (--n, pd = dst, ps = src; n > 0 && *ps != '\0'; --n, ++pd, ++ps)
      *pd = *ps;

    *pd = '\0';
  }

  return dst;
}

(En fait, le strlcpy accepté de facto renvoie size_t, vous préférerez peut-être donc mettre en oeuvre la spécification acceptée au lieu de ce que j'ai fait ci-dessus).

Méfiez-vous des réponses qui recommandent d'utiliser strncpy à cette fin. strncpy n'est pas une fonction de copie de chaîne de longueur limitée sécurisée et n'est pas censée être utilisée à cette fin. Bien que vous puissiez forcer strncpy à "travailler" à cette fin, cela revient à enfoncer des vis à bois avec un marteau.

7
AnT

Certaines versions de Nice libc fournissent un remplacement non standard mais excellent pour strcpy(3)/strncpy(3) - strlcpy(3) .

Si le vôtre ne le fait pas, le code source est librement disponible ici à partir du répertoire OpenBSD .

3
Nikolai Fetissov

Mise à jour: Je pensais que je tenterais de relier certaines des réponses, réponses qui m'ont convaincue que ma propre réponse stridente initiale était mauvaise. 

Tout d’abord, comme AndreyT l’a noté dans les commentaires sur cette question, les méthodes de troncature (snprintf, strlcpy et strncpy) ne sont souvent pas une bonne solution. Il est souvent préférable de vérifier la taille de la chaîne string.size() par rapport à la longueur du tampon et de renvoyer/renvoyer une erreur ou de redimensionner le tampon.

Si la situation est correcte dans votre cas, à mon humble avis, strlcpy est la meilleure solution, car il s’agit de la méthode la plus rapide/la moins coûteuse qui garantit la suppression des valeurs nulles. Malheureusement, ce n'est pas dans beaucoup/toutes les distributions standard et n'est donc pas portable. Si vous en faites beaucoup, cela vaut peut-être la peine de fournir votre propre implémentation, AndreyT a donné un exemple . Il s'exécute en O (longueur du résultat). La spécification de référence renvoie également le nombre d'octets copiés, ce qui peut aider à détecter si la source a été tronquée.

Les autres solutions intéressantes sont sprintf et snprintf . Ils sont standard, et sont donc portables et fournissent un résultat sûr avec une terminaison nulle. Ils ont plus de travail que strlcpy (analyse du spécificateur de chaîne de format et de la liste d'arguments variables), mais vous ne remarquerez probablement pas la différence à moins d'en faire beaucoup. Il s'exécute également en O (longueur du résultat). snprintf est toujours sûr et que sprintf risque de déborder si le spécificateur de format est incorrect (comme d'autres l'ont noté, la chaîne de format doit être "%.<N>s" et non "%<N>s"). Ces méthodes renvoient également le nombre d'octets copiés.

Une solution spéciale est strncpy . Il s'exécute en O (longueur du tampon), car s'il atteint la fin du src, il met à zéro le reste du tampon. Utile uniquement si vous devez mettre à zéro l'extrémité de la mémoire tampon ou si vous êtes sûr que les longueurs de chaîne source et de destination sont identiques Notez également que cela n’est pas sûr car cela ne met pas nécessairement la chaîne à zéro. Si la source est tronquée, alors null ne sera pas ajouté. Appelez donc en séquence avec une affectation null pour assurer une terminaison nulle: strncpy(buffer, str.c_str(), BUFFER_LAST); buffer[BUFFER_LAST] = '\0';

3
academicRobot
void stringChange(string var){

    char strArray[100];
    strcpy(strArray, var.c_str()); 

}

Je suppose que cela devrait fonctionner. il va copier la chaîne de formulaire dans un tableau de caractères.

2
Sunil
std::string str = "Your string";
char buffer[5];
strncpy(buffer, str.c_str(), sizeof(buffer)); 
buffer[sizeof(buffer)-1] = '\0';

La dernière ligne est obligatoire car strncpy n'est pas garanti pour terminer la chaîne (il y a eu une discussion sur la motivation hier).

Si vous utilisiez des chaînes larges, plutôt que sizeof(buffer), vous utiliseriez sizeof(buffer)/sizeof(*buffer) ou, mieux encore, une macro telle que

#define ARRSIZE(arr)    (sizeof(arr)/sizeof(*(arr)))
/* ... */
buffer[ARRSIZE(buffer)-1]='\0';
0
Matteo Italia

je pense que snprintf () est beaucoup plus sûr et simple

snprintf ( buffer, 100, "The half of %d is %d", 60, 60/2 );

le caractère nul est l'ajouter automatiquement et la fin :)

0
Dark Corp
char mystring[101]; // a 100 character string plus terminator
char *any_input;
any_input = "Example";
iterate = 0;
while ( any_input[iterate] != '\0' && iterate < 100) {
    mystring[iterate] = any_input[iterate];
    iterate++;
}
mystring[iterate] = '\0';

C'est la conception efficace de base. 

0
user922475
std::string my_string("something");
char* my_char_array = new char[5];
strncpy(my_char_array, my_string.c_str(), 4);
my_char_array[4] = '\0'; // my_char_array contains "some"

Avec strncpy , vous pouvez copier au maximum n caractères de la source à la destination. Cependant, notez que si la chaîne source a une longueur maximale de n caractères, la destination ne sera pas terminée avec la valeur null; vous devez y mettre vous-même le caractère nul final.

Un tableau de caractères d'une longueur de 5 peut contenir au plus une chaîne de 4 caractères, car le 5ème doit être le caractère nul final. Par conséquent, dans le code ci-dessus, n = 4.

0
Péter Török