🏠

C

Зміст:
  1. Пам’ять та угоди

Пам’ять та угоди

На втомлену голову переплутав розмір масиву з його крайнім елементом і написав:

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

int main() {
  char src[3] = "abc";
  char dest[3] = "zxc";
  strcpy(dest, src);
  printf("dest: %s\n", dest);
  return 0;
}

І отримав:

dest: abc�Nr�

Тому що функція strcpy набирає з початкового масиву доти, доки не зустріне нуль \0.
І потім abc разом зі сміттям, що після нього, успішно копіюється в dest.

Ще не розібравшись, що відбувається, я зрозумів, що можна полагодити це неподобство, “обрізавши” dest додаванням туди нуля:

  char src[3] = "abc";
  char dest[3] = "zxc";
  strcpy(dest, src);

  dest[sizeof(dest)] = '\0';  // <--

  printf("dest: %s\n", dest);

І справді помилку не видно:

dest: abc

Але під капотом я цим додаванням заліз на чужу, а точніше, незвідану територію в пам’яті, і перетер своїм нулем чиюсь комірку.
Адже я виділив 3 байти на масив, а не 4.
І потім, не спитавшись у компілятора, поліз на четвертий байт, який не був зарезервований за мною.

“Куди по копаному?!”

Отже, під час ініціалізації:

  char src[3] = "abc";

відбувається укладання угоди, що мені потрібен масив розміром в 3 байти, і компілятор виділяє для цього мені пам’ять.

Ніхто не виділяє мені пам’ять, коли я вручну щось почну писати за межами цих трьох байт.
І якщо я допишу нуль в елемент поза масивом, це буде порушенням угоди.

Отже, як правильно?

Правильно буде у розмірах завжди закладатися на нуль як невід’ємну частину рядка:

  char src[4] = "abc";

Бачиш 3 елементи, але закладаєшся на 4.

І не після, а під час укладання угоди.

І не пишіть код на втомлену голову.

(особлива подяка Furdog за допомогу у розслідуванні)



Побудовано за допомогою Eleventy