Почему код А работает нормально, а код Б выдает ошибку? Единственная разница — это printf. Также обратите внимание, что я обращаюсь к памяти за пределами диапазона. И GCC с этим согласен. В примере А я даже легко перезаписал ОЗУ.
Ошибка компилятора:
Fatal glibc error: malloc assertion failure in sysmalloc: (old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)
Мой код мира:
#include <stdio.h>
#include <stdlib.h>
int main()
{
#if 1
// A
int *items = malloc(10 * sizeof(int));
printf("allocated: %lu bytes\n", 10 * sizeof(int));
items = items;
items[0] = 5;
items[9] = 5;
items[10] = 5;
printf("[");
for (size_t i = 0; i <= 10; i++)
{
printf(" %d", items[i]);
}
printf(" ]\n");
#else
// B
int *items = malloc(10 * sizeof(int));
items = items;
items[0] = 5;
items[9] = 5;
items[10] = 5;
printf("[");
for (size_t i = 0; i <= 10; i++)
{
printf(" %d", items[i]);
}
printf(" ]\n");
#endif
return 0;
}
Я попробовал спросить в чатгпте, почему он работает, он говорит, что у меня недостаточно оперативной памяти, а это ерунда. Я ожидаю сегментированных ошибок в обоих примерах.
🤔 А знаете ли вы, что...
C имеет богатую стандартную библиотеку, включающую функции для работы с файлами, строками, памятью и другими задачами.
Я ожидаю сегментированных ошибок в обоих примерах.
Ничто в стандарте C не говорит о том, что реализация C должна вызывать нарушение доступа к памяти при переполнении выделенной памяти. Ни один надлежащий учебник или учебник не делает этого. В некоторых учебных материалах может упоминаться, что может произойти ошибка сегментации, но это не факт.
Как правило, невозможно гарантировать нарушение доступа к памяти, поскольку аппаратное обеспечение обычно обрабатывает память блоками, называемыми страницами, обычно по 4096 или 8192 байта, но malloc
выделяет память меньшими блоками, часто блоками по 16 байт. (Даже если вы запрашиваете меньшую сумму или сумму, которая не кратна 16 байтам, malloc
все равно может выполнять свою работу блоками по 16 байт.) Итак, если вы выделите 40 байтов для десяти int
, нет никакой возможности чтобы пометить память сразу после этих 40 байт как недоступную. Аппаратное обеспечение предоставляет страницу размером 4096 байт, и оно не может сказать, что к 40 из этих байт можно получить доступ, а к остальным — нет.
Стандартные процедуры управления памятью C не указаны для предотвращения некорректного доступа. Язык C обычно не предназначен для предотвращения неправильных действий вашей программы. Это поможет вам писать программы с низкими накладными расходами. В частности, это позволяет избежать накладных расходов на проверку всего, что делает ваша программа. Ваша задача как программиста — обеспечить корректность вашей программы.
Что касается разницы между двумя вашими последовательностями кода, то одна из них, переполнив массив, случайно изменила данные, которые процедуры управления памятью используют для ведения записей. Когда они это обнаружили, они сообщили об ошибке. Разница, вероятно, в том, что в памяти две кодовые последовательности располагались по-разному.