Domanda

Ieri ho passato circa 4 ore a cercare di risolvere questo problema nel mio codice. Ho semplificato il problema nell'esempio seguente.

L'idea è di memorizzare una stringa in una stringa che termina con std :: End, quindi recuperarla in un secondo momento e confrontarla con la stringa originale.

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

int main( int argc, char** argv )
{
    const std::string HELLO( "hello" );

    std::stringstream testStream;

    testStream << HELLO << std::ends;

    std::string hi = testStream.str();

    if( HELLO == hi )
    {
        std::cout << HELLO << "==" << hi << std::endl;
    }

    return 0;
}

Come probabilmente intuirai, il codice sopra quando eseguito non stamperà nulla.

Anche se, se stampato o guardato nel debugger (VS2005), HELLO e hi sembrano identici, la loro .length () in realtà differisce di 1. Questo è ciò che suppongo stia causando il " == " operatore fallito.

La mia domanda è: perché. Non capisco perché std :: Ends è un carattere invisibile aggiunto alla stringa hi, che rende hi e HELLO lunghezze diverse anche se hanno un contenuto identico. Inoltre, questo personaggio invisibile non viene tagliato con il boost boost. Tuttavia, se si utilizza strcmp per confrontare .c_str () delle due stringhe, il confronto funziona correttamente.

Il motivo per cui ho usato std :: End in primo luogo è perché ho avuto problemi in passato con stringstream che conservava i dati inutili alla fine del flusso. std :: End l'ha risolto per me.

È stato utile?

Soluzione

std :: End inserisce un carattere null nello stream. Ottenere il contenuto come std :: string manterrà quel carattere nullo e creerà una stringa con quel carattere nullo nelle rispettive posizioni.

Quindi una stringa std :: può contenere caratteri null incorporati. I seguenti contenuti std :: string sono diversi:

ABC
ABC\0

Uno zero binario non è uno spazio bianco. Ma non è nemmeno stampabile, quindi non lo vedrai (a meno che il tuo terminale non lo visualizzi appositamente).

Il confronto con strcmp interpreterà il contenuto di un std :: string come una stringa C quando si passa .c_str () . Dirà

  

Hmm, i caratteri prima del primo \ 0 (terminando il carattere null) sono ABC , quindi presumo che la stringa sia ABC

E così, non vedrà alcuna differenza tra i due sopra. Probabilmente stai riscontrando questo problema:

std::stringstream s;
s << "hello";
s.seekp(0);
s << "b";
assert(s.str() == "b"); // will fail!

L'asserzione fallirà, perché la sequenza che utilizza lo stringstream è ancora quella precedente che contiene "ciao". Quello che hai fatto è solo sovrascrivere il primo personaggio. Vuoi fare questo:

std::stringstream s;
s << "hello";
s.str(""); // reset the sequence
s << "b";
assert(s.str() == "b"); // will succeed!

Leggi anche questa risposta: Come riutilizzare un ostringstream

Altri suggerimenti

std :: End è semplicemente un carattere nullo. Tradizionalmente, le stringhe in C e C ++ sono terminate con un carattere null (ascii 0), tuttavia risulta che std :: string non richiede davvero questa cosa. Ad ogni modo, per esaminare il tuo codice punto per punto vediamo alcune cose interessanti che accadono:

int main( int argc, char** argv )
{

La stringa " hello " letterale di stringa è una costante di stringa con terminazione zero tradizionale. Copiamo tutto questo nel std :: string CIAO.

    const std::string HELLO( "hello" );

    std::stringstream testStream;

Ora inseriamo la stringa CIAO (compreso lo 0 finale) nello stream , seguito da un secondo null che viene inserito dalla chiamata a std :: estremità .

    testStream << HELLO << std::ends;

Estraiamo una copia delle cose che inseriamo nel stream (la stringa letterale " hello " ;, più i due terminatori null).

    std::string hi = testStream.str();

Confrontiamo quindi le due stringhe utilizzando operator == nella classe std :: string . Questo operatore (probabilmente) confronta la lunghezza degli oggetti string , incluso il numero di caratteri null finali. Si noti che la classe std :: string non richiede che l'array di caratteri sottostante termini con un null finale - in altri termini, consente alla stringa di contenere caratteri null, quindi il primo dei due caratteri null finali è trattato come parte della stringa hi .

Poiché le due stringhe sono diverse nel numero di null finali, il confronto fallisce.

    if( HELLO == hi )
    {
        std::cout << HELLO << "==" << hi << std::endl;
    }

    return 0;
}
  

Anche se, se stampato, o guardato   nel debugger (VS2005), CIAO e ciao   sembrano identici, il loro .length () in   il fatto differisce di 1. Ecco cosa sono   indovinare sta causando il " == " operatore   fallire.

Essendo la ragione, la lunghezza è diversa per un carattere null finale.

  

La mia domanda è: perché. Io non   capire perché std :: End è un   carattere invisibile aggiunto alla stringa   ciao, rendendo ciao e CIAO diversi   lunghezze anche se hanno   contenuto identico. Inoltre, questo   il personaggio invisibile non ottiene   rifinito con rifinitura boost. Tuttavia, se   usi strcmp per confrontare .c_str () di   le due stringhe, il confronto funziona   correttamente.

strcmp è diverso da std :: string - è scritto da dietro all'inizio quando le stringhe erano terminate con un valore nullo - quindi quando arriva al primo trascinando null in hi smette di cercare.

  

Il motivo per cui ho usato std :: termina in   il primo posto è perché ho avuto problemi   in passato con stringstream   conservazione dei dati inutili alla fine di   il flusso. std :: End ha risolto questo problema per   me.

A volte è una buona idea capire la rappresentazione sottostante.

Stai aggiungendo un carattere NULL a HELLO con std :: End. Quando si inizializza hi con str () si rimuove il carattere NULL. Le stringhe sono diverse. strcmp non confronta std :: stringhe, confronta char * (è una funzione C).

std :: end aggiunge un terminatore nullo, (char) '\ 0'. Lo useresti con le classi strstream deprecate, per aggiungere il terminatore null.

Non è necessario con stringstream, e in effetti rovina le cose, perché il terminatore null non è lo speciale terminatore null che termina una stringa " stringstream, stringstream è solo un altro personaggio, il personaggio di zeroth. stringstream lo aggiunge e questo aumenta il numero di caratteri (nel tuo caso) a sette, e fa il confronto a "ciao". fallire.

Penso che avere un buon modo per confrontare le stringhe sia usare il metodo std :: find . Non mischiare i metodi C e std :: stringne !

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top