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

C/C++ wskaźnik na char (char*)

Aruba Cloud VPS - 50% taniej przez 3 miesiące!
0 głosów
1,323 wizyt
pytanie zadane 5 stycznia 2018 w C i C++ przez Jakub 0 Pasjonat (23,120 p.)

Hej, ucząc się c++ z książki C++ szkoła programowania odkryłem coś ciekawego, co mimo wielu kursów na internecie nie słyszałem. To w jaki sposób obiekt cout traktuje łańcuchy, że trafia tam tylko adres pierwszego elementu, wskaźnik (więc adres łańcucha) jest tak samo traktowany jak literały itd... Wiem że dzisiaj się już nie korzysta z łańcuchów ani wskaźników na char znanych z C (raczej string) ale mimo wszystko chciał bym w pełni te stare pojęcia zrozumieć. To co mam na myśli umiescze w zakładce 'code'. Z góry dziękuje za pomoc i pozdrawiam :)

char arr[30] = "dom"; //jakaś tablica (łańcuch)

char *str; // brak inicjalizacji
char *str2 = "Hello World"; //str2 wskazuje na adres tego literału
char *str3 = arr; //str3 wskazuje na adres arr

cin>>str; //w pełni rozumiem czemu jest błąd i czemu program się nie kompiluje (str nie jest zainicjalizowany )

//---teraz problem---//

cin>>str2; //program się wysypuje (dlaczego?)
cin>>str3; //wszystko działa (dlaczego?)

//dlaczego wczytanie str2 sprawia problemy a str3 już nie 
//jedyna różnica jest taka że str2 wskazuje na literał a str3 na tablicę...

 

komentarz 5 stycznia 2018 przez Jakub 0 Pasjonat (23,120 p.)
ok, odkryłem już że kiedy wpiszemy coś w str3 to zmieni się tablica arr. Dlaczego jednak zmiana cin'em wartości str2 powoduje problem. Przecież on też wskazuje na adres tyle że adres literału.
1
komentarz 5 stycznia 2018 przez criss Mędrzec (172,590 p.)

Przecież on też wskazuje na adres tyle że adres literału.

Dokładnie. Literały łańcuchowe przechowywane w bloku pamięci read-only. Tablica arr jest zwyczajnie na stosie dlatego wszystko jest ok. 

1
komentarz 5 stycznia 2018 przez jpacanowski VIP (101,940 p.)
edycja 5 stycznia 2018 przez jpacanowski

Wiem że dzisiaj się już nie korzysta z łańcuchów ani wskaźników na char znanych z C

W dzisiejszej obecnej informatyce jak najbardziej się korzysta z łańcuchów oraz wskaźników na char. Jednak w C++ to rzadkość i muszę się z tym zgodzić.

ale mimo wszystko chciał bym w pełni te stare pojęcia zrozumieć

Stare? Zabijasz w tym momencie wszystkie Uniksy, Linuksa oraz dużą większość innych systemów operacyjnych... A samemu Linusowi Torvaldsowi się zrobiło przykro...

2 odpowiedzi

+1 głos
odpowiedź 5 stycznia 2018 przez the_danger Gaduła (4,800 p.)
wybrane 5 stycznia 2018 przez Jakub 0
 
Najlepsza
char *str2 = "Hello World"; //str2 wskazuje na adres tego literału
char *str3 = arr; //str3 wskazuje na adres arr

To się nie powinno skompilować w kompilatorze C++a. Powinno być:

const char *str2 = "Hello World"; //str2 wskazuje na adres tego literału 
const char *str3 = arr; //str3 wskazuje na adres arr

Powód: literał "Hello World" trafia bezpośrednio do pliku wykonywalnego do sekcji .rdata (read-only data). Dlatego próba modyfikacji danych z pod tego adresu kończy się crashem aplikacji (segfault).

1
komentarz 5 stycznia 2018 przez the_danger Gaduła (4,800 p.)

Myślałem że wskaźnik na char ułatwia sprawę w języku C, bo nie mamy ograniczeń jego wielkości.

Wskaźnik to tylko wskaźnik. On tylko wskazuje na pewien obszar pamięci a nie nim zarządza. O to musisz zadbać sam lub użyć klasy z std, która zrobi to za ciebie (vector, string)

Skoro to ma być stała to już lepiej użyć chyba tablic char'ów?

Wszystko zależy czego potrzebujesz. Jeśli piszesz w C++ie to unikasz jednego i drugiego, i zamiast tego używasz std::string. Jeśli piszesz w C i np. potrzebujesz jakiegoś bufora to możesz użyć tablicy char'ów. Jeśli masz jakiś tekst, który jest używany dużo razy w programie i nigdy się nie zmienia, to możesz użyć const char*

Po za tym V.Studio 2017 z którego korzystam mi nie wyrzuca błędu a jest to dość nowe środowisko.

Z VS jest różnie jeśli chodzi o wspieranie standardów, ale przynajmniej powinno Ci wyrzucić warning. Masz włączony 3 level warningów w ustawieniach?

komentarz 5 stycznia 2018 przez Jakub 0 Pasjonat (23,120 p.)
To słaby ten nowy standart :/ Co jest złego że mam coś takiego:

char *cc = "hello";

strncpy(cc,"podmiana",100);

zgodnie ze standardem coś takiego ma być niemożliwe bo char* to domyślnie stała... Co jest jednak złego w użyciu takiej funkcji, czy te wszystkie dopasowania do ISO itd nie utrudniają tylko życia. Oczywiście podaje przykład bo tak jak mówię zdecydowanie wolę korzystać ze string'a (on się oczywiście opiera na łańcuchach ale klasa ułatwia ich stosowanie)
1
komentarz 5 stycznia 2018 przez the_danger Gaduła (4,800 p.)

 

char *cc = "hello";

strncpy(cc,"podmiana");

A teraz spróbuj to skompilować (pomijając brak ostatniego argumentu dla strncpy). Właśnie dlatego to jest nielegalne. Bo potem ludzie, którzy nie dokońca rozumieją jak to (a dokładniej wskaźniki) działa starają się wykonywać jakieś kombinacje i kończy się to zagadkowymi (dla nich) crashami programu.

komentarz 5 stycznia 2018 przez Jakub 0 Pasjonat (23,120 p.)
edycja 5 stycznia 2018 przez Jakub 0
Zwracam honor. jednak mam błąd. Nawet kiedy dodam trzeci argument lub zmienię na strcpy. Książka też mówi że na wielu kompilatorach to nie będzie działać. Dzięki za pomoc, chodź przyznam że ciężkie jest to że na wielu środowiskach często są różne zasady.

*teraz też zauważyłem że strncpy zostało użyte dla tablicy char'ów a nie dla wskaźnika na char. Wszystko źle zrozumiałem co tam pisało (stąd problem).
komentarz 5 stycznia 2018 przez j23 Mędrzec (195,220 p.)

@the_danger,
 

(...) Powinno być:

const char *str2 = "Hello World"; //str2 wskazuje na adres tego literału
const char *str3 = arr; //str3 wskazuje na adres arr

O ile pierwszy const jest uzasadniony, to nie rozumiem, dlaczego twierdzisz, że str3 też powinno być const (arr jest zwykła tablicą).

 

//str3 wskazuje na adres arr

str3 wskazuje na arr[0].

komentarz 5 stycznia 2018 przez the_danger Gaduła (4,800 p.)
Ten drugi const przez przypadek. Nieuważnie spojrzałem i myślałem że następuje: str3=str2
0 głosów
odpowiedź 5 stycznia 2018 przez Arkadiusz Sikorski Pasjonat (20,160 p.)
edycja 5 stycznia 2018 przez Arkadiusz Sikorski
Mogę się mylić, więc liczę, że ktoś mnie ewentualnie poprawi lub potwierdzi, co tu napisałem:

Inicjalizując str2 przypisujesz do tego wskaźnika adres literału, który znajduje się w sekcji programu, gdzie zapisane są stałe. Wczytując ze strumienia dane, wskaźnik str2 jest traktowany jak adres bufora i następuje próba zapisu do tego bufora - próbujesz zmienić wartość danej w sekcji read-only, czego nie omieszka wytknąć Ci system operacyjny, kończąc działanie Twojego programu. Dodaj consta przed str2, żeby dowiedzieć się o próbie zapisu już na etapie kompilacji.

Z kolei opcja z tablicą działa, ponieważ tablica arr jest umiejscowiona na stosie, a nie w sekcji stałych. Więc dopóki tablica arr jest zdatna do użytku (czyli gdy znajdujemy się w zakresie ważności tej zmiennej tablicowej), to możemy bezkarnie zapisać do bufora pod adresem arr 30 bajtów.
komentarz 5 stycznia 2018 przez Jakub 0 Pasjonat (23,120 p.)
Dzięki, najlepiej cię zrozumiałem :) To w tym C naprawdę ciężko pracować na napisach...

Podobne pytania

0 głosów
2 odpowiedzi 979 wizyt
pytanie zadane 9 lutego 2017 w C i C++ przez robRoy Użytkownik (970 p.)
0 głosów
1 odpowiedź 236 wizyt
pytanie zadane 18 września 2017 w C i C++ przez Sic Dyskutant (8,510 p.)
0 głosów
1 odpowiedź 583 wizyt
pytanie zadane 25 kwietnia 2017 w C i C++ przez qaz3011 Nowicjusz (240 p.)

93,103 zapytań

142,077 odpowiedzi

321,562 komentarzy

62,445 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

Wprowadzenie do ITsec, tom 1 Wprowadzenie do ITsec, tom 2

Można już zamawiać dwa tomy książek o ITsec pt. "Wprowadzenie do bezpieczeństwa IT" - mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy aż 15% zniżki! Dziękujemy ekipie Sekuraka za fajny rabat dla naszej Społeczności!

...