когда вы выделяете динамическую память в куче с помощью указателя,
char *buffer_heap = new char[15];
он будет представлен в памяти как:
ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««þþþ
почему в конце нет конечного символа NULL, а не ýýýý "" " "" " þþþ?
когда вы выделяете динамическую память в куче с помощью указателя,
char *buffer_heap = new char[15];
он будет представлен в памяти как:
ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««þþþ
почему в конце нет конечного символа NULL, а не ýýýý "" " "" " þþþ?
Í является байтом 0xCD, который отладчик отладки Windows записывает в ваши 15 байт памяти, чтобы указать, что это неинициализированная память кучи. Неинициализированный стек будет равен 0xCC. Идея состоит в том, что если вы когда-либо читали память и неожиданно получали эту ценность, вы можете подумать о себе: "Хм, я, наверное, забыл инициализировать это". Кроме того, если вы прочитаете его как указатель и разыщите его, тогда Windows приведет к сбою вашего процесса, тогда как если неинициализированный буфер будет заполнен случайными или произвольными значениями, то иногда с помощью fluke вы получите действительный указатель, и ваш код может вызвать все виды неприятностей. С++ не говорит о том, какие значения имеет неинициализированная память, а не-отладочные распределители не будут тратить время на заполнение памяти специальными значениями для каждого распределения, поэтому вы никогда не должны полагаться на это значение.
За этим следуют 4 байта ý (байт 0xFD), который использует распределитель отладки Windows, чтобы указать область за пределами границ в конце буфера. Идея состоит в том, что если вы когда-нибудь окажетесь в отладчике, пишущем в регионе, который выглядит так, вы можете подумать: "Хм, я, наверное, перехватил мой буфер здесь". Кроме того, если значение изменилось при освобождении буфера, распределитель памяти может предупредить вас о том, что ваш код неверен.
"- байт 0xAB, а þ - 0xFE. Предположительно, они также предназначены для улавливателей (они не являются правдоподобными указателями или смещениями, поэтому они не являются частью структуры кучи). Я не знаю, что они означают, возможно, больше данных защиты, таких как 0xFD.
Наконец, я думаю, вы нашли 0 байт, 16-й байт за пределами вашего 15-байтового буфера (т.е. подсчет 31-го байта с начала его).
Задавая вопрос как "С++", не упоминая, что вы находитесь в Windows, предполагает, что так работает С++. Это не так, как ведет себя одна реализация С++, с конкретными параметрами компилятора и/или связанными DLL. С++ не позволяет вам прочесть конец буфера, Microsoft просто хорош для вас и позволяет вам уйти с ним, не сбой или еще хуже.
Вы не инициализировали эту память. Вы просто видите то, что уже было там...
Вам нужно инициализировать его. Встроенные типы могут быть инициализированы до нуля путем явного вызова конструктора по умолчанию:
char *b = new char[15]();
Хотя каждая строка стиля C представляется как последовательность символов, не каждая последовательность символов является строкой.
Обычно\0 появляется, когда вы напрямую назначаете строковый литерал или добавляете его там сами. И это имеет смысл только в том случае, если вы рассматриваете этот массив как строку с функциями, которые учитывают \0.
Если вы просто выделите память и не инициализируете ее, она заполнена случайными материалами. Там может быть 0, а может и не быть - на следующем шаге вам придется помещать что-то значимое. Это зависит от вас, нужно ли сделать что-то вроде строки или нет.
Поскольку char
является родным, он не инициализирован. Это как раз то, как С++ (это наследие C).
Просто примите это, и 0 завершите его самостоятельно:
char *buffer_heap = new char[15];
*buffer_heap = '\0';
или если вы хотите инициализировать весь буфер:
std::fill(buffer, buffer + 15, 0);
Он будет инициализироваться только в том случае, если вы выделите инициализированный тип. В противном случае, если вам нужны какие-то значимые ценности, вам придется писать их сами.
С другой стороны, лучший ответ заключается в том, что вы просто не должны этого делать в первую очередь. Забудьте, что new[]
существует и не оглядывается назад.
В 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;
}