2D массивы и указатели - C - PullRequest
       1

2D массивы и указатели - C

3 голосов
/ 08 октября 2010

Просто пытаюсь по-настоящему разобраться с массивами и указателями в C и различиями между ними, и у меня возникли проблемы с двумерными массивами.

Для обычного 1D массива это то, что я выучил:

char arr[] = "String constant";

создает массив символов, а переменная arr всегда будет представлять память, созданную при ее инициализации.

char *arr = "String constant";

создает указатель на char, который в данный момент указывает на первый индекс массива char "String constant". Указатель может указывать куда-нибудь еще позже.

char *point_arr[] = {
    "one", "two","three", "four"
};

создает массив указателей, которые затем указывают на массивы символов "один, два" и т. Д.

Мой вопрос

Если мы можем использовать оба:

char *arr = "constant";

и

char arr[] = "constant";

тогда почему я не могу использовать:

char **pointer_arr = {
    "one", "two", "three", "four"
};

вместо

char *pointer_arr[] = {
    "one", "two", "three", "four"
};

Если я попробую char **, я получу ошибку типа «лишние элементы в скалярном инициализаторе» Я могу заставить работать пример char**, выделив память с помощью calloc, но мне не пришлось делать это с char *arr = "blah";. Я не понимаю, почему это необходимо, и поэтому я не понимаю разницу между:

char **arr_pointer;

и

char *arr_pointer[];

Заранее большое спасибо за совет.

Ответы [ 5 ]

5 голосов
/ 08 октября 2010

См. этот ответ в C FAQ :

Там это объясняется для char [] против char *. То же самое можно расширить до char *[] против char **.

3 голосов
/ 08 октября 2010

Короче говоря, вы не можете использовать { ... } в качестве инициатора для скаляра.

char **arr_pointer объявляет скаляр, а не массив. Напротив, причина, по которой вы можете сделать char *arr = "constant";, заключается в том, что вы все еще объявляете скаляр, просто он указывает на строковый литерал.

1 голос
/ 08 октября 2010

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

int * ptr [] - это массив указателей на целые числа, где int ** ptr - указатель на указатель, который ссылается на целое число.

int * arrptrs [2];
arrptrs [0] = (int *) malloc (sizeof (int) * 5);
arrptrs [1] = (int *) malloc (sizeof(int) 5);
Инициализирует два массива, на которые ссылаются элементы массива arrptrs.Имя массива относится к ячейке памяти первого элемента массива, поэтому arrptrs имеет тип (int *
), поскольку первый элемент этого массива имеет тип (int *)

Предположим, чтомы делаем int ** ptr = arrptrs. Тогда * ptr - это первый элемент arrptrs, это arrptrs [0], а * (ptr + 1) - это arrptrs [1], а выполнение * arrptrs [0] - это первый элемент вмассив, на который ссылается arrptrs [0].

Надеюсь, это поможет, хотя я не уверен, что вам это нужно.

0 голосов
/ 08 октября 2010

Цитата из Википедии:

В вычислениях скалярная переменная или поле - это переменная, которая может содержать только одно значение за раз ... ... Например, char, int, float и double являются наиболее распространенными скалярными типами данных в C-программировании. язык.

Так, как указал в своем ответе Оли Чарльзуорт, используя {.....}, он инициализирует несколько элементов, но так как char ** arr_pointer является «скалярным» и поэтому может указывать только на одну вещь за раз (адрес), то {...} запись не может работать здесь.

0 голосов
/ 08 октября 2010

Указатели (char *pointer;) имеют значения; массивы (char array[];) имеют элементы.

Объявление char **ptr2 объявляет объект, который может принимать одно значение, а не объект, который может принимать несколько элементов.

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