Подтвердить что ты не робот

Вопрос динамической памяти

когда вы выделяете динамическую память в куче с помощью указателя,

char *buffer_heap = new char[15];

он будет представлен в памяти как:

 ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««þþþ

почему в конце нет конечного символа NULL, а не ýýýý "" " "" " þþþ?

4b9b3361

Ответ 1

Í является байтом 0xCD, который отладчик отладки Windows записывает в ваши 15 байт памяти, чтобы указать, что это неинициализированная память кучи. Неинициализированный стек будет равен 0xCC. Идея состоит в том, что если вы когда-либо читали память и неожиданно получали эту ценность, вы можете подумать о себе: "Хм, я, наверное, забыл инициализировать это". Кроме того, если вы прочитаете его как указатель и разыщите его, тогда Windows приведет к сбою вашего процесса, тогда как если неинициализированный буфер будет заполнен случайными или произвольными значениями, то иногда с помощью fluke вы получите действительный указатель, и ваш код может вызвать все виды неприятностей. С++ не говорит о том, какие значения имеет неинициализированная память, а не-отладочные распределители не будут тратить время на заполнение памяти специальными значениями для каждого распределения, поэтому вы никогда не должны полагаться на это значение.

За этим следуют 4 байта ý (байт 0xFD), который использует распределитель отладки Windows, чтобы указать область за пределами границ в конце буфера. Идея состоит в том, что если вы когда-нибудь окажетесь в отладчике, пишущем в регионе, который выглядит так, вы можете подумать: "Хм, я, наверное, перехватил мой буфер здесь". Кроме того, если значение изменилось при освобождении буфера, распределитель памяти может предупредить вас о том, что ваш код неверен.

"- байт 0xAB, а þ - 0xFE. Предположительно, они также предназначены для улавливателей (они не являются правдоподобными указателями или смещениями, поэтому они не являются частью структуры кучи). Я не знаю, что они означают, возможно, больше данных защиты, таких как 0xFD.

Наконец, я думаю, вы нашли 0 байт, 16-й байт за пределами вашего 15-байтового буфера (т.е. подсчет 31-го байта с начала его).

Задавая вопрос как "С++", не упоминая, что вы находитесь в Windows, предполагает, что так работает С++. Это не так, как ведет себя одна реализация С++, с конкретными параметрами компилятора и/или связанными DLL. С++ не позволяет вам прочесть конец буфера, Microsoft просто хорош для вас и позволяет вам уйти с ним, не сбой или еще хуже.

Ответ 2

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

Ответ 3

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

char *b = new char[15]();

Ответ 4

Хотя каждая строка стиля C представляется как последовательность символов, не каждая последовательность символов является строкой.

Обычно\0 появляется, когда вы напрямую назначаете строковый литерал или добавляете его там сами. И это имеет смысл только в том случае, если вы рассматриваете этот массив как строку с функциями, которые учитывают \0.

Если вы просто выделите память и не инициализируете ее, она заполнена случайными материалами. Там может быть 0, а может и не быть - на следующем шаге вам придется помещать что-то значимое. Это зависит от вас, нужно ли сделать что-то вроде строки или нет.

Ответ 5

Поскольку char является родным, он не инициализирован. Это как раз то, как С++ (это наследие C).

Просто примите это, и 0 завершите его самостоятельно:

char *buffer_heap = new char[15];
*buffer_heap = '\0';

или если вы хотите инициализировать весь буфер:

std::fill(buffer, buffer + 15, 0);

Ответ 6

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

С другой стороны, лучший ответ заключается в том, что вы просто не должны этого делать в первую очередь. Забудьте, что new[] существует и не оглядывается назад.

Ответ 7

В GNU С++ (g++) в Linux эта программа довольно быстро выходит:

#include <algorithm>
#include <iterator>
#include <vector>
#include <cstddef>
#include <cstdlib>
#include <iostream>

namespace {

class rand_functor {
 public:
   int operator ()() const { return ::std::rand(); }
};

}

int main()
{
   using ::std::cout;
   using ::std::vector;
   using ::std::ostream_iterator;
   using ::std::generate;
   using ::std::equal;
   using ::std::copy;

   char *tmp = new char[1000];
   // This just fills a bunch of memory with random stuff, then deallocates it
   // in the hopes of making a match more likely.
   generate(tmp, tmp+1000, rand_functor());
   delete[] tmp;
   vector<char *> smalls;
   smalls.push_back(new char[15]);
   do {
      smalls.push_back(new char[15]);
   } while (equal(smalls[0], smalls[0]+15, smalls[smalls.size() - 1]));
   cout << "        In one allocation I got: [";
   copy(smalls[0], smalls[0]+15, ostream_iterator<char>(cout));
   cout << "]\nAnd in another allocation I got: [";
   copy(smalls[smalls.size() - 1], smalls[smalls.size() - 1]+15,
        ostream_iterator<char>(cout));
   cout << "]\n";
   cout << "It took " << smalls.size() << " allocations to find a non-matching one.\n";
   return 0;
}