2013-10-08 2 views
4

Это пример кода, который мой учитель показал нам о «Как динамически выделять массив в C?». Но я не совсем понимаю это. Вот код:Динамическое распределение массива объясняет

int k; 
int** test; 
printf("Enter a value for k: "); 
scanf("%d", &k); 
test = (int **)malloc(k * sizeof(int*)); 
for (i = 0; i < k; i++) { 
    test[i] = (int*)malloc(k * sizeof(int)); //Initialize all the values 
} 

Я думал, что в C, чтобы определить массив, который должен был поставить [] после имени, так что именно int** test; это не просто указатель на указатель? И линия malloc() также очень запутывает меня .....

+1

Я надеюсь, что ваш учитель также показал вам, как выделить multidimenional массив все естественно, как построить на язык, и Ждут» t покажу вам эту эмуляцию 2D как первого бита под подставные массивы и указатели. Но так или иначе он показывает вам код, на которого многие недовольны: в C вы не будете бросать возвращаемое значение 'malloc' и, во что бы то ни стало, вы не научили бы кого-либо использовать броски на таком раннем этапе понимания языка , –

ответ

9

В соответствии с декларацией int** test;, test - pointer to pointer и код, выделяющий память для матрицы значений int динамически с использованием функции malloc.

Заявление:

test = (int **)malloc(k * sizeof(int*)); 
    //    ^^------^^------- 
    // allocate for k int* values  

Выделяют продолжают память для k указателей на INT (int*). Поэтому предположит, если k = 4 то получает что-то вроде:

temp  343 347 351 355 
+----+ +----+----+----+----+ 
|343 |---►| ? | ? | ? | ? | 
+----+ +----+----+----+----+ 

Я предполагаю, что адрес из четырех байт и ? означает значение мусора.

temp переменный присвоенный возвращенный адрес malloc, malloc выделяет сохраняемые блоки памяти размера = k * sizeof(int**), что в моем примере = 16 байт.

В цикле for вы назначаете память для k int и присваиваете возвращенный адрес temp[i] (местоположение ранее выделенного массива).

test[i] = (int*)malloc(k * sizeof(int)); //Initialize all the values 
//      ^^-----^^---------- 
//  allocate for k int values  

Примечание: выражение temp[i] == *(temp + i). Таким образом, в течение цикла в каждой итерации вы выделить память для массива значений Int K, который выглядит, как показано ниже:

First malloc      For loop 
    ---------------     ------------------ 
     temp 
     +-----+ 
     | 343 |--+ 
     +-----+ | 
       ▼     201 205 209 213 
     +--------+    +-----+-----+-----+-----+ 
343 |  |= *(temp + 0) | ? | ? | ? | ? | //for i = 0 
     |temp[0] |-------|  +-----+-----+-----+-----+ 
     | 201 |  +-----------▲ 
     +--------+     502 506 510 514 
     |  |    +-----+-----+-----+-----+ 
347 |temp[1] |= *(temp + 1) | ? | ? | ? | ? | //for i = 1 
     | 502 |-------|  +-----+-----+-----+-----+ 
     +--------+  +-----------▲ 
     |  |     43 48 52 56 
351 | 43  |    +-----+-----+-----+-----+ 
     |temp[2] |= *(temp + 2) | ? | ? | ? | ? | //for i = 2 
     |  |-------|  +-----+-----+-----+-----+ 
     +--------+  +-----------▲ 
355 |  | 
     | 9002 |     9002 9006 9010 9014 
     |temp[3] |    +-----+-----+-----+-----+ 
     |  |= *(temp + 3) | ? | ? | ? | ? | //for i = 3 
     +--------+  |  +-----+-----+-----+-----+ 
         +-----------▲ 

Опять ? означает значение мусора.

Дополнительные пункты:

1) Вы литейная возвращается адрес, таНос, но в C следует избегать. Читайте Do I cast the result of malloc? просто сделайте следующее:

test = malloc(k* sizeof(int*)); 
for (i = 0; i < k; i++){ 
    test[i] = malloc(k * sizeof(int)); 
} 

2) Если вы выделения памяти динамически, вы должны освободить память явно, когда ваша работа с этим (после освобождения динамически распределяемой памяти, вы не можете получить доступ к этой памяти). Шаги к свободной памяти для test будут выглядеть следующим образом:

for (i = 0; i < k; i++){ 
    free(test[i]); 
} 
free(test); 

3) Это один способ выделения памяти для 2D-матрицы как массив массивов, если вы хотите выделить полностью продолжает памяти для всех массивов проверить этот ответ: Allocate memory 2d array in function C

4) Если описание помогает, и вы хотите узнать для 3D выделения Проверьте этот ответ: Matrix of String or/ 3D char array

+0

Добавление ссылки: [** 23.2: Динамическое распределение многомерных массивов **] (http://www.eskimo.com/~scs/cclass/int/sx9b.html) –

4

Помните, что массивы распадываются указателями и могут использоваться в качестве указателей. И эти указатели могут использоваться как массивы. Фактически, индексирование массива можно рассматривать как арифметику формы или указателя. Например

int a[3] = { 1, 2, 3 }; /* Define and initialize an array */ 
printf("a[1] = %d\n", a[1]); /* Use array indexing */ 
printf("*(a + 1) = %d\n", *(a + 1)); /* Use pointer arithmetic */ 

Оба выхода выше будет печатать второй (индекс 1) элемент в массиве.

То же самое верно и в отношении указателей, их можно использовать с арифметикой указателя или использовать с индексацией массива.

Из вышеперечисленного вы можете считать указателя на указатель-to.type в виде массива массивов. Но это не вся правда, поскольку они хранятся по-разному в памяти. Поэтому вы не можете передать массив массивов в качестве аргумента функции, которая ожидает указателя на указатель. Однако после инициализации вы можете использовать указатель на указатель с индексированием массива, как обычные указатели.

2

malloc используется для динамического выделения памяти в тестовую переменную, считая * как массив и ** в виде массива массивов, но вместо передачи по значению указатели используются для ссылки на адрес памяти переменной. Когда вызывается malloc, вы распределяете память на тестовую переменную, получая размер целого числа и умножая на количество ints, которое пользователь предоставляет, потому что это неизвестно до того, как пользователь вводит это.

2

Да, это нормально. test - указатель на указатель, поэтому test[i] который эквивалентен написанию test + i будет указателем. Для лучшего понимания, пожалуйста, взгляните на это c - FAQ.

2

Да, int** - указатель на указатель. Мы также можем сказать, что это массив указателей.

test = (int **) malloc(k * sizeof(int*)); 

Вначале будет выделен массив из k указателей. malloc динамически выделяет память.

test[i] = (int*) malloc(k * sizeof(int)); 

Это не является необходимым, поскольку это достаточно

test[i] = (int*) malloc(sizeof(int*)); 

Здесь мы выделяем каждый из мест массива, чтобы указать на действительную память. Однако для базовых типов, таких как int, такого рода распределение не имеет смысла. Это полезно для более крупных типов (структур).

Каждый указатель может быть доступен как массив, и наоборот, например, следующее эквивалентно.

int a; 
test[i] = &a; 
(test + i) = &a; 

Это может быть массив test в памяти, которая выделяется, начиная со смещения 0x10000000:

 
+------------+------------+ 
| OFFSET | POINTER | 
+------------+------------+ 
| 0x10000000 | 0x20000000 | test[0] 
+------------+------------+ 
| 0x10000004 | 0x30000000 | test[1] 
+------------+------------+ 
| ...  | ... 

Каждый элемент (в данном примере 0x2000000 и 0x30000000) являются указателями на другой выделенной памяти.

 
+------------+------------+ 
| OFFSET | VALUE | 
+------------+------------+ 
| 0x20000000 | 0x00000001 | *(test[0]) = 1 
+------------+------------+ 
| ... 
+------------+------------+ 
| 0x30000000 | 0x00000002 | *(test[1]) = 2 
+------------+------------+ 
| ... 

Каждое из значений содержит место только для sizeof (int).

В этом примере test[0][0] будет эквивалентен *(test[0]), однако test[0][1] недействителен, поскольку он будет иметь доступ к памяти, которая не была удалена.

2

Для каждого типа T существует тип «указатель на T».

Переменные могут быть объявлены как указатели на значения различных типов с помощью декларатора типа *. Чтобы объявить переменную как указатель, перед ее именем следует указать звездочку.

Следовательно, «для каждого типа T» также применимо к типам указателей, существует множество косвенных указателей, таких как char ** или int *** и т. Д. Там существует также «указатель на массив» типов, но они менее распространены, чем «массив указателя» (http://en.wikipedia.org/wiki/C_data_types)

так int** тест объявляет массив указателей, что указывает на «ИНТ массивы»

в строке test = (int **)malloc(k*sizeof(int*)); ставит достаточно памяти в сторону для к сумме (int*) 's

так что есть к количество указателей, каждый из которых указывает на ...

test[i] = (int*)malloc(k * sizeof(int)); (каждый указатель указывает на массив с размером к количество ints)

Резюме ...

int** test; состоит из K количества указателей, указывающих на каждый K количество Интс.

Смежные вопросы