Проблема распределения памяти

Этот вопрос задавали в письменном раунде собеседования:

 #include<alloc.h>
 #define MAXROW 3
 #define MAXCOL 4

 main()
  {
    int (*p)[MAXCOL];
     p = (int (*)[MAXCOL]) malloc(MAXROW*(sizeof(*p)));
  }

Сколько байтов выделяется в процессе?

Если честно, я не ответил на вопрос. Я не понял назначение p.

Может кто-нибудь объяснить мне, что будет ответом и как его можно вывести?

Ответ 1

Это зависит от платформы.

int (*p)[MAXCOL]; объявляет указатель на массив из целых чисел MAXCOL элементов широкий (MAXCOL, конечно, 4 в этом случае). Поэтому одним из элементов этого указателя является 4*sizeof(int) на целевой платформе.

Оператор malloc выделяет буфер памяти MAXROW, умноженный на размер типа, содержащегося в P. Поэтому в общей сложности выделяются целые числа MAXROW * MAXCOL. Фактическое количество байтов будет зависеть от целевой платформы.

Кроме того, возможно, имеется дополнительная память, используемая средой выполнения C (как внутренний учет в malloc, так и различные биты инициализации процесса, которые происходят до main), что также полностью зависит от платформы.

Ответ 2

p является указателем на массив элементов MAXCOL типа int, поэтому sizeof *p (скобки являются избыточными) - это размер такого массива, то есть MAXCOL*sizeof(int).

Приведение значения возвращаемого значения malloc не является необходимым, уродливым и считается вредным. В этом случае он скрывает серьезную ошибку: из-за отсутствия прототипа malloc предполагается неявно возвращать int, что несовместимо с его правильным типом возврата (void *), что приводит к поведению undefined.

Ответ 3

sizeof(*p) будет MAXCOL*sizeof(int). Таким образом, полностью MAXROW*MAXCOL*sizeof(int) число байтов доступно.

Ответ 4

Возможно, вы захотите проверить cdecl на помощь при переводе объявлений C на английский язык. В этом случае int (*p)[4]; становится declare p as pointer to array 4 of int.

Ответ 5

#include<alloc.h>
#define MAXROW 3 
#define MAXCOL 4
main()   {
    int (*p)[MAXCOL];
    p = (int (*)[MAXCOL]) malloc(MAXROW*(sizeof(*p));
}

Сколько байтов выделяется в процессе?

p - это указатель, поэтому он будет занимать sizeof(int(*)[MAXCOL]) в стеке, который может выглядеть пугающим, но он почти всегда совпадает с sizeof(void*), sizeof(int*) или любым другим указателем. Очевидно, размеры указателей - это то, что дает приложениям их классификация как 16-, 32-, 64-и т.д. бит, и этот указатель будет соответствующим размером.

Затем p указывается в некоторой памяти, полученной из malloc...

malloc( MAXROW * sizeof(*p) )

sizeof(*p) - размер массива int, на который указывает p, а именно sizeof(int) * MAXCOL, поэтому получаем

malloc( MAXROW * (sizeof(int) * MAXCOL) )

запрашивается из кучи. Для иллюстративных целей, если принять общий 32-разрядный размер int, мы рассмотрим 48 байтов. Фактическое использование может быть округлено до того, что чувствует себя подсистемами кучи (для подпрограмм кучи часто используются "ведра фиксированного размера" для ускорения их операций).

Чтобы подтвердить это ожидание, просто замените функцию регистрации для malloc():

#include <stdio.h>

#define MAXROW 3
#define MAXCOL 4

void* our_malloc(size_t n)
{
    printf("malloc(%ld)\n", n);
    return 0;
}

int main()
{
    int (*p)[MAXCOL];
    p = (int (*)[MAXCOL]) our_malloc(MAXROW*(sizeof(*p)));
}

Вывод на моем ящике Linux:

malloc(48)

Тот факт, что возвращаемый указатель malloc отбрасывается в p-тип, не влияет на объем выделенного выделения памяти.

Как замечает R, отсутствие прототипа malloc заставит компилятор ожидать malloc вернуть int, а не фактически возвращенный void*. На практике, вероятно, что наименьшие sizeof (int) байты от указателя выживут при преобразовании, и если sizeof (void *) оказался равным sizeof (int), или - еще более слабый - произойдет куча памяти на адресе, представленном в int, несмотря на то, что размер указателей больше (т.е. все усеченные биты равны 0s), тогда последующее разыменование указателя может работать. Дешевый плагин: С++ не будет компилироваться, если не увидит прототип.

Тем не менее, возможно, ваш alloc.h содержит прототип malloc... У меня нет alloc.h, поэтому я предполагаю, что он нестандартный.

Любая программа также выделяет память для многих других вещей, таких как фрейм стека, предоставляющий некоторый контекст, в котором может быть вызван main(). Объем памяти для этого зависит от компилятора, версии, флагов компилятора, операционной системы и т.д.

Ответ 6

int (*p)[MAXCOL] == int (*p)[4] == "указатель на массив 4 из int" (см. примечание ниже)

sizeof(*p) будет то, что p указывает на, т.е. 4 * sizeof(int). Умножьте это на MAXROW и ваш окончательный ответ:

12 * sizeof(int)

Примечание. Это отличается от:

int *p[MAXCOL] == int *p[4] == "массив 4 указателя на int"
Скобки заключаются в значительной степени!

Ответ 7

Это должно быть MAXROW * MAXCOL * sizeof (int) количество байтов

Ответ 8

Мне очень не нравятся такие вопросы, потому что я считаю, что это лучше, чем рабочий инженер, чтобы экспериментировать, а не предполагать, что вы знаете, что вы делаете, особенно если есть подозрение, например, что программа работает не так, как ожидалось, или кто-то занимается трюком.

#include <stdlib.h>
#include <stdio.h>
#define MAXROW 3
#define MAXCOL 4

main()
{
  int (*p)[MAXCOL];
  int bytes = MAXROW * (sizeof(*p));
  p = (int (*)[MAXCOL]) malloc(bytes);
  printf("malloc called for %d bytes\n", bytes);
}

В 32-битной Linux-системе:

gcc test.c
. /a.out
malloc вызывается для 48 байт

(отредактировано, чтобы удалить вставку авария умножения на maxrow дважды, что дает ошибочный размер 144 байта)

Ответ 9

Выполнение следующих действий на codepad.org:

//#include<alloc.h>
#define MAXROW 3
#define MAXCOL 4

int main()
{
    int (*p)[MAXCOL];
    p = (int (*)[MAXCOL]) malloc(MAXROW*(sizeof(*p)));

    int x = MAXROW*(sizeof(*p));
    printf("%d", x);

    return 0;
}

выдает 48.

Почему? Поскольку MAXROW равно 3, а sizeof(*p) равно 16, мы получаем 3 * 16.

Почему sizeof(*p) 16? Потому что MAXCOL равно 4, поэтому p является указателем на массив из 4 целых чисел. Каждый int 32 бит = 4 байта. 4 ints в массиве * 4 байта = 16.

Почему sizeof(*p) не 4? Потому что это размер, на который указывает p, а не размер p. Чтобы быть размером p, он должен быть sizeof(p), который будет равен 4, поскольку p является указателем.

Педантично вы можете добавить:

  • Если машина 64 бит (скажем), ответ будет равен 96.
  • Как говорится в вопросе "Сколько байтов выделено в процессе?", вам нужно добавить 4 байта для указателя p.
  • malloc может выделять больше, чем вы запрашиваете (но не менее), поэтому на вопрос не может быть ответ.
  • В том же духе, что и 2, вы можете утверждать, что по мере того, как процесс также загружает системные DLL, такие как dll C runtime для запуска, он также выделяет пространство для них. Затем вы можете утверждать, что пространство, выделенное dll, которое впрыскивается в процесс другими (не системными) процессами, такими как те, которые были введены Actual Window Manager и его ilk. Но как педантично мы хотим получить?

Но я думаю, что вопрос действительно просят 48, с возможным дополнительным кредитом для объяснения 96.

Ответ 10

Как насчет нулевых байтов, потому что он даже не будет компилироваться без нестандартного alloc.h. Если вы не можете скомпилировать его, вы не сможете его запустить, и если вы не можете его запустить, он не сможет выделить какую-либо память.