Usuń ostatni znak z ciągu C ++

210

Jak mogę usunąć ostatni znak z ciągu C ++?

Próbowałem st = substr(st.length()-1);Ale to nie zadziałało.

skazhy
źródło
6
Czy chcesz nowy ciąg z usuniętym ostatnim znakiem lub ten sam ciąg bez ostatniego znaku?
Matthieu M.
Dla MFC Visual C ++ CString: CString str=CString("Hello world"); str.Delete(str.GetLength()-1);
sergiol

Odpowiedzi:

193

W przypadku wersji niemutującej:

st = myString.substr(0, myString.size()-1);
Matthieu M.
źródło
20
@MatthieuM. Twój przykład jest mylący, myślę, że istotą pytania jest modyfikacja oryginalnego ciągu, w twoim przykładzie nie modyfikujesz oryginalnego ciągu, ponieważ w twoim przykładzie oryginalny ciąg nazywa się „myString”, co powoduje zamieszanie, w pytaniu jest to „st”. Kod powinien być: st = st.substr(0, st.size()-1). Ale to nadal nie wygląda we właściwy sposób, myślę, że właściwym sposobem jest użycie funkcji, który jest przeznaczony do tego zadania, to się nazywa erase (), a kod jest: st.erase(st.size()-1). Nazywa się to „wersją mutującą”.
Czarek Tomczak
1
@CzarekTomczak: Rozumiem, że nie jest to dokładnie to, o co poproszono, dlatego wyłączenie odpowiedzialności przed samą istotą.
Matthieu M.
2
@MattPhillips: jego rozwiązanie jest jednak specyficzne dla C ++ 11 ( pop_backnie istniało w C ++ 03) i jest to również modyfikacja na miejscu (a OP nigdy nie wyjaśnił, czy chce na miejscu, czy nie) ... as takie, że ma się poprawną odpowiedź, ale nie jest to możliwe tylko jeden.
Matthieu M.,
404

Proste rozwiązanie, jeśli używasz C ++ 11. Prawdopodobnie również czas O (1):

st.pop_back();
mpgaillard
źródło
49
to jest dla c ++ 11!
Amir
1
Jako FYI - jest obsługiwany tylko z GCC 4.7 (oczywiście wraz z przełącznikiem kompilacji -std = c ++ 11)
Shmil The Cat
20
Nie zapomnij sprawdzić length().
Tak, wydaje się, że jest za daleko na stronie ...!
James Bedford
1
The behavior is undefined if the string is empty. od tutaj
Raffi
24
if (str.size () > 0)  str.resize (str.size () - 1);

Alternatywa std :: erase jest dobra, ale podoba mi się „- 1” (niezależnie od tego, czy jest to rozmiar, czy iterator końcowy) - pomaga mi wyrazić zamiar.

BTW - Czy naprawdę nie ma std :: string :: pop_back? - wydaje się dziwny.

Steve314
źródło
11
Nie ma std::string::pop_backw C ++ 03; został jednak dodany w C ++ 0x.
James McNellis
Ok dzięki. Spowodowało to trochę zamieszania - mógłbym przysiąc, że go użyłem, ale go nie ma. Może mam gdzieś niestandardową bibliotekę w jakimś kompilatorze (między VC ++ 2003, VC ++ 2008, MinGW GCC3 MinGW GCC 4 i Linux GCC 4, masz kilka różnic). Bardziej prawdopodobne jest, że mylę się z innymi typami.
Steve314
resize () prawdopodobnie nie jest przeznaczony do takiego zastosowania, jest to funkcja związana z pamięcią, erase () służy do usuwania znaków.
Czarek Tomczak
3
@Czarek Tomczak - przepraszam za absurdalnie spóźnioną odpowiedź, ale resizejest to funkcja zmiany rozmiaru i nie jest już funkcją pamięci, niż cokolwiek innego, co mogłoby zwiększyć potrzebną pamięć. Na przykład, jeśli masz resizemniejszy rozmiar, nie zmniejszy to zarezerwowanej pamięci. Myślę, że myślisz o tym reserve, co najmniej może zmniejszyć przydzieloną pamięć, jeśli zostaniesz o to poproszony - zobacz tutaj zmień rozmiar i zarezerwuj tutaj .
Steve314,
3
if (! str.empty ()) jest
lepszy
19
buf.erase(buf.size() - 1);

Zakłada się, że wiesz, że ciąg nie jest pusty. Jeśli tak, otrzymasz out_of_rangewyjątek.

RC.
źródło
8
buf [buf.size () - 1] = '\ 0'; niczego nie usuwa - po prostu zmienia znak, który miał tam wartość zero. std:; łańcuchy mogą szczęśliwie zawierać takie znaki.
Neil ma rację. Prawdopodobnie powinienem to wyjaśnić w mojej odpowiedzi. Druga opcja skutecznie zmieni wartość ostatniego znaku, więc nie będzie drukowany, ale długość łańcucha pozostanie taka sama. Użycie kasowania faktycznie „usuwa” ostatni znak i zmieni rozmiar łańcucha.
RC.
@RC Zostanie wydrukowane, zakładając, że używasz czegoś takiego jak cout << buf. To, jak będzie wyglądać, zależy od twojej platformy. Zawsze możesz to wyjaśnić, edytując odpowiedź.
Co jest znacznie lepszego size() w porównaniu end()z inną odpowiedzią?
ribamar
17

str.erase( str.end()-1 )

Odniesienie: prototyp std :: string :: erase () 2

nie wymaga c ++ 11 lub c ++ 0x.

ribamar
źródło
1
Może to prowadzić do dziwnej sytuacji: rozmiar łańcucha został zmniejszony, ale ostatni znak nie jest ustawiony na „\ 0”.
Deqing
1
@ Deqing, czy możesz podać więcej szczegółów na temat tego, co dzieje się w takim przypadku?
ribamar
Na przykład, jeśli string s("abc");po erase wydaje robocza: cout<<s; // prints "ab"jednak ostatni znak jest nadal istnieje: cout<<s[2]; // still prints 'c'.
Deqing
1
łatwo naprawić: juststr[str.length()-1] = 0; str.erase(str.end()-1);
taxilian
5
@Dequing: twój przykład jest nieprawidłowy. Kasowanie zmniejsza rozmiar ciągu, więc dostęp do niego s[2]jest nielegalny.
EML
11

To wszystko, czego potrzebujesz:

#include <string>  //string::pop_back & string::empty

if (!st.empty())
    st.pop_back();
jcrv
źródło
9
int main () {

  string str1="123";
  string str2 = str1.substr (0,str1.length()-1);

  cout<<str2; // output: 12

  return 0;
}
kodaddict
źródło
2

Dzięki C ++ 11 nie potrzebujesz nawet długości / rozmiaru. Dopóki łańcuch nie jest pusty, możesz wykonać następujące czynności:

if (!st.empty())
  st.erase(std::prev(st.end())); // Erase element referred to by iterator one
                                 // before the end
Michael Goldshteyn
źródło
2

str.erase(str.begin() + str.size() - 1)

str.erase(str.rbegin())nie kompiluje się niestety, ponieważ reverse_iteratornie można go przekonwertować na normal_iterator.

C ++ 11 jest twoim przyjacielem w tym przypadku.

Zebra
źródło
Ta metoda ma również problem, ostatni znak nie jest ustawiony na „\ 0”.
Deqing
1
Czy jest jakiś konkretny powód, aby tego nie robić str.erase(str.end() - 1)?
vallentin
-4

Jeśli długość nie jest równa zero, możesz również

str[str.length() - 1] = '\0';
Jan Glaser
źródło
4
Ustawienie ostatniego znaku na \0nie zmienia długości łańcucha. str.length()będzie niedokładny.
jww
Tak, teraz to widzę. Rozważamy C ++. Masz rację, to nie zmienia długości sznurka
Jan Glaser