Как вернуть массив из функции A, а затем функция B принимает этот массив - PullRequest
0 голосов
/ 03 января 2019

У меня есть две функции в моей основной функции.

Я пытался решить эту проблему с указателями, но как новичок, с этим очень сложно работать.

int main(){
  int *p;

  p = function_A();
  function_B(p);

  return 0; 
}

int function_A(){
  static int myArray[3];
  myArray[0] = 11;
  myArray[1] = 22;
  myArray[2] = 33;

  return myArray;
}

int function_B(int *myPointer){
  // Here I just want to print my array I've got from function_A() to the 
  // console

  printf("%d", *myPointer)
  return 0;
}

function_A должна вернуть массив, а function_B должна взять этот массив.

Спасибо!

Ответы [ 4 ]

0 голосов
/ 04 января 2019

Если размер массива действительно равен 3 (или другому небольшому фиксированному значению), тогда вы можете просто использовать структуры в качестве значений, например:

struct ints3 {
  int values[3];
  // if needed, can add other fields
}

int main(){
  struct ints3 ints;

  ints = function_A();
  function_B(&ints);

  return 0; 
}

// note about function_A signature: void is important,
// because in C empty () means function can take any arguments...
struct ints3 function_A(void) {
  // use C designated initialiser syntax to create struct value,
  // and return it directly
  return (struct ints3){ .values = { 11, 22, 33 } };
}

int function_B(const struct ints3 *ints) {
  // pass struct as const pointer to avoid copy,
  // though difference to just passing a value in this case is insignificant

  // could use for loop, see other answers, but it's just 3 values, so:
  printf("%d %d %d\n", ints->values[0], ints->values[1], ints->values[2]);
  return 0; // does this function really need return value?
}
0 голосов
/ 04 января 2019

Примечание: ссылка на массив ухудшается до адреса первого байта массива.

следующий предложенный код:

  1. чисто компилирует
  2. включает комментарии к вопросу
  3. предполагает, что программист уже знает размер массива
  4. выполняет желаемую функциональность
  5. добавлен '\ n' для форматирования строки вызовов printf(), поэтому вывод в отдельных строках

и теперь предложенный код:

#include <stdio.h>


int * function_A( void );
void  function_B(int *myPointer);

int main( void )
{
  int *p;

  p = function_A();
  function_B(p);

  return 0; 
}


int * function_A()
{
  static int myArray[3];
  myArray[0] = 11;
  myArray[1] = 22;
  myArray[2] = 33;

  return myArray;
}

void function_B(int *myPointer)
{
  printf("%d\n", myPointer[0]);
  printf("%d\n", myPointer[1]);
  printf("%d\n", myPointer[2]);
}

при запуске программы выдается следующий вывод:

11
22
33
0 голосов
/ 04 января 2019

Допустим, у вас есть функция, которая создает массив int s:

int *create_int_array(const size_t num)
{
    int    *iarray;
    size_t  i;

    if (num < 1)
        return NULL; /* Let's not return an empty array. */

    iarray = malloc(num * sizeof iarray[0]);
    if (!iarray)
        return NULL; /* Out of memory! */

    /* Fill in the array with increasing integers. */
    for (i = 0; i < num; i++)
        iarray[i] = i + 1;

    return iarray;
}

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

int sum_int_array(const int *iarray, const size_t num)
{
    int    sum = 0;
    size_t i;

    /* Sum of an empty array is 0. */
    if (num < 1)
        return 0;

    for (i = 0; i < num; i++)
        sum += iarray[i];

    return sum;
}

Обратите внимание, что sizeof - это не функция, а ключевое слово языка Си.Его аргумент рассматривается только для его размера.Таким образом, sizeof iarray[0] возвращает размер каждого элемента в iarray и является полностью безопасным и допустимым, даже если iarray не определен или равен NULL в этой точке.Вы часто видите эту идиому в программах на Си;научитесь читать его как "размер первого элемента iarray" , что совпадает с "размером каждого элемента в iarray" , поскольку все элементы массива C имеют одинаковый размер.

В вашем main() вы могли бы назвать их так:

#ifndef  NUM
#define  NUM  5
#endif

int main(void)
{
    int  *array, result;

    array = create_int_array(NUM);
    if (!array) {
        fprintf(stderr, "Out of memory!\n");
        exit(EXIT_FAILURE);
    }

    result = sum_int_array(array, NUM);

    printf("Sum is %d.\n", result);

    free(array);

    return EXIT_SUCCESS;
}

Как вы видите, на самом деле ничего особенного.Что ж, вам нужно ознакомиться с синтаксисом указателя.

(Правило, на которое я хотел бы обратить внимание, заключается в том, что при чтении типов указателей читайте спецификаторы справа налево, ограниченные *, читаемые как указатель на . Таким образом, int *const a читается как "a является константой, указатель на int" , а const char **b читается как "b является указателем на aуказатель на const char ".)


В таких ситуациях структура , описывающая массив, имеет гораздо больший смысл.Например:

typedef struct {
    size_t  max;   /* Maximum number of elements val[] can hold */
    size_t  num;   /* Number of elements in val[] */
    int    *val;
} iarray;
#define  IARRAY_INIT  { 0, 0, NULL }

Идея состоит в том, что вы можете объявить переменную типа iarray так же, как и любую другую переменную;но вы также инициализируете их в пустой массив, используя макрос IARRAY_INIT.Другими словами, таким образом:

    iarray  my_array = IARRAY_INIT;

При этой инициализации структура всегда инициализируется в известное состояние, и нам не нужна отдельная функция инициализации.Нам действительно нужна только пара вспомогательных функций:

static inline void iarray_free(iarray *array)
{
    if (array) {
        free(array->val);
        array->max = 0;
        array->num = 0;
        array->val = NULL;
    }
}

/* Try to grow the array dynamically.
   Returns the number of elements that can be added right now. */
static inline size_t iarray_need(iarray *array, const size_t more)
{
    if (!array)
        return 0;

    if (array->num + more > array->max) {
        size_t  max = array->num + more;
        void   *val;

        /* Optional: Growth policy. Instead of allocating exactly
                     as much memory as needed, we allocate more,
                     in the hopes that this reduces the number of
                     realloc() calls, which tend to be a bit slow.
                     However, we don't want to waste too much
                     memory by allocating and then not using it. */
        if (max < 16) {
            /* Always allocate at least 16 elements, */
            max = 16;  
        } else
        if (max < 65536) {
            /* up to 65535 elements add 50% extra, */
            max = (3*max) / 2;
        } else {
            /* then round up to next multiple of 65536, less 16. */
            max = (max | 65535) + 65521;
        }

        val = realloc(array->val, max * sizeof array->val[0]);
        if (!val) {
            /* We cannot grow the array. However, the old
               array is still intact; realloc() does not
               free it if it fails. */
            return array->max - array->num;
        }

        /* Note: the new elements in array->val,
                 array->val[array->max] to
                 array->val[max-1], inclusive,
                 are undefined. That is fine, usually,
                 but might be important in some special
                 cases like resizing hash tables or such. */

        array->max = max;
        array->val = val;
    }

    return array->max - array->num;
}

/* Optional; same as initializing the variable to IARRAY_INIT. */
static inline void iarray_init(iarray *array)
{
    array->max = 0;
    array->num = 0;
    array->val = NULL;
}

Бит static inline означает, что функции видны только в этом модуле компиляции, и компилятор может реализовать эту функцию непосредственно на сайте вызова.,В основном, static inline используется для макроподобных функций и функций доступа.Если вы поместите структуру в файл заголовка (.h), вы также включите в нее соответствующие вспомогательные функции static inline.

Часть policy policy является лишь примером,Если вы опускаете политику роста и всегда перераспределяете элементы array->num + more, ваш код будет очень часто вызывать realloc(), потенциально для каждого добавленного int.В большинстве случаев выполнение этого часто замедляет вашу программу, потому что realloc() (а также malloc(), calloc()) довольно медленные.Чтобы избежать этого, мы предпочитаем немного дополнить или округлить распределение: не слишком много, чтобы тратить выделенную, но неиспользуемую память, но достаточно, чтобы сохранить общую программу быстро, и не ставить узкие места на слишком много вызовов realloc().

«Хорошая политика роста» очень спорна и действительно зависит от поставленной задачи.Вышеприведенное должно действительно хорошо работать на всех современных операционных системах на настольных компьютерах, ноутбуках и планшетах, когда программе требуется только один или только несколько таких массивов.

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

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

/* Append an int to the array.
   Returns 0 if success, nonzero if an error occurs.
*/
int iarray_append(iarray *array, int value)
{
    if (!array)
        return -1; /* NULL array specified! */

    if (iarray_need(array, 1) < 1)
        return -2; /* Not enough memory to grow the array. */

    array->val[array->num++] = value;

    return 0;
}

Другой пример функции, которая сортирует int s в массиве по возрастанию или убыванию:

static int cmp_int_ascending(const void *ptr1, const void *ptr2)
{
    const int  val1 = *(const int *)ptr1;
    const int  val2 = *(const int *)ptr2;
    return (val1 < val2) ? -1 :
           (val1 > val2) ? +1 : 0;
}

static int cmp_int_descending(const void *ptr1, const void *ptr2)
{
    const int  val1 = *(const int *)ptr1;
    const int  val2 = *(const int *)ptr2;
    return (val1 < val2) ? +1 :
           (val1 > val2) ? -1 : 0;
}

static void iarray_sort(iarray *array, int direction)
{
    if (array && array->num > 1) {
        if (direction > 0)
            qsort(array->val, array->num, sizeof array->val[0],
                  cmp_int_ascending);
        else
        if (direction < 0)
            qsort(array->val, array->num, sizeof array->val[0],
                  cmp_int_descending);
    }
}

Многие новые программисты не понимают, что стандартная библиотека C имеет эту изящную и довольно эффективную qsort() функцию для сортировки массивов;все, что нужно, это функция сравнения.Если direction положительно для iarray_sort(), массив сортируется в порядке возрастания, сначала наименьший int;если direction отрицательно, то в порядке убывания сначала самое большое int.

Простой пример main(), который читает все действительные int s из стандартного ввода, сортирует их и печатает их в порядке возрастания (возрастающее значение):

int main(void)
{
    iarray  array = IARRAY_INIT;
    int     value;
    size_t  i;

    while (scanf(" %d", &value) == 1)
        if (iarray_append(&array, value)) {
            fprintf(stderr, "Out of memory.\n");
            exit(EXIT_FAILURE);
        }

    iarray_sort(&array, +1); /* sort by increasing value */

    for (i = 0; i < array.num; i++)
        printf("%d\n", array.val[i]);

    iarray_free(&array);

    return EXIT_SUCCESS;
}
0 голосов
/ 03 января 2019

Есть некоторые проблемы, о которых ваш компилятор уже говорил вам.Во-первых, вы должны определить функции перед их вызовом или, по крайней мере, объявить их заблаговременно.

Во-вторых, чтобы вернуть массив, вам нужно вернуть указатель на первый элемент этого массива, т.е. тип возвращаемого значения int *, а не int.

В-третьих, как указал ФредК, когда вы получаете только указатель, у вас нет шанса определить, сколько элементов находится в массиве, на который он указывает.Вы можете завершить массив определенным значением, например, 0, или вам также нужно вернуть размер массива.

См. Следующие изменения, сделанные в вашей программе:

int* function_A(int *size){
    static int myArray[3];
    myArray[0] = 11;
    myArray[1] = 22;
    myArray[2] = 33;

    if (size) {
        *size = 3;
    }
    return myArray;
}

void function_B(int *myPointer, int size){
    for (int i=0; i<size; i++) {
        printf("%d\n", myPointer[i]);
    }
}

int main(){
    int *p;

    int size=0;
    p = function_A(&size);
    function_B(p,size);

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...