Нулевой символ в конце строкового литерала - PullRequest
0 голосов
/ 13 апреля 2020

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

версия 1:

int main(void)
{
    char a[7] = "and";

    printf("size: %d   length: %d",sizeof(a), strlen(a) );
}

версия 2:

int main(void)
{
    char a[7];
    a[1] = 'a';
    a[2] = 'n';
    a[3] = 'd';

    printf("size: %d   length: %d",sizeof(a), strlen(a) );
}

Однако вот результат, который я получил:

версия 1:

size: 7   length: 3

версия 2:

size: 7   length: 4

Пока как я знаю, строка заканчивается нулевым символом, а нулевой символ в строковом литерале неявный, но почему он исчез? Почему он не был включен как последний элемент, поскольку длина в версии 1 показывает 3?

Ответы [ 4 ]

1 голос
/ 13 апреля 2020

Во втором случае

int main(void)
{
    char a[7];
    a[1] = 'a';
    a[2] = 'n';
    a[3] = 'd';

    printf("size: %d   length: %d",sizeof(a), strlen(a) );
}

вам повезло, что

  • a[0] не содержит 0 (т. Е. '\0' или ноль): вы увидел бы значение 0 как длину.
  • a[4] фактически имеет нулевое значение, иначе ваш компьютер мог бы быть сожжен !!

Другими словами, для локальная переменная с автоматическим хранением c, если оставить ее неинициализированной, значения будут неопределенными. Нет гарантии на заполнение 0 (которое действует как нулевой терминатор), поэтому использование массива в виде строки (например, аргумент для strlen()), вероятно, приведет к доступу из связанной памяти и вызовет неопределенное поведение .

1 голос
/ 13 апреля 2020

sizeof измерить объем памяти чего-либо. strlen вычисляет длину c -строки (длина определяется как длина последовательности символов, исключая ноль, заканчивающийся единицей). Здесь ваша c -строка короче памяти, используемой для ее хранения.

sizeof - это C -оператор, оцениваемый как время компиляции.

strlen - это библиотека функция, вызываемая во время выполнения.

strlen(3)

ОПИСАНИЕ Функция strlen () вычисляет длину строки s.

ВОЗВРАЩАЕМЫЕ ЗНАЧЕНИЯ Функция strlen () возвращает количество символов, предшествующих завершающему символу NUL.

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

1 голос
/ 13 апреля 2020

Согласно strlen описание:

size_t strlen(const char *str);

Возвращает длину заданной строки байтов с нулем в конце, то есть количества символов в символе массив, на первый элемент которого указывает str до и не включая первый нулевой символ. Поведение не определено, если str не является указателем на байтовую строку с нулевым символом в конце.

Поскольку во второй версии a не является байтовой строкой с нулевым символом в конце, поведение не определено .

Обратите внимание, что присвоение отдельных символьных литералов массиву char не делает его строковым литералом, чтобы создать должным образом завершенный нулем массив char с использованием такого рода назначения вам нужно сделать это самостоятельно, начиная с индекса 0:

a[0] = 'a';
//...
a[3] = '\0';
1 голос
/ 13 апреля 2020

Фактически strlen должен исключать нулевой символ, поэтому вывод 3 является правильным. Проблема со второй версией заключается в том, что a [7] не инициализируется, поэтому его значения могут быть произвольными. В этом случае просто так получается, что 5-е значение равно 0, а 0-е - нет, следовательно, вывод 4. Обратите внимание, что во второй версии вы используете неправильные индексы - индексация массивов начинается с 0, а не с 1.

Если вы хотите, чтобы это работало во второй версии, переписайте это так:

int main(void)
{
    char a[7] = {0};
    a[0] = 'a';
    a[1] = 'n';
    a[2] = 'd';

    printf("size: %d   length: %d",sizeof(a), strlen(a) );
}

Это инициализирует первое значение в a в 0 явно и неявно делает все остальные значения также равными нулю.

...