Czy std :: string zawiera terminator null?

87

Czy poniższy ciąg będzie zawierał terminator zerowy „\ 0”?

std::string temp = "hello whats up";

Dzięki! :)

pan
źródło
1
W tej chwili zaakceptowana odpowiedź od @jahhaj jest sprzeczna z odpowiedzią użytkownika529758, którego odpowiedź jest prawdopodobnie bardziej aktualna. Podczas lektury pominąłem komentarz Jessego Gooda, więc tutaj chcę podkreślić jego wagę.
Jonathan Komar

Odpowiedzi:

99

Nie, ale jeśli powiesz, że temp.c_str()w wyniku zwracanym z tej metody zostanie uwzględniony terminator zerowy.

Warto również powiedzieć, że możesz umieścić znak null w ciągu, tak jak każdy inny znak.

string s("hello");
cout << s.size() << ' ';
s[1] = '\0';
cout << s.size() << '\n';

wydruki

5 5

a nie 5 1tak, jak można by się spodziewać, gdyby znaki puste miały specjalne znaczenie dla łańcuchów.

jahhaj
źródło
5
Jeśli zadzwonisz, temp.c_str()znak null zostanie uwzględniony. Jeśli naprawdę potrzebujesz tego w ciągu, po prostu dodaj go jak każdy inny znak. temp.push_back('\0'). Teraz temp.c_str()będzie zawierać dwa znaki null.
jahhaj
1
@dupdupdup, jak wspomniały niektóre odpowiedzi, jeśli potrzebujesz ciągu zakończonego znakiem null, powinieneś wywołać s.c_str () na skonstruowanym obiekcie. Zwróci wskaźnik do tablicy znaków, która ma na końcu '\ 0'.
Maksim Skurydzin
@Rico, Jahhaj Jak w takim razie zakończyć ciąg. Na przykład - dodałem kilka znaków do mojego ciągu jako str [i]. Teraz nie mogę go wydrukować za pomocą cout.
Bhavuk Mathur
Aby dodać do twojego punktu: Ponieważ operator << jest przeciążony, cout << s, chociaż wydrukuje cały łańcuch char po znaku, ale jeśli weźmiesz c_str () i wstawisz do operatora <<, wydrukuje do null char. następujący program przedstawia ten punkt. {string s ("SampleString"); cout << s.size () << "\ t" << s << endl; s [3] = '\ 0'; cout << "\ n \ n After Null \ n \ n" << s.size () << "\ t" << s << endl; cout << "\ n \ n Biorąc c_str \ n \ n" << s.size () << "\ t" << s.c_str () << endl; }
Fooo
70

Nie w C ++ 03 i nie jest nawet gwarantowane przed C ++ 11, że w C ++ std :: string jest ciągła w pamięci. Tylko ciągi C (tablice char, które są przeznaczone do przechowywania ciągów) miały terminator zerowy.

W C ++ 11 i nowszych mystring.c_str()wersjach mystring.data()jest równoważne jest równoważne &mystring[0]i mystring[mystring.size()]gwarantuje, że będzie '\0'.

Quuxplusone
źródło
4
Dzięki C ++ 11 ciągi są teraz gwarantowane jako ciągłe w pamięci.
zneak
@zneak thanks! Zaktualizowano. Ale wątpię, czy istnieją jakiekolwiek kompilatory kompilujące C ++ 11, które przynajmniej w rozsądnym zakresie ... nawet GCC ma zepsute wsparcie dla tego.
4
@ H2CO3: Pomijając C ++ 11, problem ten został rozwiązany w DR 530 w 2005 roku . Zdecydowana większość implementacji bibliotek standardowych przechowuje dane łańcuchowe w ciągłej pamięci przez co najmniej tak długo.
ildjarn
3
Dziękuję @ildjarn, właśnie tego szukałem. Po części uzasadnieniem posunięcia było to, że nikt w komitecie nie wiedział o implementacji STL, która nie używa pamięci ciągłej.
zneak
7
@ H2CO3: Szczerze, jeśli cię to uraziło, potrzebujesz grubszej skóry.
ildjarn
8

Zależy to od Twojej definicji „zawiera”. W

std::string temp = "hello whats up";

jest kilka rzeczy, na które należy zwrócić uwagę:

  • temp.size()zwróci liczbę znaków od pierwszego hdo ostatniego p(łącznie)
  • Ale w tym samym czasie temp.c_str()lub temp.data()powróci z nullterminatorem
  • Innymi słowy, int(temp[temp.size()])będzie wynosić zero

Wiem, brzmię podobnie do niektórych odpowiedzi tutaj, ale chcę zwrócić uwagę, że sizeof std::stringin C++jest utrzymywane osobno i nie jest tak, jak w Cprzypadku liczenia, dopóki nie znajdziesz pierwszego nullterminatora.

Aby dodać, historia byłaby trochę inna, gdyby string literalzawierała osadzone \0. W tym przypadku konstrukcja std::stringzatrzymuje się na pierwszym nullznaku, jak poniżej:

std::string s1 = "ab\0\0cd";   // s1 contains "ab",       using string literal
std::string s2{"ab\0\0cd", 6}; // s2 contains "ab\0\0cd", using different ctr
std::string s3 = "ab\0\0cd"s;  // s3 contains "ab\0\0cd", using ""s operator

Bibliografia:

aniliitb10
źródło
2

Tak, jeśli zadzwonisz temp.c_str(), zwróci łańcuch c zakończony znakiem null.

Jednak rzeczywiste dane przechowywane w obiekcie tempmogą nie być zakończone znakiem null, ale nie ma to znaczenia i nie powinno mieć znaczenia dla programisty, ponieważ gdy programista tego chce const char*, wywołuje c_str()obiekt, który gwarantuje zwrócenie wartości null -terminated string.

Nawaz
źródło
1
Ani terminator zerowy (jeśli istnieje) nie zostanie uwzględniony w powrocie z temp.size().
jahhaj
1

W przypadku ciągów C ++ nie musisz się o to martwić i prawdopodobnie zależy to od implementacji.

Używając temp.c_str()otrzymasz reprezentację napisu w C, która z pewnością będzie zawierała \0znak. Poza tym tak naprawdę nie widzę, jak byłoby to przydatne w łańcuchu C ++

Naps62
źródło
1

std::stringwewnętrznie liczy liczbę znaków. Wewnętrznie działa przy użyciu tej liczby. Jak powiedzieli inni, kiedy potrzebujesz łańcucha do wyświetlenia lub z jakiegokolwiek powodu, możesz użyć jego c_str()metody, która da ci łańcuch z zakończeniem zerowym na końcu.

Nadczłowiek
źródło
Czy możesz podać jakieś odniesienia do tej instrukcji, "std :: string wewnętrznie przechowuje liczbę znaków. Wewnętrznie działa przy użyciu tej liczby"
rimalonfire