Разница между статическими и динамическими объявлениями 2D массивов - PullRequest
0 голосов
/ 09 октября 2018

Это две разные программы для объявления 2D-массива

1) Я думаю, что они одинаковы, потому что оба 2D-массива?

2) можем ли мы получить доступ как к [i] [j], так и к p [i] [j]?

3) Почему *a или a одинаковы и p или *p разные

#include<stdio.h>
#include<stdlib.h>
int main(){
   int a[100][100];
   printf("%d\n",a);
   printf("%d\n",*a);


   int **p=malloc(sizeof(int*)*100);
   for(int i=0;i<100;i++){
     p[i]=malloc(sizeof(int)*100);
   }
   printf("%d",p);
   printf("%d",*p);

   }

Ответы [ 3 ]

0 голосов
/ 09 октября 2018

большая разница в том, что в случае a[100][100] компилятор знает полный размер массива и выделяет непрерывную область памяти в стеке (как в вашем случае) или в статической области.При доступе к элементу массива компилятор может рассчитать его адрес на основе измерений массива и использовать одну ссылку для доступа к нему.как это

[0,0][0,1][0,2]...[0,99][1,0][1,1][1,2]...[99,0]...[99,99]
+-------0------...-----+----- 1 -------...+----- 99 -----+

В случае динамического выделения, которое вы использовали, память выделяется непрерывно только для одного измерения массива.Итак, вы выделяете 100 указателей, каждый из которых указывает на одномерный массив целых чисел.Эти массивы могут быть размещены в произвольных местах памяти.В результате компилятор должен сделать как минимум 2 ссылки в этом случае, использовать первый индекс для получения указателя на второй массив, а затем использовать второй индекс для получения элемента во втором массиве.

pointers[index0] : [0][1][2]..[99]
                    /  |  \
                   /   |   |
                   V   V   V
                  [0] [0] [0]     
                  [1] [1] [1]
                  ... ... ...

некоторые дополнения о a и *a.В 'c', когда имя массива используется в контексте, аналогичном указателю, оно интерпретируется как адрес массива.Итак, в printf a указывает на начало двумерного массива.*a по той же причине должен предоставить вам адрес первого столбца.Который в этом случае совпадает с началом или массивом.**a укажет вам на самый первый элемент массива a[0][0].И, кстати, для указателей лучше использовать %p вместо %d.

Вы можете видеть, что для динамического массива p дает вам адрес массива указателей, будь то*p дает значение первого элемента p[0], который сам по себе является указателем на столбец.Адреса определенно разные.

Но в обоих случаях вы можете использовать a[i][j] и p[i][j] для доступа к элементам массива.

0 голосов
/ 09 октября 2018

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

Если вы хотите иметь фактический 2D-массив в динамическом хранилище, вот как вы это делаете:

#include <stdlib.h>

int main()
{
    int (*m)[100][100];

    m = malloc(sizeof *m);
    for (int i = 0; i < 100; i++)
        for (int j = 0; j < 100; j++)
            (*m)[i][j] = 0;
}

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

Причина, по которой a и *a дают один и тот же вывод, заключается в том, что оба они затухают в указателе на первый элемент a, который равен a[0][0].С другой стороны, p - это сам указатель, а *p - это содержимое переменной, на которую указывает p.Они такие же разные, какими они были бы, если бы вы сделали это:

int d = 0;
int *p = &d;
printf("%p\n", p);
printf("%d\n", *p);

Теперь вернемся к вашему int **p.

Да, вы можете получить доступ к int a[][100] и int **pс двойной индексацией.Однако существует принципиальное различие в способах обработки компилятором a[i][j] и p[i][j].

В a[i][j] каждый a[i] представляет собой массив из 100 целочисленных объектов.Таким образом, чтобы получить доступ к i -ому элементу, а затем к j -ому элементу, компилятор должен получить доступ к i*100+j -ому элементу из a[0][0].Этот доступ может быть выполнен за один шаг с некоторой индексной арифметикой.

В v[i][j] каждый v[i] является указателем, который может указывать на объекты, удаленные друг от друга в памяти.Чтобы получить доступ к элементу v[i][j], компилятор должен сначала следовать p к массиву *p, а затем найти i -й элемент в этом массиве, который является указателем на массив p[i].И затем с некоторой арифметикой указателя он найдет j -й элемент этого массива.

0 голосов
/ 09 октября 2018

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

Для простоты отладки большинство операционных систем устанавливают для памяти некоторое преднамеренное фиксированное значение.Unix обычно устанавливает память malloc () на ноль.Windows имеет диапазон содержимого по умолчанию в зависимости от того, как была выделена память, см .: Когда и почему ОС инициализирует память в 0xCD, 0xDD и т. Д. При malloc / free / new / delete?

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