Нулевое завершение массива char

Рассмотрим следующий случай:

#include int main() { char A[5]; scanf("%s",A); printf("%s",A); } 

Мой вопрос в том, что char A[5] содержит только два символа. Скажем «ab», затем A[0]='a' , A[1]='b' и A[2]='\0' . Но если вход скажет «abcde», тогда где '\0' в этом случае. Будет ли A[5] содержать '\0' ? Если да, то почему? sizeof(A) всегда будет возвращать 5 в качестве ответа. Затем, когда массив заполнен, есть ли дополнительный байт, зарезервированный для '\0' который sizeof() не учитывается?

Если вы введете более четырех символов, то дополнительные символы и нулевой терминатор будут записаны вне конца массива, переписывая память, не принадлежащую массиву. Это переполнение буфера.

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

Это отличный пример того, почему scanf("%s") является опасным и никогда не должен использоваться. Он не знает о размере вашего массива, что означает, что нет возможности безопасно его использовать. Вместо этого избегайте scanf и используйте что-то более безопасное, например fgets () :

fgets () читает не более одного символа размера из streamа и сохраняет их в буфер, на который указывает s. Чтение останавливается после EOF или новой строки. Если читается новая строка, она сохраняется в буфере. Конечный нулевой байт (‘\ 0’) сохраняется после последнего символа в буфере.

Пример:

 if (fgets(A, sizeof A, stdin) == NULL) { /* error reading input */ } 

Раздражающе, fgets () оставит конечный символ новой строки (‘\ n’) в конце массива. Таким образом, вы также можете захотеть удалить код.

 size_t length = strlen(A); if (A[length - 1] == '\n') { A[length - 1] = '\0'; } 

Тьфу. Простой (но сломанный) scanf("%s") превратился в 7-строчное чудовище. И это второй урок дня: C не подходит для ввода / вывода и обработки строк. Это можно сделать, и это можно сделать безопасно, но C будет пинать и кричать все время.

Как уже указывалось, вы должны определить / выделить массив длины N + 1 для правильного хранения символов N. Можно ограничить количество символов, прочитанных scanf. В вашем примере это будет:

 scanf("%4s", A); 

для чтения макс. 4 символа от stdin.

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

Многое C-код, который вы увидите, будет использовать производные от n таких функций, как strncpy. На этой странице можно прочитать:

Функции strcpy () и strncpy () возвращают s1. Функции stpcpy () и stpncpy () возвращают указатель на завершающий символ `\ 0 ‘s1. Если stpncpy () не завершает s1 с символом NUL, вместо этого он возвращает указатель на s1 [n] (который не обязательно относится к действительной ячейке памяти).

strlen также полагается на нулевой символ, чтобы определить длину символьного буфера. Если и когда вам не хватает этого персонажа, вы получите неверные результаты.

Вы получите неопределенное поведение .

Как вы говорите, размер A всегда будет 5, поэтому, если вы читаете 5 или более char , scanf попытается записать в память, что он не должен изменяться.

И нет, нет зарезервированного пространства / символа для символа \0 .

Любая строка длиной более 4 символов приведет к тому, что scanf будет писать за пределы массива. Полученное поведение не определено, и если вам повезет, это приведет к сбою вашей программы.

Если вам интересно, почему scanf не прекращает записывать строки, которые слишком длинны для хранения в массиве A , это потому, что scanf знает, что sizeof(A) равен 5. Когда вы передаете массив как параметр для функция C, массив распадается на указатель, указывающий на первый элемент в массиве. Таким образом, нет способа запросить размер массива внутри функции.

Чтобы ограничить количество символов, считанных в массиве, используйте

 scanf("%4s", A); 

массивы символов в c являются просто указателями на блоки памяти. Если вы сообщите компилятору зарезервировать 5 байт для символов, это произойдет. Если вы попытаетесь разместить там более 5 байтов, он просто перезапишет память за 5 байтов, которые вы зарезервировали.

Вот почему c может иметь серьезные реализации безопасности. Вы должны знать, что вы собираетесь писать только 4 символа + a \ 0. C позволит вам перезаписать память до сбоя программы.

Пожалуйста, не думайте о char foo [5] как строку. Подумайте об этом как о месте, чтобы поместить 5 байт. Вы можете сохранить там 5 символов без нулевого значения, но вы должны помнить, что вам нужно сделать memcpy (otherCharArray, foo, 5) и не использовать strcpy. Вы также должны знать, что у otherCharArray достаточно места для этих 5 байтов.

нулевой символ используется для завершения массива. он находится в конце массива и показывает, что массив заканчивается в этой точке. массив автоматически делает последний символ нулевым символом, так что компилятор может легко понять, что массив закончен.

\ 0 – оператор терминатора, который завершается, когда массив заполнен, если массив не заполнен, тогда \ 0 будет в конце массива, когда вы введете строку, которую он будет читать с конца массива