В правильном контексте (а именно, в аргументах функции) следующие объявления эквивалентны:
int main(int argc, char *argv[]);
int main(int argc, char **argv);
int main(int argc, char *argv[12]); // Very aconventional!
Аналогичные комментарии применяются к определениям функций (в которых вместо фигурных скобок есть блокточка с запятой).
В любом другом контексте существуют важные различия между обозначениями.Например:
extern char *list1[];
extern char **list2;
extern char *list3[12];
Первый говорит, что где-то есть массив неопределенного размера, содержащий значения 'char *'.Второе говорит, что где-то - возможно, здесь - есть единственное значение, содержащее указатель на указатель на символ.Третий говорит, что где-то - возможно, здесь - есть массив из 12 символьных указателей.
Однако на все три списка можно ссылаться примерно одинаково - при условии, что они на самом деле были определены и инициализированы.
list1[0][0] = '1';
list2[0][0] = '2';
list3[0][0] = '3';
Далее, если они передаются в функцию, подобную этой:
function(list1, list2, list3);
, тогда функция может быть объявлена как:
void function(char **list1, char **list2, char **list3);
Массивы (list1, list3) распад из массива на указатель на первый элемент массива;list2, конечно, уже является указателем на указатель.
Одна деталь, которую следует отметить в функции, такой как:
void otherfunction(char *list[12])
{
...
}
Компилятор C не обрабатывает это объявление иначе, чем:
void otherfunction(char **list)
{
...
}
или
void otherfunction(char *list[])
{
...
}
В частности, он не проверяет границы массива, а что касается функции, то 12 также может отсутствовать.
C99 представляет типы VLA (массив переменной длины), а также вводит нотацию с «static» и размером в границах массива.Вам необходимо прочитать стандарт, чтобы понять их полностью.
Достаточно сказать, что в функции, подобной следующей, размер массива имеет значение и определяется во время выполнения.В целом для двумерных массивов необходимо указывать все размеры, кроме первого.
void vla_function(size_t m, int vla[m][m]);
Цитирование из стандарта (раздел 6.7.5.3):
void f(double (* restrict a)[5]);
void f(double a[restrict][5]);
void f(double a[restrict 3][5]);
void f(double a[restrict static 3][5]);
(Обратите внимание, что в последнем объявлении также указывается, что аргумент, соответствующий a в любом вызове f, должен быть ненулевым указателем на первый из как минимум трех массивов по 5 двойных, чего нет у других.)