Имеет ли C строковый тип? [закрытый]

недавно я начал программировать на C, исходя из Java и Python. Теперь, в моей книге я заметил, что для создания программы "Hello World" синтаксис примерно такой:

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

теперь этот пример использует массив символов, и я задался вопросом-Что случилось со строками? Почему я не могу просто использовать один из этих? Может быть, есть другой способ сделать это?

7 ответов


C не имеет и никогда не имел собственного типа String. По соглашению язык использует массивы char завершается нулевым символом, т. е. с ''. Функции и макросы в стандартных библиотеках языка обеспечивают поддержку массивов символов с нулевым завершением, например,strlen перебирает массив char пока не встретится '' характера и strcpy копирует из исходной строки, пока не встретится ''.

использование строк с нулевым завершением в C отражает тот факт, что C должен был быть только немного более высоким, чем язык ассемблера. Строки с нулевым завершением уже поддерживались непосредственно в то время в язык ассемблера для PDP-10 и PDP-11.

стоит отметить, что это свойство строк C приводит к довольно неприятным ошибкам переполнения буфера, включая серьезные недостатки безопасности. Например, если вы забыли null-завершить символьная строка, переданная в качестве исходного аргумента strcpy, функция будет продолжать копировать последовательные байты из того, что происходит в памяти после конца исходной строки, пока не столкнется с 0, потенциально перезаписывая любую ценную информацию, следующую за местоположением строки назначения в памяти.

в вашем примере кода строковый литерал " Hello, world!"будет скомпилирован в 14-байтовый массив char. Первые 13 байт будут содержать буквы, запятая, пробел и восклицательный знак, а последний байт будет содержать символ null-terminator '', автоматически добавленный для вас компилятором. Если бы вы получили доступ к последнему элементу массива, вы бы нашли его равным 0. Например:

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

однако, в вашем примере, message имеет длину всего 10 байт. strcpy собирается записать все 14 байтов, включая нуль-Терминатор, в память, начиная с адреса message. Первые 10 байт будут записаны в память, выделенная в стеке для message и оставшиеся четыре байта будут просто записаны в конец стека. Последствия записи этих четырех дополнительных байтов в стек трудно предсказать в этом случае (в этом простом примере это может не повредить вещь), но в реальном коде это обычно приводит к поврежденным данным или ошибкам нарушения доступа к памяти.


нет string тип C. Вы должны использовать массивы символов.

Кстати, Ваш код не будет работать, потому что размер массива должен позволить всему массиву поместиться плюс один дополнительный нулевой завершающий символ.


в C строка просто представляет собой массив символов, заканчивающийся нулевым байтом. Так char* часто произносится как "строка", когда вы читаете код C.


чтобы отметить это на языках, которые вы упомянули:

Java:

String str = new String("Hello");

Python:

str = "Hello"

и Java, и Python имеют понятие "string", C не имеет понятия"string". C имеет массивы символов, которые могут входить в "только для чтения" или манипулировать.

C:

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

или

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

массив символов-это последовательность непрерывных символов с уникальным символом sentinel в конце (обычно a Нуль-Терминатор ''). Обратите внимание, что символ sentinel автоматически добавляется для вас в приведенных выше случаях.


C не поддерживает строковый тип первого класса.

C++ имеет std:: string


C не имеет собственного строкового типа данных, такого как Java.

только мы можем объявить строковый тип данных в C с помощью символьного массива или символьного указателя Например :

 char message[10]; 
 or 
 char *message;

но вам нужно объявить хотя бы:

    char message[14]; 

копировать "Привет, мир!- в переменную сообщения.

  • 13: длина "Привет, мир!"
  • 1 : Для '\0' нулевой символ, который определяет конец строки

во-первых, вам не нужно делать все это. В частности,strcpy является избыточным - вам не нужно копировать строку только в printf его. Ваш message можно определить с помощью этой строки на месте.

во-вторых, вы не позволили достаточно места для этого " Привет, Мир!"string (message должно быть не менее 14 символов, что позволяет использовать дополнительный символ для нулевого Терминатора).

о том, почему, хотя, это история. В ассемблере нет строк, только байты, слова и т. д. У Паскаля были строки, но из - за этого были проблемы со статической типизацией -string[20] был другой тип, который string[40]. Даже в первые дни существовали языки, которые избегали этой проблемы, но это вызывало косвенные и динамические накладные расходы на распределение, которые в то время были гораздо большей проблемой эффективности.

C просто решил избежать накладных расходов и оставаться на очень низком уровне. Строки символьные массивы. Массивы очень тесно связаны с указателями на первый элемент. Когда типы массивов "распадаются" на типы указателей, информация о размере буфера теряется из статического типа, поэтому вы не получаете старые проблемы строки Pascal.

в C++ есть std::string класс, который избегает многих из этих проблем - и имеет динамические накладные расходы на распределение, но в эти дни мы обычно не заботимся об этом. И в любом случае, std::string является классом библиотеки-есть обработка символьного массива в стиле C под ним.