Jak dołączyć znak do std :: string?

175

Następujący błąd kończy się niepowodzeniem prog.cpp:5:13: error: invalid conversion from ‘char’ to ‘const char*’

int main()
{
  char d = 'd';
  std::string y("Hello worl");
  y.append(d); // Line 5 - this fails
  std::cout << y;
  return 0;
}

Spróbowałem również poniższego, który kompiluje się, ale zachowuje się losowo w czasie wykonywania:

int main()
{
  char d[1] = { 'd' };
  std::string y("Hello worl");
  y.append(d);
  std::cout << y;
  return 0;
}

Przepraszam za to głupie pytanie, ale przeszukałem google, zobaczyłem tylko „tablica znaków do tablicy znaków ptr”, „tablica znaków do tablicy znaków” itp.

drowneath
źródło
błąd kompilatora tak ... Zapomniałem o błędzie, ale jest rozsądny.
drowneath
3
Poniżej masz lepsze odpowiedzi, ale możesz sprawić, że drugi przykład będzie działał jak ten char d [2] = {'d', 0}; lub po prostu char d [2] = "d"; Zasadniczo potrzebujesz 0, aby zakończyć ciąg w stylu c, który przekazujesz, aby dołączyć
sbk
Dobra dokumentacja tutaj: sgi.com/tech/stl/basic_string.html
Martin York

Odpowiedzi:

225
y += d;

Użyłbym +=operatora zamiast nazwanych funkcji.

AraK
źródło
2
dlaczego uważasz, że + = lepsze niż push_back? Czy to po prostu mniej pisania, czy masz inny powód?
Glen,
4
To mniej pisania. W gcc, basic_string::operator+=to tylko wezwanie push_back.
Eduffy
2
Jest to bardziej naturalne IMO dla strun. push_back to funkcja kontenera, a ciąg znaków jest wyspecjalizowany w STL :)
AraK
6
Odwróćmy to pytanie: dlaczego uważasz, że push_back jest lepsze niż + =? Moim zdaniem + = jest jasne i zwięzłe.
Jesper
34
Chcesz być ostrożny, ponieważ jeśli nabędziesz przyzwyczajenia, kompilacja będzie dobrze, jeśli yjest to char*zamiast std::string. Dodałby dznaki do wskaźnika y.
Zan Lynx,
65

Zastosowanie push_back():

std::string y("Hello worl");
y.push_back('d')
std::cout << y;
Ferdinand Beyer
źródło
19

Aby dodać znak do zmiennej std :: string przy użyciu metody append, musisz użyć tego przeciążenia:

std::string::append(size_type _Count, char _Ch)

Edycja: Masz rację Źle zrozumiałem parametr size_type, wyświetlany w pomocy kontekstowej. To jest liczba znaków do dodania. Więc prawidłowe połączenie to

s.append(1, d);

nie

s.append(sizeof(char), d);

Lub najprościej:

s += d;
Patrice Bernassola
źródło
Myślę, że użycie sizeof nie jest tutaj semantycznie poprawne (chociaż zdarza się, że działa, ponieważ sizeof (char) jest zawsze jeden). Metoda dołączania jest oczywiście bardziej użyteczna, jeśli chcesz dołączyć więcej kopii tego samego znaku !!!!!!!!!!
UncleBens
1
Dlaczego używasz sizeof(char)zamiast 1? Chcesz dodać dokładnie jedno powtórzenie d, więc powiedz to. Używanie sizeoftutaj jest mylące, ponieważ sugeruje, że należy podać appendrozmiar bajtu używanego typu danych (co nie ma miejsca).
Ferdinand Beyer
Jak powiedział Unclebens, metoda dołączania jest naprawdę bardziej użyteczna przy wielokrotnym dodawaniu tego samego znaku.
Patrice Bernassola
10

Oprócz innych wymienionych konstruktorów, jeden z konstruktorów łańcuchów przyjmuje znak i liczbę powtórzeń tego znaku. Możesz więc użyć tego do dołączenia pojedynczego znaku.

std::string s = "hell";
s += std::string(1, 'o');
Brian R. Bondy
źródło
7

Testuję kilka propozycji, uruchamiając je w dużej pętli. Użyłem Microsoft Visual Studio 2015 jako kompilatora, a mój procesor to i7, 8Hz, 2GHz.

    long start = clock();
    int a = 0;
    //100000000
    std::string ret;
    for (int i = 0; i < 60000000; i++)
    {
        ret.append(1, ' ');
        //ret += ' ';
        //ret.push_back(' ');
        //ret.insert(ret.end(), 1, ' ');
        //ret.resize(ret.size() + 1, ' ');
    }
    long stop = clock();
    long test = stop - start;
    return 0;

Zgodnie z tym testem wyniki są następujące:

     operation             time(ms)            note
------------------------------------------------------------------------
append                     66015
+=                         67328      1.02 time slower than 'append'
resize                     83867      1.27 time slower than 'append'
push_back & insert         90000      more than 1.36 time slower than 'append'

Wniosek

+= wydaje się bardziej zrozumiałe, ale jeśli myślisz o szybkości, użyj dołączania

Hugo Zevetel
źródło
Aby taka odpowiedź miała znaczenie, powinieneś przynajmniej powiedzieć, jakiego kompilatora używasz, ponieważ takie rzeczy mogą się bardzo różnić. Opowiadanie o procesorze też może być świetne, aby uzyskać przybliżone oszacowanie rzeczywistego wpływu, jaki może to mieć.
akaltar
Użyłem Visual Studio 2015. Poszukam gcc, żeby zrobić kilka innych testów. Mój procesor to i7, 8 serc, 2,20 GHz ... Ale niezależnie od tego, jaki jest mój procesor, nie będzie to miało wpływu na implementację std :: string ... chyba że niektóre z tych metod są wielowątkowe, a inne nie.
Hugo Zevetel
Czasami ma to wpływ, zwłaszcza jeśli wyświetlasz czasy w milisekundach. Zamiast tego możesz pokazać w procentach w stosunku do najszybszej metody (więc rzeczywista prędkość procesora nie ma znaczenia) Przenieś również te dane z komentarza do odpowiedzi, to tylko ogólna etykieta StackExchange. W przeciwnym razie miła odpowiedź.
akaltar
6

Spróbować + = operatora związek tekst , do dołączania () w tekst łącza lub push_back () w tekst łącza

Linki w tym poście zawierają również przykłady korzystania z odpowiednich interfejsów API.

Michael Berg
źródło
2

problem z:

std::string y("Hello worl");
y.push_back('d')
std::cout << y;

polega na tym, że musisz mieć „d”, a nie nazwę znaku, jak char d = „d”; A może się mylę?

Alex Spencer
źródło
Po prostu spróbowałem i zadziałało dobrze. Mam char c = 'd'i mogę obejść się y.push_back(c)bez problemu. Nie ma więc problemu z std::string::push_back()(poza tym, że jest dłuższy niż +=).
Franklin Yu
1
int main()
{
  char d = 'd';
  std::string y("Hello worl");

  y += d;
  y.push_back(d);
  y.append(1, d); //appending the character 1 time
  y.insert(y.end(), 1, d); //appending the character 1 time
  y.resize(y.size()+1, d); //appending the character 1 time
  y += std::string(1, d); //appending the character 1 time
}

Należy zauważyć, że we wszystkich tych przykładach mogłeś stosować znak literalny bezpośrednio: y += 'd';.

Twój drugi przykład prawie by zadziałał z niepowiązanych powodów. char d[1] = { 'd'};nie działa, ale char d[2] = { 'd'};(uwaga tablica jest rozmiar dwa) byłby pracował w przybliżeniu taka sama jak const char* d = "d";i ciągiem znaków mogą być dołączone: y.append(d);.

Mooing Duck
źródło
1

Spróbuj użyć d jako wskaźnika y.append (* d)

Bez drugiej
źródło
Jest to niebezpieczne, ponieważ pojedynczy charnie jest łańcuchem i nie ma terminatora zerowego. Takie postępowanie powoduje niezdefiniowane zachowanie.
Simon Kraemer
To jest po prostu złe. *doznacza wskaźnik usuwania referencji, dktóry jest błędem składniowym, ponieważ dnie jest wskaźnikiem.
Franklin Yu
0
str.append(10u,'d'); //appends character d 10 times

Zauważ, że napisałem 10u, a nie 10, ile razy chciałbym dodać znak; zastąp 10 dowolną liczbą.

Ioan Stef
źródło
0

Znalazłem prosty sposób ... Musiałem założyć charsznur, który był budowany w locie. Potrzebowałem, char list;ponieważ dawałem użytkownikowi wybór i użyłem tego wyboru w switch()oświadczeniu.

Po prostu dodałem kolejny std::string Slist;i ustawiłem nowy ciąg na równy znakowi, "liście" - a, b, c lub cokolwiek wybierze użytkownik końcowy, w ten sposób:

char list;
std::string cmd, state[], Slist;
Slist = list; //set this string to the chosen char;
cmd = Slist + state[x] + "whatever";
system(cmd.c_str());

Złożoność może być fajna, ale prostota jest fajniejsza. moim zdaniem

Charles H.
źródło
0

Dodanie również opcji wstawiania, o czym jeszcze nie wspomniano.

std::string str("Hello World");
char ch;

str.push_back(ch);  //ch is the character to be added
OR
str.append(sizeof(ch),ch);
OR
str.insert(str.length(),sizeof(ch),ch) //not mentioned above
Gopesh Bharadwaj
źródło
-1

Jeśli używasz push_back, nie ma wywołania konstruktora ciągu. W przeciwnym razie utworzy obiekt łańcuchowy poprzez rzutowanie, a następnie doda znak w tym ciągu do innego ciągu. Za dużo kłopotu dla malutkiej postaci;)

progician
źródło
1
operator + = (char c); jest przeciążony dla ciągów. W rzeczywistości konstruktor napisów nie akceptuje jednego znaku, patrz odpowiedź Briana;)
AraK