Чтобы ответить на ваши пронумерованные баллы.
- Да.
- Все байты. Malloc / free не знает и не заботится о типе объекта, только о размере.
- Строго говоря, неопределенное поведение, но распространенный прием, поддерживаемый многими реализациями. Ниже приведены другие альтернативы.
Последний стандарт C, ISO / IEC 9899: 1999 (неофициально C99), позволяет гибкие элементы массива .
Примером этого может быть:
int main(void)
{
struct { size_t x; char a[]; } *p;
p = malloc(sizeof *p + 100);
if (p)
{
/* You can now access up to p->a[99] safely */
}
}
Эта теперь стандартизированная функция позволила вам избежать использования общего, но нестандартного расширения реализации, которое вы описали в своем вопросе. Строго говоря, использование негибкого члена массива и доступ за его пределы - неопределенное поведение, но многие реализации документируют и поощряют его.
Кроме того, gcc допускает массивы нулевой длины в качестве расширения. Массивы нулевой длины недопустимы в стандартном C, но gcc ввел эту функцию до того, как C99 предоставил нам гибкие члены массива.
В ответ на комментарий я объясню, почему приведенный ниже фрагмент является технически неопределенным поведением. Номера секций, которые я цитирую, относятся к C99 (ISO / IEC 9899: 1999)
struct {
char arr[1];
} *x;
x = malloc(sizeof *x + 1024);
x->arr[23] = 42;
Во-первых, 6.5.2.1 # 2 показывает, что [i] идентично (* ((a) + (i))), поэтому x-> arr [23] эквивалентно (* ((x-> arr) ) + (23))). Теперь 6.5.6 # 8 (с добавлением указателя и целого числа) говорит:
"Если и операнд-указатель, и результат указывают на элементы одного и того же объекта массива или один после последнего элемента объекта массива, при оценке не должно быть переполнения; в противном случае поведение не определено".
По этой причине, поскольку x-> arr [23] не находится в массиве, поведение не определено. Вы все еще можете подумать, что все в порядке, потому что malloc () подразумевает, что массив теперь расширен, но это не совсем так. В информативном приложении J.2 (в котором перечислены примеры неопределенного поведения) приводятся дополнительные пояснения на примере:
Индекс массива вне диапазона, даже если объект, очевидно, доступен с
заданный индекс (как в выражении lvalue a [1] [7] с учетом объявления int
а [4] [5]) (6,5,6).