с языком.Возвращаемый тип функции - PullRequest
0 голосов
/ 16 июля 2010
?? fun()
{
   int a[3]={3,3,4};
   return &a; 
}

что может быть совместимым типом возврата.Здесь указатель указывает на массив из 3 целых чисел, а не только указатель, который указывает на массив целых чисел.Цель состоит в том, чтобы вернуть указатель на массив из 3 целых чисел.

Ответы [ 11 ]

14 голосов
/ 16 июля 2010

Во-первых, вы действительно должны не возвращать адрес локальной переменной. При выходе из функции массив a будет уничтожен.

Что касается вашего вопроса, тип &a равен int (*)[].

5 голосов
/ 16 июля 2010

Не делай этого.

Вы возвращаете указатель на локальную переменную. Когда функция возвращается, этот указатель указывает на местоположение, которое больше не является допустимым, поэтому это упражнение бессмысленно. Хотя возвращаемый тип был бы int (*)[3], но когда вы используете его в качестве возвращаемого типа функции, прототип будет int (*fun(void))[3] (тьфу, eew)

1010 * Тем не менее *

Если бы a был статическим, вы могли бы сделать

int (*fun(void))[3]
{ 
   static int a[3]={3,3,4}; 
   return &a;
}

Чаще встречается возвращение указателя на первый элемент в массиве - хотя вам нужно «знать» в вызывающей стороне, что вы можете получить доступ к 3 и только к 3 элементам этого указателя.

int *fun(void)
{ 
   static int a[3]={3,3,4}; 
   return &a[0]; // or just return a;
}

Поскольку a в этих случаях является статическим, вам придется беспокоиться о повторном входе

2 более распространенных способа достижения того же:

Передать массив через параметры и выделить его в вызывающей программе:

void fun(int *a)
{ 
       a[0] = 3;
       a[1] = 3;
       a[2] = 4;

}

Назовите это как:

int a[3];
fun(a);

Динамически распределять память:

int *fun(void) 
{
  int *a = malloc(3*sizeof *a);
  if(a) {
     a[0] = 3;
     a[1] = 3;
     a[2] = 4;
   }
   return a;
}

Назовите это как:

int *a;
a = fun();
if(a) {
  ///use a
  free(a); // remember to free it when done
} else {
  //out of memory
}
4 голосов
/ 16 июля 2010

Тип возвращаемого значения не будет int* или int**, как предлагали другие.Тип возвращаемого значения будет указателем на массив.Например:

// we'll use a typedef so we can keep our sanity:
typedef int(*int3arrayptr)[3];

int3arrayptr fun()
{
    int a[3]={3,3,4};
    return &a; 
}

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

3 голосов
/ 16 июля 2010

Тип будет int **

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

1 голос
/ 16 июля 2010

a является локальной переменной.Не возвращайте указатель на это.

Вернемся к делу.Вот как вы определяете тип указатель на массив размера 3 в C:

int a[3] = { 1, 2, 3 };

typedef int (*p_arr_3)[3];   

p_arr_3 fun() { return &a; }
1 голос
/ 16 июля 2010

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

1 голос
/ 16 июля 2010

Не делайте ошибку.Как только fun () теряет область видимости, так же как и все локальные переменные.

0 голосов
/ 16 июля 2010

Все остальные уже сказали вам, почему вы не должны делать это так, как написано, но вот типы, которые вас интересуют.

Учитывая объявление int a[3], тип выражения &a - это int (*)[3] (, а не int **), или "указатель на массив из 3 элементов типа int", такой как

void f()
{
  int a[3] = {1,2,3};
  int (*aptr)[3] = &a;
  ...
}

и подпись для функции, возвращающейтип будет int (*fun())[3] {...}.

Еще одна опция, которую не показывали, это:

int (*fun())[3]
{
  int (*aptr)[3] = malloc(sizeof *aptr);
  if (aptr)
  {
    (*aptr)[0] = 1; // array pointer must be deferenced before applying
    (*aptr)[1] = 2; // the subscript. 
    (*aptr)[2] = 3;
  }
  return aptr;
}

, хотя это не очень полезно;вы обычно не видите выделения отдельных массивов фиксированного размера, как это.Несколько более полезно выделить массив из этих массивов:

int (*fun(size_t count))[3]
{
  int (*aptr)[3] = malloc(sizeof *aptr * count);
  if (aptr)
  {
    size_t i;
    for (i = 0; i < count; i++)
    {
      aptr[i][0] = 1; // aptr[i] implicitly dereferences aptr, so
      aptr[i][1] = 2; // there's no need for an explicit dereference
      aptr[i][2] = 3; // here.
    }
  }
  return aptr;
}

Даже в этом случае, если кому-то нужно выделить тип массива фиксированного размера, они обычно прячут его за определением типа:

typedef int fixedSizeRecord[SOME_SIZE];
...
fixedSizeRecord *fun(size_t count)
{
  fixedSizeRecord *aptr = malloc(sizeof *aptr * count);
  if (aptr)
  {
      // initialize contents as necessary
      for (size_t i = 0; i < count; i++)
        for (j = 0; j < sizeof *aptr / sizeof *aptr[0]; j++)
          aptr[i][j] = ...;
  }
  return aptr;
}

Абстракция - это хорошая вещь.

Я поднял несколько итераций этой таблицы раньше;Вы можете найти это под рукой.

Declaration: T a[N];

Expression        Type        Decays To        Value
----------        ----        ---------        -----
         a        T [N]       T *              Address of first element in a
        &a        T (*)[N]    n/a              Address of a (same value as above,
                                                 but different type)
        *a        T           n/a              Same as a[0]
      a[i]        T           n/a              Value at index i
     &a[i]        T *         n/a              Address of value at index i
  sizeof a        size_t                       Total number of bytes in a
                                                 (N * sizeof T)
sizeof a / 
  sizeof *a       size_t      n/a              Number of elements in a (N)

Declaration: T a[N][M];

Expression        Type        Decays To        Value
----------        ----        ---------        -----
         a        T [N][M]    T (*)[M]         Address of first element in a[0]
        &a        T (*)[N][M] n/a              Address of a (same value as above,
                                                 but different type)
        *a        T [M]       T *              Same as a[0]
       a[i]       T [M]       T *              Address of first element in array 
                                                 at index i
      &a[i]       T (*)[M]    n/a              Address of array at index i (same 
                                                 value as above, but different 
                                                 type)
      *a[i]       T           n/a              Same as a[i][0]
    a[i][j]       T           n/a              Value at a[i][j]
   &a[i][j]       T *         n/a              Address of value at index i,j
   sizeof a       size_t      n/a              Total number of bytes in a
                                                 (N * M * sizeof T)
sizeof a /
  sizeof *a       size_t      n/a              Number of subarrays in a (N)
sizeof a[i]       size_t      n/a              Total number of bytes in a[i]
                                                 (M * sizeof T)
sizeof a[i] /
  sizeof *a[i]    size_t      n/a              Number of elements in a[i] (M)
0 голосов
/ 16 июля 2010

Если вы должны вернуть a, тип возврата будет int *.Я не совсем уверен, что означает &a в этом случае, и моя удобная справка говорит мне, что единственная операция, которая может быть применена к массиву, это sizeof, и у меня нет удобного стандарта.Он может быть помечен как недопустимый или может просто возвращать значение a.Единственное, что обозначает a, - это массив, и единственное, что напоминает указатель на массив, - это указатель на его первый элемент.Адрес не указан.

В Си трудно обойти массив, так как массивы распадаются на указатели при малейшей провокации.Если вам нужно передать реальный массив, проще всего встроить его в struct.struct, содержащее int a[3];, может быть передано как обычное значение.

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

0 голосов
/ 16 июля 2010

Ваша функция будет иметь тип возврата int *, и вы бы назвали его так:

int *array=fun();
printf("%d\n",array[0]); //print the first value in the array

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

int *more_fun(){
  int *a=malloc(sizeof(int)*3);
  a[0]=3;
  a[1]=3;
  a[2]=4;
  return a;
}

Назовите это как:

int *array=more_fun();
printf("%d\n",array[0]); //print the first value in the array

Но когда вы закончите, обязательно наберите free(array)утечка памяти.

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