Сложные определения языка

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



Сложные определения

В си часто могут появляться сложные определения, состоящие из указателей на массивы, указатели на функции, указатели на функции возвращающие указатели на указатели на функции и т.п. В большинстве случаев такие проблемы разрешаются определением нового типа (с помощью typedef).

Самый простой случай – массивы.

int *a;
Указатель, или массив.
int (*a)[10];
Указатель на массив из десяти элементов типа int
int (*a)();
Указатель на функцию, которая возвращает переменную типа int и не принимает никаких аргументов.
int (*a)(int*);
Указатель на функцию, которая принимает указатель на int и возвращает переменную типа int.
int* (*a)(double *);
Указатель на функцию, возвращающую указатель на int и принимающую в качестве аргумента указатель на double.
int* (**a)(float);
Указатель на указатель на функцию, принимающую в качестве аргумента переменную типа float и возвращающую указатель на int. Он может хранить адрес динамически созданного массива указателей на функцию.
double (*a[10])(int, int, int);
Массив указателей на функцию, принимающую три параметра типа int и возвращающую значение типа double.
int* bar(int (*f)(void));
Функция, которая принимает в качестве аргумента указатель на функцию, возвращающую int и не получающую никаких аргументов. Сама функция bar возвращает указатель на int.
int* (*b)(int (void))
Указатель на такую функцию.
float bar2(int *(f)(int (void))) {...
Функция, принимающая в качестве аргумента функцию, возвращающую указатель на int и принимающую в качестве аргумента функцию, возвращающую int, у которой нет аргументов. Сама функция возвращает значение типа float.
float (*b2)(int* (int (void)));
Указатель на такую функцию. Функция, возвращающая значение типа int и указатель на неё с вызовом.
int foo() {
	return 3;
}

int (*p)(void) = foo;
printf("%d\n", p());
Функция, которая возвращает функцию, которая возвращает int и принимает в качестве аргумента указатель на float, вместе с указателем на неё и вызовом.
int (*foo3())(float*) {
	return foo2;
}

int (*(*p3)(void))(float*) = foo3;
printf("%d\n", p3()(&a));
Функция, которая возвращает функцию, у которой нет параметров, которая возвращает функцию, возвращающую int и принимающую указатель на float, вместе с указателем на неё и вызовом.
int (*(*foo4())(void))(float*) {
	return foo3;
}

int (*(*(*p4)(void))(void))(float*) = foo4;
printf("%d\n", p4()()(&a));
Функция, принимающая значение типа char и возвращающая функцию, которая не имеет аргументов и возвращает функцию, которая не имеет аргументов и возвращает функцию, которая принимает аргумент типа *float и возвращает int, вместе с указателем на неё и вызовом.
int (*(*(*foo5(char letter))(void))(void))(float*) {
	printf("inside foo5 got %c\n", letter);
	return foo4;
}

int (*(*(*(*p5)(char))(void))(void))(float*) = foo5;
printf("%d\n", p5('A')()()(&a));
Функция, которая возвращает указатель на функцию, принимающую char и возвращающую функцию, которая не имеет параметров и возвращает функцию, которая не имеет параметров и возвращает функцию, которая принимает указатель на float и возвращает int.
int (*(*(*(*foo6(double *x))(char))(void))(void))(float*) {
	printf("inside foo6 got %.3f\n", *x);
	return foo5;
}

int (*(*(*(*(*p6)(double*))(char))(void))(void))(float*) = foo6;
printf("%d\n", p6(&d)('B')()()(&a));
Функция, которая возвращает указатель на функцию, возвращающую int и принимающую указатель на float и принимающая в качестве аргумента функцию, возвращающую int без параметров, с указателем на неё и вызовом.
int (*foobar (int (*f)(void)))(float*) {
	printf("inside foobar %d\n", f());
	return foo2;
}


int (*(*fb)(int (void)))(float*) = foobar;
printf("%d\n", foobar(foo)(&a));
Такие сложные определения трудно разбираются и приводят к куче ошибок, поэтому их заменяют на типы данных. Например
int foo2(float *b) {
	return (int)(*b);
}

int (*p2)(float*) = foo2;
Могут быть заменены на
typedef int (*foo_type)(float *);

foo_type p2a = foo2;
Далее, можно определить новый тип на основе заданного ранее
typedef foo_type (*foo_foo_type)();
Это указатель на функцию без параметров, которая возвращает foo_type, то есть указатель на функцию, которая возвращает int и принимает в качестве параметра переменную типа float*. И использовать указатель вида
foo_foo_type p3a = foo3;
Q&A

Всё ещё не понятно? – пиши вопросы на ящик email
Работа с бинарными файлами