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

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

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

#include<stdio.h>
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() не учитывается?

4b9b3361

Ответ 1

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

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

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

fgets() читает не более один меньше, чем размер символов из потока и сохраняет их в буфер, на который указывает 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 будет пинать и кричать все время.

Ответ 2

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

scanf("%4s", A);

чтобы читать макс. 4 символа от stdin.

Ответ 3

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

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

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

scanf("%4s", A);

Ответ 6

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

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

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

Ответ 7

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

Ответ 8

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