Длина массива Dynami c, возвращаемого функцией - PullRequest
2 голосов
/ 20 апреля 2020

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

Итак, я определяю

typedef struct Pair {
    int* ptr;
    int length;
} Pair;

и измените функцию, чтобы она возвращала эту структуру. Это работает как задумано, хотя у меня есть проблемы. Я никогда не видел ничего подобного. Это правильный подход?

Ответы [ 2 ]

4 голосов
/ 20 апреля 2020

Это правильно в том смысле, что единственный способ, которым функция распределения может вернуть размер распределения, - это вернуть эту информацию. Хотя это не обычное и не привычное.

Обычно вызывающая сторона имеет некоторое представление о том, сколько элементов, вероятно, будет, и распределяет соответственно. Примеры включают scanf (3), массив совпавших выражений в regexe c (3) и буферный массив для readv (2). Эти функции передают размер массива и возвращают заполненное число.

Функции, которые распределяют массивы, встречаются относительно редко. Из тех, что есть в стандартной библиотеке, я не могу вспомнить ту, которая возвращает структуру, подобную вашей. Обычно либо указатель, либо счетчик возвращается по значению, а другой по ссылке. scandir (3), например, выделяет массив символьных указателей. Количество элементов - это возвращаемое значение функции. Расположение массива записывается в указатель, адрес которого передается в качестве аргумента (char ***).

Другой метод - не вернуть память, а вместо этого обеспечить итерацию и свободные функции. Примеры включают opendir (3) и getpwent (3).

Конечно, стандартная библиотека C была разработана в эпоху, когда функции C не могли возвращать целые структуры. Может быть, они бы выглядели иначе, если бы это было не так. Тем не менее, доминирующая идиома вызывающего абонента выделяет , предполагает, что вы, возможно, захотите тщательно подумать, действительно ли вам нравится ваша функция, как задумано.

3 голосов
/ 20 апреля 2020

Как вы заметили, ваш метод возврата структуры будет работать, и это безопасно. Является ли это «правильным» подходом, на самом деле вопрос мнения; Другой способ - вернуть массив и его размер в аргументах, заданных в виде указателей (фактически, указатель на указатель для самого массива):

int CreateArray(int** array, size_t* size)
{
    size_t n = 42; // Or whatever size is required.
    // .. Some code here that determines the 'n' value required
    int* data = malloc(sizeof(int) * n); // Create the array
    if (data != NULL) { // Success...
        *array = data; // Set first argument to POINT to the new array
        *size = n;     // and the second to point to its size
        return 1;      // Return "1" to indicate success
    }
    else { // Error: set size to zero and return "0" error code...
        *array = NULL;
        *size = 0;
        return 0;
    }
}

Затем можно вызвать эту функцию следующим образом:

int main()
{
    int* MyArray;
    size_t ArraySize;
    int status = CreateArray(&MyArray, &ArraySize); // Pass the ADDRESS of the pointer and of the size.
    if (!status) {
        // Error message, or whatever!
        return 1;
    }
    // You can now do stuff with MyArray, knowing that its size is in ArraySize
    //...
    free(MyArray); //Don't forget to free the memory when you're done with it!
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...