Когда int (* aaa)[3];
появляется вне какой-либо функции, он aaa
автоматически инициализируется нулевым указателем. Когда он появляется внутри функции, он не инициализируется.
Код aaa = pass(aaa);
передает aaa
подпрограмме с именем pass
. Это использование значения aaa
. Когда aaa
был инициализирован, это нормально. Но когда aaa
не инициализирован и вы пытаетесь передать его значение, поведение не определяется стандартом C. Это то, о чем вас предупреждает компилятор.
Затем давайте рассмотрим этот код:
int* pass(int (*a)[3]) {
a=(int*)malloc(sizeof(int*)*2);
a[0][1] = 1;
a[0][2] = 2;
return a;
}
Этот код никогда не использует значение a
, которое ему передается. Когда функция вызывается, ее параметру, в данном случае a
, присваивается значение (которое получается из аргумента, переданного вызывающей стороной). Этот параметр является отдельной переменной от аргумента. Присвоение a
значения с помощью a=(int*)malloc(sizeof(int*)*2);
не изменяет значение aaa
в вызывающей подпрограмме. Таким образом, этот код присваивает новое значение a
без использования старого значения.
По этой причине подпрограмме не требуется передавать параметр. Вместо этого можно было бы написать для использования локальной переменной, например:
int (*pass(void))[3] {
int (*a)[3] = malloc(2 * sizeof *a);
a[0][1] = 1;
a[0][2] = 2;
return a;
}
void
в этом случае означает, что pass
не принимает никаких аргументов.
Обратите внимание, что я изменил * С 1031 * на malloc(2 * sizeof *a)
. sizeof(int*)*2
неверно, потому что он запрашивает место для двух указателей на int
. Но a
указывает на массивы из трех int
, поэтому, чтобы получить два из них, вам нужно место для двух массивов из трех int
. Это 2 * sizeof(int [3])
. Однако проще записать это как malloc(2 * sizeof *a)
, что означает «два из того, на что указывает a
». Это также лучше, потому что снижает частоту, с которой совершаются ошибки: даже если объявление a
изменено, это sizeof *a
будет автоматически корректироваться без необходимости редактирования. С sizeof(int [3])
любое редактирование объявления a
потребует другого редактирования sizeof
.
Кроме того, я удалил (int*)
, чтобы привести результат malloc
. В C void *
, который является типом, возвращаемым malloc
, будет автоматически преобразован в любой тип указателя объекта, которому он назначен. Нет необходимости в явном приведении, а использование явного приведения может замаскировать определенные ошибки. (Однако, если вы скомпилируете программу с помощью компилятора C ++, он будет жаловаться на отсутствие преобразования, потому что правила в C ++ другие.)
Поскольку функция возвращает указатель на массив из трех int
, а не указатель на int
, я изменил его объявление на int (*pass(void))[3]
.
С этими изменениями программа могла быть:
#include <stdio.h>
#include <stdlib.h>
int (*pass(void))[3]
{
int (*a)[3] = malloc(2 * sizeof *a);
a[0][1] = 1;
a[0][2] = 2;
return a;
}
int main(void)
{
int (*aaa)[3] = pass();
printf("%d\n", aaa[0][2]);
}