• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

C++ napisy const char* vs const char[] vs std::string

Object Storage Arubacloud
0 głosów
2,454 wizyt
pytanie zadane 16 grudnia 2020 w C i C++ przez Zaqu93 Gaduła (4,850 p.)

Witam, ostatnimi czasy zainteresowałem się cpp dzisiaj na tapet wziąłem łańcuchy wiem że istnieje możliwość zadeklarowania łańcucha poprzez const char*, const char [] oraz std::string. Czym różnią się te sposoby oprócz wielkości zadeklarowanej pamięci na zmienną oraz tym że std::string ma łatwiejsze metody na manipulowanie napisem? 

//const char*
const char* charString = "Abc";
std::cout << "Char ptr string: " << charString << " " << sizeof(charString) << "\n";

//const char []
const char charArrString [] = "Abc";
std::cout << "Char array string: " << charArrString << " " << sizeof(charArrString) << "\n";

//std::string
std::string cppString = "Abc";
std::cout << "C++ string: " << cppString << " " << sizeof(cppString) << "\n";

Wybaczcie, że zadaje takie pewnie banalne pytanie ale nie rozumiem za bardzo różnic.

4 odpowiedzi

+2 głosów
odpowiedź 16 grudnia 2020 przez j23 Mędrzec (194,920 p.)
  • Pierwszy sposób to definicja wskaźnika wskazującego na literał znakowy.
  • Drugi - definicja tablicy znaków, do której skopiowany literał znakowy (IMO bez sensu z tym const).
  • Trzeci - podejście obiektowe. cppString jest obiektem klasy std::string, która jest odpowiedzialna za zarządzanie pamięcią. W twoim przykładzie nie jest const, więc zawartości tego obiektu możesz dowolnie zmieniać.
0 głosów
odpowiedź 17 grudnia 2020 przez Ronie Użytkownik (780 p.)

Trzecia definicja to użycie konstruktora klasy string. string(const * cstr).

Jest to konstruktor którego, argumentem jest wskaźnik do C-stringu.

Powstaje dzięki niemu obiekt klasy string.

W pierwszym przypadku tworzysz stały wskaźnik wskazujący na stałą znakową będącą C-stringiem, dlatego wymagany jest const, ponieważ kompilator traktuje C-string jako const char[n].

komentarz 17 grudnia 2020 przez tkz Nałogowiec (42,000 p.)
Ale co "tu"?
komentarz 17 grudnia 2020 przez NewEraOfPeace Gaduła (4,790 p.)

  gdzie mogę znaleźć o tym więcej informacji? 

 

1) Narrow multibyte string literal. The type of an unprefixed string literal is const char[N], where N is the size of the string in code units of the execution narrow encoding, including the null terminator.

Attempting to modify a string literal results in undefined behavior: they may be stored in read-only storage (such as .rodata) or combined with other string literals:  

const char* pc = "Hello";
char* p = const_cast<char*>(pc);
p[0] = 'M'; // undefined behavior

 

String literals are not convertible or assignable to non-const CharT*. An explicit cast (e.g. const_cast) must be used if such conversion is wanted.  

komentarz 17 grudnia 2020 przez tkz Nałogowiec (42,000 p.)
Nie miałem na myśli rzutowania, ani żadnych operacji na tym ciągu. Sam zapis. Dlaczego const przy char* jest wymagany?

W sumie już nieważne. https://stackoverflow.com/questions/1524356/c-deprecated-conversion-from-string-constant-to-char Różnice pomiędzy C i C++.
komentarz 17 grudnia 2020 przez NewEraOfPeace Gaduła (4,790 p.)

No tak, w docsach jest napisane:

String literals are convertible and assignable to non-const char* or wchar_t* in order to be compatible with C, where string literals are of types char[N] and wchar_t[N]. Such implicit conversion is deprecated.

(until C++11)

String literals are not convertible or assignable to non-const CharT*. An explicit cast (e.g. const_cast) must be used if such conversion is wanted.

(since C++11)
komentarz 17 grudnia 2020 przez Ronie Użytkownik (780 p.)
edycja 18 grudnia 2020 przez Ronie

@tkz,

Dodatkowo, const char* jest zmiennym wskaźnikiem do niezmiennego ciągu. 

 

 

Tak, zgadza się, jest to wskaźnik do wskazywania na stałą a nie stały wskaźnik, przepraszam za brak precyzji.

0 głosów
odpowiedź 17 grudnia 2020 przez NewEraOfPeace Gaduła (4,790 p.)

Warto jeszcze nadmienić, że w przypadku wskaźnika nie masz żadnego wymiaru. Masz po prostu wskaźnik na pierwszy element (choć niekoniecznie, może pointować np. w środek lub na koniec, z tego tez powodu wyrażenie typu ptr[-5] może istnieć). Gdybyś zrobił na nim sizeof to uzyskasz rozmiar wskaźnika pod danym systemem.

W przypadku tablicy (drugi sposób) masz wymiarowość. sizeof na charArrString zwróci Ci 4, ponieważ tablica ma 4 elementy ('A', 'b', 'c' oraz niejawnie dodawane do literałów znakowych '\0'). Po takiej tablicy można normalnie przeiterować. std::begin, std::end lub std::size zwracją poprawne wyniki dla typu tablicowego, dla wskaźnika (tego co wyżej) nie.


Warto przeanalizować ten kod:
 

#include <iostream>

void foo(char* str){
    std::cout<<"Type: "<<typeid(str).name()<<'\n';
    std::cout<<"Size: "<<sizeof(str)<<" "<<'\n';
}

int main(){
    char arr[] = "Hejka"; // const char[6] przekopiowany do char[6]
    std::cout<<"Type: "<<typeid(arr).name()<<'\n';
    std::cout<<"Size: "<<sizeof(arr)<<" "<<'\n';
    foo(arr);
}

I jego wyjście:

Type: A6_c (zdemanglowane przez c++filt: char [6])
Size: 6
Type: Pc (zdemanglowane przez c++filt: char*)
Size: 8

Następuje tu niejawny "rozpad" (konwersja) typu tablicowego do wskaźnika.

0 głosów
odpowiedź 17 grudnia 2020 przez profesorek96 Szeryf (91,420 p.)
edycja 17 grudnia 2020 przez profesorek96

Zacznijmy od tego że const char * jest to literał znakowy (string z języka C). Raz zadeklarowany string w ten sposób jest nie zmienny.

const char * a="ala ma kota";
cout<<a[0]; //OK
a[0]='A'; //Nie ok

Pragnę zwrócić uwagę że do elementów można dostać się jak by to była tablica znaków. Możesz wypisać element o indexie 0 zaś zmienić elementu pod żadnym z indexów nie wolno.

Każdy napis zgodny z standardem języka C musi mieć na końcu znak końca napisu tak zwany NULL zwany inaczej \0.

Weźmy teraz ten sam przypadek co poprzednio ale dla tablicy znaków.

char b[12]="ala ma kota"; // rozmiar tablicy to długość napisu +1
cout<<b[0];//OK
b[0]='A';//OK

Deklarujemy tablicę która będzie zawierać nasz napis. Zwróć uwagę że rozmiar tablicy to 12 elementów, napis "Ala ma kota" ma długość 11. Dzieję się tak dlatego że każdy poprawny napis w języku C musi zawierać znak końca napisu, wspomniany NULL, stawiamy go na końcu dlatego jest plus jedna komórka. 

std::string to nic innego jak połączenie tych dwóch koncepcji plus świata obiektowego. Jest to klasa należąca do standardowej przestrzeni nazw, została wprowadzona w języku C++. Klasa ta pozwala w łatwy sposób operować na napisach, ma przeciążone operatory [] dlatego pozwala odwoływać się do stworzonego obiektu jak by to była tablica. Dodatkowo umożliwia konkatenację stringów (łączenie) za pomocą operatora + oraz +=. Przeciążone zostąły również operatory << jak i >> co pozwala na łatwe wprowadzanie danych jak i wypisywanie zawartości stringa na ekran.

std::string a="Ala ma kota";
cout<<a.size()<<endl; //wypisuje długość napisu
cout<<a<<endl;//wypisuje napis;
cout<<a[0]<<endl;//wypisuje element o indexie 0
a[0]='A';//zmienia element o indexie 0

Klasa string posiada wiele metod, między innym metodę size która zwraca długość napisu. Ciekawostką jest że ze względów historycznych klasa string posiada zarówno metodę size jak i length, obydwie zwracają długość napisu.

Polecam zapoznać się z dokumentacją klasy:

https://en.cppreference.com/w/cpp/string/basic_string

1
komentarz 17 grudnia 2020 przez NewEraOfPeace Gaduła (4,790 p.)

Zacznijmy od tego że char * jest to literał znakowy

Nie, char* to wskaźnik na typ znakowy :d

Podobne pytania

0 głosów
1 odpowiedź 1,149 wizyt
pytanie zadane 13 października 2018 w C i C++ przez jegor377 Stary wyjadacz (13,230 p.)
–2 głosów
1 odpowiedź 469 wizyt
pytanie zadane 22 sierpnia 2019 w C i C++ przez niezalogowany
0 głosów
2 odpowiedzi 555 wizyt

92,624 zapytań

141,482 odpowiedzi

319,822 komentarzy

62,005 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...