C ++ char array [] утечка памяти [дубликат]

Aug 18 2020

я создал char arr [] и присвоил ему строковый литерал

char arr[] = "some string";                  // arr occupies 12 chars in memory
std::cout << std::strlen(arr)  << std::endl; // lenght is 11 chars + 1 null-terminator
                                             //arr[11] is '\0'

Затем я помещаю нуль-терминатор в 6-й элемент

arr[5] = '\0';
std::cout << std::strlen(arr) << std::endl; // lenght is 5 chars  + 1 null-terminator
  1. Это утечка памяти?
  2. Как компилятор узнает, что он должен освободить память после первого '\ 0'? (когда удалят переменную arr)
  3. Можно ли изменить длину этой переменной arr и уведомить компилятор, сколько он должен освободить при удалении переменной?

Ответы

5 user253751 Aug 18 2020 at 13:03
  1. Это утечка памяти?

Нет.

  1. Как компилятор узнает, что он должен освободить память после первого '\ 0'? (когда удалят переменную arr)

Переменная состоит из 12 символов. Это то же самое, что писать:

char arr[12] = "some string";

Таким образом, он всегда будет освобождать 12 символов. Переменная представляет собой массив из 12 символов; тот факт, что 6-й символ оказывается '\ 0', совершенно не имеет значения.

Между прочим, как только вы установили 6-й символ в '\ 0', вам все равно разрешено использовать все 12 символов, потому что это все еще массив из 12 символов. Даже те, что после '\ 0'. Но вы не можете хранить в нем 13 символов.

  1. Можно ли изменить длину этой переменной arr и уведомить компилятор, сколько он должен освободить при удалении переменной?

Нет. Невозможно изменить размер какой-либо переменной.

6 cigien Aug 18 2020 at 13:03

В этом коде:

char arr[] = "some string";

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

2 JoopEggen Aug 18 2020 at 13:07

Для полноты.

Также нет утечки памяти в выделенной памяти, например:

char* arr = (char*) malloc(12);
strcpy(arr, "some string");
arr[6] = '\0';
free(arr);

Управление памятью осуществляется за счет выделенной памяти (12), а не за счет основного использования (символ с завершающим нулем *). (Стиль C, аналогично C ++)

1 Slava Aug 18 2020 at 13:56

Похоже, ты получил это задом наперед. Размер массива в C ++ изменить нельзя, точка. Из-за этого факта и из-за того факта, что если вы передаете массив в качестве указателя, вы теряете информацию о фактическом размере этого массива, соглашение было создано для строк стиля C - 0 байт, также известный \0как нулевой терминатор, обрабатывается как динамический конец строки. Соглашение означает, что функции, работающие со строками в стиле C, рассматривают это как завершение строки. Это позволяет вам использовать массив фиксированного размера для строк разной длины и передавать только один указатель без размера фактической памяти функциям для чтения из него (например, печать на экран). Обратите внимание: когда вы передаете массив char функциям, которые записывают в него данные, вам часто нужно сообщить ему, каков фактический размер массива, чтобы эта функция не имела доступа к памяти за пределами границ, поскольку эта функция игнорировала бы нулевой терминатор, если он уже существует.

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

VladfromMoscow Aug 18 2020 at 13:16

Утечка памяти происходит, когда память была выделена программистом с помощью оператора newи не была удалена с помощью оператора deleteили delete [].

В этой декларации

char arr[] = "some string"; 

Память, выделенная компилятором (или системой) для символьного массива arr, имеет либо автоматическую продолжительность хранения, либо статическую продолжительность хранения. Таким образом, компилятор (или система) отвечает за освобождение выделенной памяти. Адрес выделенной памяти известен компилятору (или системе).

Используя это утверждение

arr[5] = '\0';

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

Как компилятор узнает, что он должен освободить память после первого '\ 0'? (когда удалят переменную arr)

Поскольку компилятор (или система) знает, как был объявлен объект типа массива.

Для объекта было выделено 12 байт.

char arr[] = "some string"; 

Можно ли изменить длину этой переменной arr и уведомить компилятор, сколько он должен освободить при удалении переменной?

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

Вы можете перераспределить объект, если использовали оператор newдля его выделения, например,

char *arr = new char[12];

std::strcpy( arr, "some string" );

//...

char *tmp = new char[20];

strcpy( tmp, "another " );
strcat( tmp, arr );

delete [] arr;
arr = tmp;