Функция, возвращающая указатель на массив

Мне удалось работать с массивами переменной длины вC и теперь у меня есть следующее:

#include <stdio.h>
#include <stdlib.h>

int (*foo(size_t row, size_t col))[3];

int main(void){
    size_t row, col;


    printf("Give the ROW: ");
    if ( scanf("%zu",&row) != 1){
        printf("Error, scanf ROW\n");
        exit(1);
    }

    printf("Give the COL: ");
    if ( scanf("%zu",&col) != 1){
        printf("Error, scanf COL\n");
        exit(2);
    }

    int (*arr)[col] = foo(row, col);

    for ( size_t i = 0; i < row; i++){
        for( size_t j = 0; j < col; j++){
            printf("%d ",*(*(arr+i)+j));
        }
    }

    free(arr);
}


int (*foo(size_t row, size_t col))[3]{
    int (*arr)[col] = malloc(row * col * sizeof(int));
    int l=0;

    if (arr == NULL){
        printf("Error, malloc\n");
        exit(3);
    }

    for ( size_t i = 0; i < row; i++){
        for( size_t j = 0; j < col; j++){
            *(*(arr+i)+j) = l;
            l++;
        }
    }

    return arr;
}

Выход:

Give the ROW: 2
Give the COL: 5
0 1 2 3 4 5 6 7 8 9

Теперь это:

int (*foo(size_t row, size_t col))[3]{ /* code */ }

означает, если я правильно понял, что объявляет foo как функцию с двумя параметрами (size_t row, size_t col), которая возвращает указатель на массив 3 из int.

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

Любой способ здесьint (*foo(size_t row, size_t col))[3] У меня есть [3], который мне не совсем понятен о том, как это работает и как я могу сделать это возможным во время выполнения (конечно, только если это возможно), что-то вродеint (*foo(size_t row, size_t col))[SIZE].

Я прочитал несколько книг оC, но нет точных объяснений этой ситуации, и Google тоже не помогает, поэтому у меня есть два вопроса:

1) это возможноint (*foo(size_t row, size_t col))[SIZE] где РАЗМЕР должен быть параметром? Или я должен объявить эту функцию по-другому?

2) это правильный путь для того, что я здесь пробовал, или есть другая альтернатива?

Я только пытаюсь вернуть указатель на массив, размер которого известен во время выполнения, а не во время компиляции. Зовmalloc а такжеfree происходит только один раз, и это хороший подход, потому что всякий раз, когдаmalloc наша программа мешает ядру выделить память и пометить страницу как доступную для записи. Так что у этого метода меньше накладных расходовkernel, Это может быть написано в одномmalloc работа с VLA

РЕДАКТИРОВАТЬ:

@ChronoKitsune сказал, что я должен использовать / попробовать[] (массив неопределенного размера), в этом случае функция станет такой:

int (*foo(size_t row, size_t col))[]{ /* code */ }

Это то, что я должен использовать?

 Michi27 мая 2016 г., 20:11
@ChronoKitsune у меня уже естьЭто решение, но это не то, что мне нужно.
 Michi27 мая 2016 г., 20:36
@ ChronoKitsune Это означает, что в моем случае это нормально.
 Michi27 мая 2016 г., 20:09
@ChronoKitsune Я попробовал это, но я не был уверен, что это нормально, отсюда и вопрос. Я мог бы также напечатать [0]. :) 2) мне нужен этот синтаксисint (*arr)[col]
 user53981027 мая 2016 г., 20:32
Синтаксис[] формально обозначаетмассив неполного типа (C11 раздел 6.7.6.2p4). Возврат указателя на этот массив разрешен. Однако вы не можете разыменовать этот указатель, пока указатель не будет присвоен массиву с полным типом. Например, если вы объявилиint (*arr)[] = foo(row, col); тогда ты не мог сделать*arr или жеarr[...] совсем.int (*arr)[col] = foo(row, col); разрешено, и вы можете успешно использовать указатель по желанию, потому чтоint (*arr)[col] указатель на полный тип
 user53981027 мая 2016 г., 20:05
1) нет, но попробуйте[] (массив неопределенного размера). 2) Да, у вас правильный синтаксис. Наиболее эквивалентной альтернативой будет просто вернуть нормальный указатель. Затем вы либо объявитеarr какint *arr = foo(row, col); и использовать его какarr[i * col + j] (или же*(arr + i * col + j)), или вы приведете возвращаемое значение к объявлениюarr как вint (*arr)[col] = (int (*)[col])foo(row, col); быть в состоянии использоватьarr[i][j] (или же*(*(arr + i) + j) так как вы предпочитаете использовать нотацию указателя, а не более читаемый эквивалент, используя нотацию массива).

Ответы на вопрос(1)

Решение Вопроса

int (*foo(size_t row, size_t col))[3] у меня есть это[3] который мне не понятно, как это работает

Объявления типов легче всего прочитать изнутри. Я начну с простого и приведу пример к вашему. Если ты пишешь

int foo[3];

или же

int (foo)[3];

вы декларируетеfoo как массив из 3ints. Здесь круглые скобки служат для функции группирования приоритетов, как в выражениях, но они не нужны, потому что тип интерпретируется одинаково в обоих случаях.

Если ты пишешь

int (*foo)[3];

вы декларируетеfoo бытьуказатель в массив из 3ints. Эквивалентно, вы можете прочитать это как сказать, что вещьfoo указывает на массив из 3intс, будучи неявным, чтоfoo это указатель В этом случае скобки необходимы; без них вы бы объявилиfoo как массив из 3int *.

Если ты пишешь

int (*foo(size_t row, size_t col))[3];

Вы заявляете, чтоfoo это функция, принимающая два аргумента типаsize_t, чье возвращаемое значение указывает на массив 3ints.

и как я могу сделать это возможным во время выполнения (конечно, только если это возможно), что-то вродеint (*foo(size_t row, size_t col))[SIZE].

ЕслиSIZE не является константой времени компиляции, тогда вы не можете этого сделать. C2011 считает, что

Если идентификатор объявлен как имеющий изменяемый тип, он не должен иметь [...] связи и иметь либо область видимости блока, либо область видимости прототипа функции. [...]

(6.7.6.2/2)

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

Обычно в таких случаях возвращается указатель на первый элемент массива, а не указатель на весь массив. Указанный адрес в любом случае одинаков, но тип отличается:

int *foo(size_t row, size_t col);

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

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

Обновить:

Также возможно объявить вашу функцию, чтобы она возвращала указатель на массив неопределенного размера, как предложено @ChronoKitsune. Синтаксис будет

int (*bar(size_t row, size_t col))[];

, но вы обнаружите, что этот тип возврата труднее использовать практически во всех отношениях. Например, объявить переменные, которые могут содержать возвращаемое значение, сложнее и уродливее:

int (*array_ptr)[] = bar(x, y);

и получить доступ к элементам указанного массива:

int z = (*array_ptr)[1];

Сравните это с

int *ptr = foo(x, y);
int w = ptr[2];
 Michi27 мая 2016 г., 20:34
Спасибо, мне нужно было знать, законно ли это. Пожалуйста, предоставьте это вам. Ответ.
 John Bollinger27 мая 2016 г., 20:33
@Michi, да, твой пример IdeaOne - это то, что я описывал. Да, вы можете использовать[] форма, предложенная ChronoKitsune, но я думаю, вам будет сложнее работать практически во всех отношениях.
 Michi27 мая 2016 г., 20:20
Вы имеете в виду что-то вродеэто если это не то, что мне нужно, если нет, не могли бы вы предоставить мнеDEMO где у меня есть указатель на массив в основной функции и функции, которая делает это?
 Michi27 мая 2016 г., 20:23
Или можно просто использовать (как @ChronoKitsune указатель) это[] (массив неопределенного размера) ==>int (*func(size_t row, size_t col))[]; ?

Ваш ответ на вопрос