Подтвердить что ты не робот

Имеет ли C тип строки?

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

Ответ 4

Чтобы отметить это на указанных вами языках:

Java:

String str = new String("Hello");

Python:

str = "Hello"

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

С

char * str = "Hello";  // the string "Hello\0" 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''\0' have been copied to the 
                       // array str. You can change them via: str[x] = 't'

Символьный массив представляет собой последовательность смежных символов с уникальным символом сторожевого знака в конце (обычно это NULL-терминатор '\0'). Обратите внимание, что дозорный символ автоматически добавляется к вам в случаях выше.

Ответ 5

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

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

Ответ 6

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

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

 char message[10]; 
 or 
 char *message;

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

    char message[14]; 

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

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

Ответ 7

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

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

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

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

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