Вопрос о динамическом выделении памяти

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

char *buffer_heap = new char[15];

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

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

почему ПУСТОЙ оконечный знак в конце вместо ýýýý там не ««««««««þþþ?

11
задан Omnifarious 20 February 2010 в 00:19
поделиться

7 ответов

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

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

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

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

Если задать вопрос как «C ++», не упоминая, что вы работаете в Windows, это означает, что C ++ ведет себя именно так.Это не так, это то, как ведет себя одна реализация C ++ с определенными параметрами компилятора и / или связанными dll. C ++ не позволяет вам читать дальше конца буфера, Microsoft просто вежлива с вами и позволяет вам избежать сбоев или того хуже.

22
ответ дан 3 December 2019 в 02:01
поделиться

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

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

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

1
ответ дан 3 December 2019 в 02:01
поделиться

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

6
ответ дан 3 December 2019 в 02:01
поделиться

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

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

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

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

std::fill(buffer, buffer + 15, 0);
1
ответ дан 3 December 2019 в 02:01
поделиться

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

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

1
ответ дан 3 December 2019 в 02:01
поделиться

В GNU C++ (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;
}
0
ответ дан 3 December 2019 в 02:01
поделиться

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

char *b = new char[15]();
4
ответ дан 3 December 2019 в 02:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: