Проблема выделения памяти - PullRequest
13 голосов
/ 09 декабря 2010

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

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

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

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

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

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

Ответы [ 10 ]

8 голосов
/ 09 декабря 2010

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

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

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

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

7 голосов
/ 09 декабря 2010

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

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

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

6 голосов
/ 09 декабря 2010

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

5 голосов
/ 09 декабря 2010
#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*. На практике, вероятно, что наименьший размер (int) байтов из указателя переживет преобразование, и если sizeof (void *) окажется равным sizeof (int) или, что еще более незначительно, то начнется кучи памяти по адресу, представленному в int, несмотря на то, что размер указателей больше (т. е. все усеченные биты были равны нулю в любом случае), тогда последующая разыменование указателя может сработать. Дешевый плагин: C ++ не скомпилируется, пока не увидит прототип.

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

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

3 голосов
/ 09 декабря 2010

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

#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 байта)

3 голосов
/ 09 декабря 2010

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

3 голосов
/ 09 декабря 2010

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"
Скобки имеют большое значение!

1 голос
/ 09 декабря 2010

Выполнение следующего в 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 массива в массиве * 4 байта = 16.

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

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

  1. Если машина 64-битная (скажем), ответ будет 96.
  2. Поскольку вопрос гласит «Сколько байтов выделено в процессе?», Вам нужно добавить 4 байта для указателя p.
  3. malloc может выделить больше, чем вы просите (но не меньше), поэтому на вопрос нельзя ответить.
  4. Аналогично 2, вы можете утверждать, что, поскольку процесс также загружает системные dll, такие как dll времени выполнения C, для выполнения, он также выделяет пространство для них. Тогда вы могли бы поспорить за место, выделенное dll, которое вводится в процесс другими (не системными) процессами, такими как те, что вводятся Actual Window Manager и его аналогами. Но какой педантизм мы хотим получить?

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

0 голосов
/ 09 декабря 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...