Место в массиве
У массива-строки фиксированный размер, как у любого массива. В char name[] = "Anna"; ровно 5 элементов: место для 4 букв и для '\0', и больше ничего. Если вы хотите позже сохранить в нём более длинный текст, дайте массиву больше места при создании:
char nickname[20] = "Anna";
int size = sizeof(nickname);
int length = strlen(nickname);
printf("%d %d\n", size, length);Это выведет:
20 4В массиве 20 элементов. Текст занимает первые пять элементов вместе со своим '\0', а остальные равны нулю, как у int numbers[5] = {0};. Вот почему sizeof и strlen теперь дают разные числа: размер массива и длину текста в нём.
Как поместить в массив новый текст? Не с помощью =. Как вы знаете из урока о массивах, массив нельзя присвоить целиком:
char nickname[20] = "Anna";
nickname = "Bob";main.c:5:14: error: array type 'char[20]' is not assignableВместо этого используйте функцию strcpy (string copy, «копирование строки») из string.h. Она копирует символы текста, включая его '\0', в массив. В скобках сначала напишите, куда копировать, потом — что:
char nickname[20] = "Anna";
strcpy(nickname, "Bob");
printf("%s\n", nickname);Это выведет:
BobПорядок такой же, как у =: слева то, куда копируем. Более короткий текст — не проблема. Его '\0' отмечает новый конец, а то, что осталось в массиве после него, уже не важно.
В массиве должно быть место для всего текста и его '\0'. strcpy этого не проверяет: она не знает, насколько велик массив, и копирует, пока не дойдёт до '\0'. Если текст не помещается, она продолжает записывать за концом массива, в память, которая принадлежит чему-то другому. Когда Clang видит, что текст не поместится, программа здесь не компилируется:
char nickname[5] = "Anna";
strcpy(nickname, "Alexander");main.c:6:5: error: 'strcpy' will always overflow; destination buffer has size 5, but the source string has length 10 (including NUL byte) [-Werror,-Wfortify-source]Сообщение говорит, что в целевом массиве (destination buffer) место для 5 символов, а тексту (source string) нужно 10 вместе с нулевым символом (NUL byte). Но Clang видит это не всегда, например когда текст берётся из другого массива. Тогда ничто не остановит программу, и она продолжит работать с испорченными данными. Такие ошибки стали причиной многих дыр в безопасности настоящих программ. Поэтому перед каждым strcpy проверяйте, что длина текста плюс 1 помещается в массив.
То же относится и к начальному тексту. C позволяет написать char name[4] = "Anna";, но тогда для '\0' места не остаётся, и у текста нет конца:
char city[] = "Paris";
char name[4] = "Anna";
printf("%s\n", name);
printf("%s\n", city);Это выведет:
AnnaParis
ParisВ первой строке должно быть только Anna. Но printf не нашла после неё '\0' и продолжила выводить всё, что лежало в памяти после массива, — здесь это оказался массив city.
Задание
- 1
Игрок начинает игру. Под
printfскопируйте текст"playing a game"вstatusс помощьюstrcpyи снова выведите статус тем жеprintf. Запустите программу: она не скомпилируется, потому что вstatusместа только для"online". Дайте массиву место для 20 символов,char status[20] = "online";, и запустите снова. Вывод должен заканчиваться строкойСтатус: playing a game. - 2
Потом игрок ненадолго отходит. Скопируйте
"away"вstatusи выведите статус ещё раз:Статус: away.