Czy C ma typ string? [zamknięte]

Ostatnio zacząłem programować w języku C, pochodzącym z Javy i Pythona. Teraz w mojej książce zauważyłem, że aby zrobić program "Hello World", składnia jest mniej więcej taka:

char message[10]
strcpy(message, "Hello, world!")
printf("%s\n", message);

Teraz, ten przykład używa tablicy znaków i zastanawiałem się - co się stało z łańcuchami? Dlaczego nie mogę tego po prostu użyć? Może jest na to inny sposób?

Author: dgvid, 2013-02-05

7 answers

C nie ma i nigdy nie miał natywnego typu string. Zgodnie z konwencją, język używa tablic char zakończonych znakiem null, tzn. z '\0'. Funkcje i makra w standardowych bibliotekach języka zapewniają wsparcie dla tablic znakowych zakończonych znakiem null, np. strlen iteruje nad tablicą char dopóki nie napotka znaku '\0', A strcpy kopiuje z łańcucha źródłowego, dopóki nie napotka '\0'.

Użycie zakończonych znakiem null łańcuchów w C odzwierciedla fakt, że C miał być tylko trochę bardziej zaawansowany niż język asemblacji. Zero-zakończone ciągi znaków były już w tym czasie obsługiwane bezpośrednio w języku asemblacji dla PDP-10 i PDP-11 .

Warto zauważyć, że ta właściwość ciągów C prowadzi do wielu paskudnych błędów przepełnienia bufora, w tym poważnych wad bezpieczeństwa. Na przykład, jeśli zapomnisz o null-Zakończ łańcuch znaków przekazany jako argument źródłowy do strcpy, funkcja Kopiuj sekwencyjne bajty z tego, co znajduje się w pamięci za końcem łańcucha źródłowego, dopóki nie spotka się 0, potencjalnie nadpisując cenne informacje, które następują po położeniu łańcucha docelowego w pamięci.

W twoim przykładzie kodowym literał " Hello, world!"zostanie skompilowana do 14-bajtowej tablicy char. Pierwsze 13 bajtów będzie zawierać litery, przecinek, spację i wykrzyknik, a ostatni bajt będzie zawierał znak null-terminator znak '\0', automatycznie dodawany dla ciebie przez kompilator. Jeśli uzyskasz dostęp do ostatniego elementu tablicy, znajdziesz go równym 0. Np.:

const char foo[] = "Hello, world!";
assert(foo[12] == '!');
assert(foo[13] == '\0');

Jednak w twoim przykładzie message ma tylko 10 bajtów. strcpy zapisuje do pamięci wszystkie 14 bajtów, łącznie z null-terminatorem, zaczynając od adresu message. Pierwsze 10 bajtów zostanie zapisanych do pamięci przydzielonej na stosie dla message, a pozostałe cztery bajty zostaną zapisane na końcu stos. Konsekwencja zapisania tych czterech dodatkowych bajtów na stos jest trudna do przewidzenia w tym przypadku (w tym prostym przykładzie może to nic nie zaszkodzić), ale w kodzie rzeczywistym zwykle prowadzi do uszkodzonych danych lub błędów naruszenia dostępu do pamięci.

 53
Author: dgvid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-10 07:53:31

Nie ma string wpisz C. Musisz użyć tablic znaków.

Przy okazji twój kod nie będzie działał, ponieważ rozmiar tablicy powinien pozwalać na zmieszczenie się całej tablicy plus jeden dodatkowy znak zerowy kończący.

 12
Author: Ivaylo Strandjev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-05 14:06:36

W języku C łańcuch znaków jest po prostu tablicą znaków, zakończoną bajtem null. Tak więc char* jest często wymawiane jako "string", gdy czytasz Kod C.

 7
Author: Peter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-05 14:06:49

Aby zanotować to w wymienionych językach:

Java:

String str = new String("Hello");

Python:

str = "Hello"

Zarówno Java, jak i Python mają pojęcie "string", C nie ma pojęcia"string". C ma tablice znaków, które mogą być "tylko do odczytu" lub manipulowalne.

C:

char * str = "Hello";  // the string "Hello\0" is pointed to by the character pointer
                       // str. This "string" can not be modified (read only)

Lub

char str[] = "Hello";  // the characters: 'H''e''l''l''o''\0' have been copied to the 
                       // array str. You can change them via: str[x] = 't'

Tablica znaków jest sekwencją ciągłych znaków z unikalnym znakiem sentinel na końcu(zwykle Terminator NULL '\0'). Zauważ, że sentinel postać jest automatycznie dołączana do Ciebie w powyższych przypadkach.

 5
Author: Mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-05 14:27:18

C nie obsługuje typu string pierwszej klasy.

C++ has std:: string

 3
Author: wich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-05 14:06:04

C nie ma własnego typu danych String, takiego jak Java.

Tylko możemy zadeklarować string datatype w C używając tablicy znaków lub wskaźnika znaków Na przykład:

 char message[10]; 
 or 
 char *message;

Ale musisz zadeklarować co najmniej:

    char message[14]; 

Aby skopiować " Hello, world!"do zmiennej wiadomości.

  • 13 : 01, 14 Mar 2007 (cet)"
  • 1: dla' \0 ' znaku null identyfikującego koniec łańcucha
 1
Author: Babul Mirdha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-05 14:24:47

Po pierwsze, nie musisz tego robić. W szczególności strcpy jest zbędny - nie musisz kopiować ciągu znaków Tylko do printf. Twój message może być zdefiniowany za pomocą tego ciągu znaków.

Po drugie, nie masz wystarczająco dużo miejsca dla tego " Hello, World!"string (message musi mieć co najmniej 14 znaków, pozwalając na dodatkowy dla terminatora null).

Dlaczego, choć, to historia. W asemblerze nie ma żadnych łańcuchów, tylko bajty, słowa itp. Pascal miał struny, ale tam były problemy ze statycznym typowaniem z tego powodu - string[20] był inny typ, który string[40]. Nawet w pierwszych dniach istniały języki, które unikały tego problemu, ale powodowały to indirection i Dynamic allocation overheads, które były znacznie większym problemem wydajności w tamtych czasach.

C po prostu zdecydował się uniknąć kosztów ogólnych i pozostać na bardzo niskim poziomie. Ciągi znaków są tablicami znaków. Tablice są bardzo blisko związane ze wskaźnikami, które wskazują na ich pierwszy element. Gdy typy tablic "decay" to pointer typy, informacje o rozmiarze bufora są tracone z typu statycznego, więc nie masz problemów ze starym Pascalem.

W C++, jest klasa std::string, która unika wielu z tych problemów - i ma dynamiczne koszty ogólne alokacji, ale w dzisiejszych czasach Zwykle nas to nie obchodzi. W każdym razie std::string jest klasą biblioteczną - pod nią znajduje się obsługa tablicy znaków w stylu C.

 0
Author: Steve314,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-05 14:17:44