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.


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);

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();

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.


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.


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.


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();

9
int main () {

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

  cout<<str2; // output: 12

  return 0;
}

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

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.


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';

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.