1
votes

what (): basic_string :: _ M_construct null non valide

Je crée un programme dans lequel j'ai besoin d'utiliser une fonction qui stocke un jeton d'une chaîne dans un vecteur. La fonction ne fonctionnait pas correctement, j'ai donc essayé la fonction sur un programme plus petit. Bien sûr, j'ai utilisé la fonction de tokenizer de chaîne. Mais cela ne fonctionne pas comme prévu. Tout d'abord, voici le code:

cout<<"coming out";

Maintenant, les problèmes. Je pense que le problème a quelque chose à voir avec la commande:

(string)ptr

Cette chose fonctionne parfaitement dans le premier appel, mais donne une erreur lorsqu'elle est présente dans la boucle while. Si je le commente et imprime ptr, alors cela fonctionne bien, mais le programme se termine après la boucle while, et ne s'exécute même pas

#include <vector>
#include <string>
#include <cstring>
using namespace std;

int main()
{
    vector<string> v;
    string input = "My name is Aman Kumar";
    
    char* ptr = strtok((char*)input.c_str(), " ");
    v.push_back((string)ptr);

    while(ptr)
    {
        ptr = strtok(NULL," ");
        v.push_back((string)ptr);
    }
    cout<<"Coming out";
    for(string s:v)
    {
        cout<<s<<endl;
    }
}

laisse seul le contenu de le vecteur. Mais encore une fois, si je n'imprime pas trop ptr, alors le premier jeton "My" qui a été stocké dans le vecteur est imprimé. Je ne peux littéralement pas trouver ce qui cause cela. Toute suggestion serait utile.


5 commentaires

Il semble que vous invoquez un constructeur de chaîne avec un pointeur nul, ce qui n'est pas autorisé.


Est-ce que cela répond à votre question? Attribuer un nullptr à une std :: string est sûr?


char * ptr = strtok ((char *) input.c_str (), ""); cela pourrait être un problème. c_str () renvoie la chaîne const C et vous ne devez pas la modifier. Mais vous supprimez la constness avec (char *) input.c_str () et la passez à strtok . strtok modifie les chaînes. Cela provoque un comportement indéfini.


Vous n'êtes pas autorisé à modifier le résultat de input.c_str () . Utilisez les fonctions std :: string et au lieu de l'ancienne interface C.


La version courte et sûre: std :: istringstream stream (input); std :: copy (std :: istream_iterator (flux), std :: istream_iterator (), std :: back_inserter (v)); .


3 Réponses :


2
votes

Vous ne savez pas si ptr est nullptr avant d'essayer de créer une chaîne à partir de celui-ci (et d'appeler std :: string construtor avec nullptr est UB)

Vous devez réorganiser votre boucle, par exemple comme ceci:

char* ptr = strtok(input.data(), " ");

while(ptr)
{
    v.push_back(std::string(ptr));
    ptr = strtok(NULL," ");
}

En remarque, n'utilisez pas la syntaxe de conversion de style C en C ++. Il est très probable que cela cache des problèmes, et la syntaxe C ++ offre des alternatives beaucoup plus sûres.

Le rejet de constness et la modification du résultat sont UB en C ++, donc le premier cast peut être remplacé par un appel data (qui renvoie le pointeur vers non-const si nécessaire). Si vous n'avez pas C ++ 11, alors c'est UB de toute façon, car il n'était pas garanti que la chaîne stocke la mémoire en mémoire continue et vous devez utiliser différentes méthodes .


1 commentaires

Rejeter la constness n'est pas un problème (il serait impossible de s'interfacer avec beaucoup de code C autrement). Ce sont les modifications ultérieures qui provoquent un comportement indéfini.



4
votes

In

#include <vector>
#include <string>
#include <iostream>
#include <sstream>

int main()
{
    std::vector<std::string> v;
    std::string input = "My name is Aman Kumar";
    
    std::stringstream ss(input);
    
    std::string word;
    while(ss >> word)
    {
        v.push_back(word);
    }
    std::cout << "Coming out\n";
    for(std::string& s:v)
    {
        std::cout << s << "\n";
    }
}

Pour le dernier jeton ptr sera nul, la construction d'un std :: string à partir d'un pointeur nul n'est pas définie comportement. Essayez:

while(ptr = strtok(NULL," "))
{
    v.push_back(string(ptr));
}

Pour une solution plus C ++:

while(ptr)
{
    ptr = strtok(NULL," ");
    v.push_back((string)ptr);
}


3 commentaires

Merci beaucoup. Pouvez-vous me dire pourquoi dans la dernière boucle for vous avez utilisé string & au lieu de string? For loop a sûrement le même objet et pas un objet de copie, non?


@ProfessorofStupidity Le vecteur v est le même objet, mais la variable de boucle s fonctionne de la même manière que les autres variables.


@ProfessorofStupidity sans la référence, vous feriez une copie des chaînes dans le vecteur, ce qui n'est pas nécessaire



1
votes

Vous mélangez std :: string avec la fonction C-ish strtok . C'est vraiment une mauvaise idée. std :: string sont plus ou moins intervertibles avec const char * mais pas avec char * mutable . Je ne parle pas de la question du pointeur nul. Alors choisissez une méthode et respectez-la.

  1. C-ish one: construisez un tableau char simple et stockez les vecteurs de char * :

     std::stringstream fd(input);
     for(;;) {
         std::string ptr;
         fd >> ptr;
         if (! fd) break;
         v.push_back(ptr);
     }
    
     cout<<"Coming out";
     for(std::string s: v)
     {
         cout<<s<<endl;
     }
    
  2. C ++ un, utilisez un std :: stringstream :

     char *cstr = strdup(input.c_str());
     ptr = strtok(cstr, " ");
     while(ptr) {
         v.push_back(ptr);
         ptr = strtok(NULL, " ");
     }
    
     cout<<"Coming out";
     for(char *s:v)
     {
         cout<<s<<endl;
     }
    
     free(cstr);         // always free what has been allocated...
    


0 commentaires