C Строка произвольной длины - PullRequest
4 голосов
/ 05 мая 2020

Я сомневаюсь, как распределяется длина для массива.

#include <stdio.h>
#include <string.h>

int main()
{
    char str[] = "s";
    long unsigned a = strlen(str);
    scanf("%s", str);
    printf("%s\n%lu\n", str, a);
    return 0;
}

В приведенной выше программе я присваиваю строку "s" массиву char. Я думал, что длина str[] равна 1. Поэтому мы не можем хранить больше, чем длина массива. Но ведет себя иначе. Если я читаю строку, используя scanf, она сохраняется в str[] без каких-либо ошибок. Какова была длина массива str?

Пример ввода-вывода:

Hello

Hello 1

Ответы [ 3 ]

6 голосов
/ 05 мая 2020

Ваш str представляет собой массив char, инициализированный "s", то есть он имеет размер 2 и длину 1. Размер на единицу больше длины, потому что в конце добавляется символ конца строки NUL (\0).

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

На самом деле происходит то, что, поскольку массив str хранится где-то в памяти (на stack), и эта область памяти намного больше, чем 2 байта, вы действительно можете писать после конца, не вызывая ошибки sh. Это не означает, что вы должны. Это все еще неопределенное поведение.

Поскольку ваш массив имеет размер 2, он может содержать только строку длиной 1 плюс ее терминатор. Чтобы использовать scanf() и правильно избегать записи после конца массива, вы можете использовать спецификатор ширины поля: значение numeri c после % и перед s, например:

scanf("%1s", str);
4 голосов
/ 05 мая 2020

Массив str имеет размер 2: 1 байт для символа 's' и один байт для завершающего нулевого байта. Вы пишете за конец массива. Это вызывает неопределенное поведение .

Когда ваш код имеет неопределенное поведение, он может взломать sh, он может выдать странные результаты или (как в этом случае) работать должным образом. Кроме того, внесение, казалось бы, несвязанного изменения, такого как вызов printf для отладки или неиспользуемая локальная переменная, может изменить способ проявления неопределенного поведения.

4 голосов
/ 05 мая 2020

Когда массив объявляется без указания его размера, когда размер определяется используемыми инициализаторами.

В этом объявлении массива

char str[] = "s";

используется строковый литерал как инициализатор. Строковый литерал - это последовательность символов, заканчивающаяся включенным нулевым символом в конце. То есть строковый литерал "s" имеет два символа { 's', '\0' }.

Его символы используются для последовательной инициализации элементов массива str.

Итак, если вы напишете

printf( "sizeof( str ) = %zu\n", sizeof( str ) );

, тогда вывод будет 2. Длина строки определяется как количество символов перед завершающим нулевым символом. Поэтому, если вы напишете

#include <string.h>
//...
printf( "strlen( str ) = %zu\n", strlen( str ) );

, то на выходе будет 1.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...