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