2016-08-23 6 views
0

Je lis mon manuel et j'essaie de résoudre la question posée aux lecteurs.Quel est le problème avec strncpy_s() ici?

Le code de mise en jachère est la définition de fonction de mon fichier source de ma réponse.

Je souhaite copier le contenu des chaînes de caractères vers d'autres chaînes.

J'ai choisi les fonctions strncpy_s().

Mais cela ne fonctionne pas. Microsoft Visual Studio indique que l'assertion de débogage a échoué!

Je n'ai aucune idée de comment le réparer.

cow.h

// déclarations de classe

#include <iostream> 
#ifndef COW_H_ 
#define COW_H_ 

class Cow { 
char name[20]; 
char * hobby; 
double weight; 
public: 
Cow(); 
Cow(const char * nm, const char * ho, double wt); 
Cow(const Cow & c); 
~Cow(); 
Cow & operator=(const Cow & c); 
void ShowCow() const; // display all cow data 
}; 
#endif 

de cow.cpp

// méthodes de classe

Cow::Cow(const char * nm, const char * ho, double wt) 
{ 
    int len = std::strlen(nm); 
    strncpy_s(name, len, nm, len); 
    name[19] = '\0'; 

    len = std::strlen(ho); 
    hobby = new char[len + 1]; 
    strncpy_s(hobby, len, ho, len); 
    hobby[len] = '\0'; 

    weight = wt; 
} 

Cow::Cow() 
{ 
    strncpy_s(name, 19, "no name", 19); 
    name[19] = '\0'; 

    int len = std::strlen("no hobby"); 
    hobby = new char[len + 1]; 
    strncpy_s(hobby, len, "no hobby", len); 
    hobby[len] = '\0'; 

    weight = 0.0; 
} 

Cow::Cow(const Cow & c) 
{ 
    int len = std::strlen(c.name); 
    strncpy_s(name, len, c.name, len); 
    name[19] = '\0'; 

    len = std::strlen(c.hobby); 
    hobby = new char[len + 1]; 
    strncpy_s(hobby, len, c.hobby, len); 
    hobby[len] = '\0'; 

    weight = c.weight; 
} 

Cow::~Cow() 
{ 
    delete [] hobby; 
} 

Cow & Cow::operator=(const Cow & c) 
{ 
    if (this == &c) 
     return * this; 

    delete [] hobby; 

    int len = std::strlen(c.name); 
    strncpy_s(name, len, c.name, len); 
    name[19] = '\0'; 

    len = std::strlen(c.hobby); 
    hobby = new char[len + 1]; 
    strncpy_s(hobby, len, c.hobby, len); 
    hobby[len] = '\0'; 

    weight = c.weight; 
    return * this; 
} 

void Cow::ShowCow() const 
{ 
    cout << name << ", " << hobby << ", " << weight << endl; 
} 

usecow.cpp

#include <iostream> 
    #include "cow.h" 


    int main() 
    { 
     Cow Japan; 
     Japan.ShowCow(); 

     Cow America("Aspen", "Swim", 307.45); 
     America.ShowCow(); 

     return 0; 
    } 
+0

Veuillez ajouter du code lorsque vous utilisez votre classe 'Cow'. – Ari0nhh

+0

Avez-vous vérifié les paramètres que vous avez passés avec ce que le manuel dit sont nécessaires? Dans un endroit, vous ne passez que les paramètres '3', mais dans un autre endroit, vous passez les paramètres' 4' à 'strncpy_s'. – Galik

+0

@ Ari0nhh Oui, j'ajoute usecow.cpp tout à l'heure. – user9418

Répondre

3

De strncpy_sdocumentation:

Ces fonctions tentent de copier les premiers caractères D de strSource à strDest, où D est le moindre de comptage et la longueur de strSource. Si ces caractères D s'inscrivent dans strDest (dont la taille est numberOfElements) et laissent toujours la place à un terminateur null, alors ces caractères sont copiés et une valeur nulle est ajoutée; Sinon, strDest [0] est défini sur le caractère nul et le gestionnaire de paramètres non valide est appelé, comme décrit dans la section Validation de paramètre.

Lets considèrent votre code:

int len = std::strlen("no hobby"); 
hobby = new char[len + 1]; 
strncpy_s(hobby, len, "no hobby", len); 

deuxième argument de strcpy_s est une taille de tampon en caractères. Quatrième - nombre de caractères copiés. Puisque vous passez la même variable len, strcpy_s détecte que ce tampon a une taille insuffisante (car il doit y avoir un espace pour le \ 0 final) et appelle un gestionnaire de paramètres invalide. Cela fonctionne correctement:

int len = std::strlen("no hobby"); 
hobby = new char[len + 1]; 
strncpy_s(hobby, len+1, "no hobby", len); 

Vérifiez d'autres endroits où vous utilisez strncpy_s pour cette erreur. Il est également conseillé de lire le texte dans les fenêtres d'assertion de débogage.Dans cette source d'erreur de cas est assez simple:

debug assertion failed

+0

Enfin, ce projet fonctionne. Ça me passe quelques jours. soupir – user9418

+0

Je veux ajouter une question que la fenêtre d'assertion de débogage n'informe pas les utilisateurs quelle ligne où (L "Buffer est trop petit" && 0) arrive. – user9418

+0

@ user9418 C'est le cas. Appuyez sur le bouton «Réessayer» lorsque le débogueur est attaché et il vous montrera la ligne avec une erreur. – Ari0nhh

0
int len = std::strlen(nm); 
strncpy_s(name, len, nm, len); 

En premier lieu, la deuxième ligne devrait utiliser len + 1 au lieu de len. Et en second lieu, il devrait utiliser strcpy au lieu de strncpy_s. Le calcul de la longueur de la source (strlen(nm)) ne fournit aucune information sur la taille du tampon cible (name). Et comme il n'y a aucune information sur la taille du tampon cible, restreindre le nombre de caractères à copier n'a aucun sens. Donc, ne faites pas tout ce qui tourne. Il suffit de copier la chaîne:

strcpy(name, nm); 
+0

Oui, à la fois strcpy() et strncpy() sont enseignées par mon manuel. Mais j'utilise Visual Studio pour écrire du code. Visual Studio dit qu'ils sont dangereux. Donc, je choisis strncpy(). Je voudrais quand même vous remercier pour votre temps. – user9418

+0

L'utilisation de 'strncpy_s' dans l'exemple de code est également" dangereuse ", exactement comme le ferait' strcpy'. C'est le problème avec à peu près toutes les utilisations de 'strncpy' que j'ai vues sur SO: c'est mal utilisé, parce que celui qui a écrit le code ne pensait pas assez au problème qu'il essayait de résoudre, et choisissait simplement une fonction parce qu'il était étiqueté "sûr". C'est sur "sûr" s'il est utilisé correctement. –

+0

Merci à vous. En fait, je prends des petits pas dans la direction de C++. Vos mots m'encouragent beaucoup. – user9418