k = new char*;
Это выделенное хранилище только для одного char*
.
*(k + 1) = k2;
Это пытается сделать вид, что выделено два char*
. Это может быть не сайт segfault, но это ошибка.
delete [] (k + 1);
Здесь вы пытаетесь delete[]
что-то, что вы не сделали new[]
, еще одна ошибка.
РЕДАКТИРОВАТЬ: В глубине, память выделяется большими кусками, такими как страницы. Поэтому, когда вы выделяете небольшой объем памяти, очень вероятно, что память вокруг него также является действительной. Однако доступ к нему все еще очень недействителен.
Более того, когда вы говорите что-то вроде new char*
, это превращается в вызов operator new(sizeof(char*))
. Допустим, ОС выделяет новую страницу 4 КБ физической памяти для этого по адресу 0x12340000
. Менеджеру памяти нужна небольшая структура, чтобы отслеживать блок, что-то вроде:
struct mem_block_info {
void* next_block;
size_t block_size;
};
Таким образом, эта структура помещается в 0x12340000
. Сразу после этого он помещает запрошенное вами хранилище, поэтому (при условии, что это 32-разрядный компьютер) он возвращает указатель 0x12340008
, начиная с sizeof(void*) == sizeof(size_t) == 4
. Затем он должен поместить заголовок после вашего хранилища, чтобы отследить неиспользуемую часть этой страницы 4K, чтобы не тратить память, выделяя еще одну страницу 4K, когда вам нужно еще char*
. Этот заголовок идет по адресу сразу после конца выделенного блока, 0x1234000C
. Как только пыль осядет, new char*
записал это в память:
Address Data
0x12340000 0x00000000
0x12340004 0x00000001
0x12340008 uninitialized; could be anything
0x1234000C 0x00000000
0x12340010 0x00000FF4
Нулевые указатели указывают на конец выделенных и связанных списков свободных блоков.
Итак, когда вы делаете:
*(k + 1) = k2;
k + 1 == 0x1234000C
- это указатель next_block
для свободного блока, и вы просто перезаписали его недопустимым значением (скорее всего, адрес строки в постоянной памяти). Это не сразу вызывает ошибку сегментации, но когда диспетчер памяти пытается просмотреть список свободных блоков, он в конечном итоге смотрит на эту строку и неправильно интерпретирует ее как заголовок блока, а затем переходит к next_block
, который является неверный адрес и бум, segfault.