Функция в C может возвращать только одно значение. Тем не менее, что если нам надо получить из функции сразу несколько значений? В этом случае мы можем использовать разные подходы. Основные из них - возвращение комплексного объекта, который инкапсулирует отдельные значения, либо использование выходных параметров.
Наиболее простой способ возвратить из функции несколько значений - это определить структуру для хранения этих значений и возвратить ее. Например, нам надо получить из массива минимальное и максимальное значения. Для этого мы могли определить функцию, которая возвращает структуру с двумя значениями:
#include <stdio.h> #include <assert.h> typedef struct{ int min; int max; } MinMax; MinMax getMinMax(int* array, size_t length) { assert(length >1 && "Array length is invalid"); MinMax result; result.min = array[0]; result.max = array[0]; for(size_t i = 0; i < length; i++) { if(array[i] < result.min) result.min = array[i]; if(array[i] > result.max) result.max = array[i]; } return result; } int main(void) { int array[] = {2, 3, 4, 5, 6, 9}; size_t length = sizeof(array) / sizeof(int); MinMax data = getMinMax(array, length); printf("min=%d\n", data.min); // min=2 printf("max=%d\n", data.max); // max=9 }
Здесь для возвращения из функции минимального и максимального значения массива определена структура MinMax, которую возвращает функция getMinMax. Это наиболее простой и очевидный способ возвращения нескольких значений. Однако он имеет свои минусы. Прежде всего нам надо специально определять структуру под возвращаемые значения. Во-вторых, при возвращении структуры происходит копирование ее значений в стеке, что увеличивает объем потребляемой памяти.
Другой способ возвратить из функции несколько значений представляют выходные параметры (out-параметры). Язык Си как таковой не имеет концепции выходных параметров функции (как например, C#), однако мы можем симулировать выходные параметры с помощью указателей:
#include <stdio.h> #include <assert.h> void getMinMax(int* array, size_t length, int* min, int* max) { assert(length >1 && "Array length is invalid"); *min = array[0]; *max = array[0]; for(size_t i = 0; i < length; i++) { if(array[i] < *min) *min = array[i]; if(array[i] > *max) *max = array[i]; } } int main(void) { int array[] = {7, 3, 4, 5, 6, 8}; size_t length = sizeof(array) / sizeof(int); int minVal = 0; int maxVal = 0; getMinMax(array, length, &minVal, &maxVal); printf("min=%d\n", minVal); printf("max=%d\n", maxVal); }
Общий механизм определения и передачи выходных параметров заключается в следующем. Во-первых, определяем в функции параметры-указатели:
void getMinMax(int* array, size_t length, int* min, int* max)
Здесь параметры-указатели min и max как представляют выходные параметры. Внутри функции нам не важны их начальные значения. Наоборот, функция устанавливает их значения.
При вызове функции определяются переменные, и их адреса передаются выходным параметрам:
int minVal = 0; int maxVal = 0; getMinMax(array, length, &minVal, &maxVal);
В данном случае выходным параметрам min и max передаются соответственно адреса переменных minVal и maxVal.
При использовании выходных параметров нам не обязательно определять дополнительные структуры. Мы избегаем изличнего копирования возвращаемых значений в стеке. Однако выходные параметры рахдувают определение функции, могут снизить ее читабельность, особенно когда таких параметров много.