Несколько беспокойств по поводу указателя - PullRequest
0 голосов
/ 24 августа 2018

Я прочитал несколько тем об указателях на веб-сайтах и ​​PDF в Интернете. Но есть много вещей, которые я не могу до конца понять до сих пор:

В PDF было написано, что двумерный массив, имеющий 10 строк и 20 столбцов, может быть объявлен как int (*ary)[20] вместо int array[10][20]

Они объясняют:

"ary определяется как указатель на группу смежных, одномерные 20-элементные целочисленные массивы. "

На многих веб-сайтах в Интернете они просто говорят, что int (*ary)[20] является объявлением для указателя, который указывает на массив из 20 целых чисел.

Ответы [ 5 ]

0 голосов
/ 24 августа 2018

int array[10][20] - это массив из 10 элементов, каждый элемент - это массив из 20 целых чисел.Или, если хотите: это двумерный массив 10x20 int.

int (*ptr)[20] - указатель массива на массив из 20 целых чисел.Он не выделяет никакой памяти для массива, но может указывать на единицу.

Если вы пишете

int array[10][20];
int (*ptr)[20] = array;

, то array "разлагается" в указатель на первый элемент.Первый элемент int [10][20] - это int[20]int (*ptr)[20] - указатель на такой элемент, так что это нормально.

Возможно, вы путаете это для динамического выделения 2D-массива, что можно сделать так:

int (*ptr)[20] = malloc( sizeof(int[10][20]) );

Здесь ptr указывает на первый элемент (int[20]) массива int[10][20].

0 голосов
/ 24 августа 2018

Вы просто должны учитывать, что ary является указателем на его первый элемент .Помните, что синтаксис ary[index] эквивалентен *(ary + index), он поможет вам понять, как он работает.

0 голосов
/ 24 августа 2018

Это массивы:

int a[10];
int b[10][20];

Это указатели:

int *p1;
int (*p2)[20];

Они разные.Они не одинаковы.

Однако, даже если они разные, вы можете сделать это:

p1 = a;
p2 = b;

Теперь p1 указывает на a и p2 указываетв b.

Когда вы сказали p1 = a, это была стенография.Как будто вы написали

p1 = &a[0];

Строго говоря, p1 указывает на первый элемент a.Точно так же p2 = b подобен p2 = &b[0] и делает точку p2 на первом элементе b.Однако, поскольку b - это массив массивов, первый элемент b - это массив из 20 дюймов.

Кроме того, если вы передаете a и b функции, например, так:

f(a, b);

как должно выглядеть определение функции?Оказывается, есть два способа взглянуть на это.Вы можете объявить

void f(int a[], int b[20][]) { ... }

, что делает параметры f похожими на то, что, по вашему мнению, вы передаете.Но оказывается, что на самом деле передаются указатели, поэтому f также может быть объявлено следующим образом:

void f(int *a, int (*b)[20]) { ... }

В любом случае, именно поэтому на этой странице вы предполагали, что междумассив int a[10][20] и указатель int (*p2)[20].Существует «какая-то эквивалентность», но это не значит, что они одного типа.(Вовсе нет. По этой причине большинство людей предпочитают больше не использовать слово «эквивалентность» в этом контексте.)

0 голосов
/ 24 августа 2018

декларации

int (*ary)[20];

и

int ary[10][20];

очень разные. Первый действительно объявляет указатель на массив из 20 int элементов. Второй объявляет массив из 10 массивов из 20 int элементов.


Следует помнить, что массив естественным образом распадается на указатель на свой первый элемент.

Для простого массива, подобного

int simple_array[10];

, затем использование простого simple_array в выражении аналогично &simple_array[0], а тип выражения - int *.

Теперь для массива массивов

int complex_array[10][20];

если вы используете complex_array в выражении, оно все еще приводит к указателю на его первый элемент, то есть &complex_array[0]. Теперь разница составляет тип выражения: &complex_array[0] (или простой эквивалент complex_array) равен int (*)[20].

С помощью этой информации вы можете легко создать указатель на complex_array и указать ему первый элемент complex_array:

int (*complex_array_pointer)[20];

// Make complex_array_pointer point to the first element of complex_array
// i.e. make complex_array_pointer point to complex_array[0]
complex_array_pointer = complex_array;
0 голосов
/ 24 августа 2018

Главное, чтобы понять, что C не имеет ничего, кроме одномерных массивов. Да, двумерные массивы (например, матрицы) на самом деле не существуют в C.

Однако массив имеет элементы одинакового размера (как указано sizeof) и типа. Таким образом, вы можете иметь массивы чисел, массивы указателей, массивы struct -s и даже массивы массивов (например, целых чисел).

Таким образом, злоупотребляя, вы можете сказать, что массив массивов является матрицей (поэтому некоторые люди утверждают, что двумерные массивы существуют в C. Я чувствую, что это преувеличение). Но это (например, что-то объявленное как int a[10][20];) действительно сохраняет одномерный массив (из 10 элементов каждый является массивом) из одномерных массивов (из 20 целых чисел). И во многих случаях полезен массив указателей (например, массивы «строк»).

Интересной особенностью в C99 (или более поздней версии) является гибкий элемент массива s. При этом вы можете грамотно определить свой собственный Matrix абстрактный тип данных , используемый как непрозрачный указатель (см. этот ответ для некоторого кода).

Во многих случаях (особенно когда вы присваиваете массив - по праву присваивания - некоторому lvalue, например, переменной, или передаете массив в качестве аргумента некоторой функции), массивы распадаются на указатели. Но их sizeof и тип разные.

Посмотрите на некоторый C эталонный сайт (и намного позже, на стандарт n1570 C, например, §6.5.2.1 Подписка на массив ). Читать Как отлаживать небольшие программы

Кстати, так называемые двумерные массивы в C, такие как int a[10][20];, редко нужны в C (если вы не специализируетесь на численных вычислениях на матрицах фиксированных измерений, известных во время компиляции; я полагаю, что разработчики игр может использовать тип как typedef double transform3Dmatrix_ty[3][3]; довольно часто). За более чем 30-летний опыт программирования я почти никогда не использовал 2D-массивы.

Я не претендую на то, чтобы научить вас С в нескольких параграфах. Вы найдете много хороших книг (и несколько очень плохих).

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