Передача массива по ссылке в C?

Как я могу передать массив структур по ссылке в C?

В качестве примера:

struct Coordinate {
   int X;
   int Y;
};
SomeMethod(Coordinate *Coordinates[]){
   //Do Something with the array
}
int main(){ 
   Coordinate Coordinates[10];
   SomeMethod(&Coordinates);
}

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

Язык C не поддерживает передачу по ссылке любого типа. Ближайшим эквивалентом является передача указателя на тип.

Вот надуманный пример на обоих языках

API стиля C ++

void UpdateValue(int& i) {
  i = 42;
}

Ближайший эквивалент C

void UpdateValue(int *i) {
  *i = 42;
}
 10 июл. 2009 г., 01:46
@ Ральф, а ты веришь, что это стоило -1? ОП задал вопрос, на который нет действительного ответа, и я предоставил простую & quot; ближайшую особенность - ... & quot; ответ. Может быть, не +1 ответ, но, конечно, не -1
 10 июл. 2009 г., 01:44
Я имею в виду, продемонстрировано должным образом в dribeas & apos; сообщение! знак равно
 Hannoun Yassir10 июл. 2009 г., 01:31
я знаю, но я нахожу проблемы с передачей массива тем же методом: s
 10 июл. 2009 г., 01:40
Этот пример демонстрирует передачу примитивного типа по ссылке (с использованием указателя, который передается по значению), но не демонстрирует передачу массива структур по ссылке, как это продемонстрировано должным образом в посте ниже.
 10 июл. 2009 г., 01:32
@ Яссир, можешь привести пример?
Решение Вопроса

В Си массивы передаются как указатель на первый элемент. Они являются единственным элементом, который на самом деле не передается по значению (указатель передается по значению, но массив не копируется). Это позволяет вызываемой функции изменять содержимое.

void reset( int *array, int size) {
   memset(array,0,size * sizeof(*array));
}
int main()
{
   int array[10];
   reset( array, 10 ); // sets all elements to 0
}

Теперь, если вам нужно изменить сам массив (количество элементов ...), вы не можете сделать это со стеком или глобальными массивами, только с динамически распределенной памятью в куче. В этом случае, если вы хотите изменить указатель, вы должны передать указатель на него:

void resize( int **p, int size ) {
   free( *p );
   *p = malloc( size * sizeof(int) );
}
int main() {
   int *p = malloc( 10 * sizeof(int) );
   resize( &p, 20 );
}

В вопросе редактирования вы задаете вопрос о передаче массива структур. У вас есть два решения: объявить typedef или сделать явным, что вы передаете структуру:

struct Coordinate {
   int x;
   int y;
};
void f( struct Coordinate coordinates[], int size );
typedef struct Coordinate Coordinate;  // generate a type alias 'Coordinate' that is equivalent to struct Coordinate
void g( Coordinate coordinates[], int size ); // uses typedef'ed Coordinate

Вы можете ввести typedef типа, как вы его объявили (и это распространенная идиома в C):

typedef struct Coordinate {
   int x;
   int y;
} Coordinate;
 03 мар. 2018 г., 22:19
@Aka: Вы абсолютно правы, и я узнал, что с тех пор, как написал это около 9 лет назад :) [Я отредактировал, чтобы убрать слепки, спасибо, что поднял этот вопрос]
 02 мар. 2019 г., 06:33
Почему sizeof (* array), если тип массива ограничен int? Почему не просто sizeof (int)?
 12 дек. 2012 г., 18:28
использовать memset (массив, 0, размер массива); вместо цикла for () внутри сброса :)
 12 дек. 2012 г., 19:45
@rodi: Это интересный момент, учитывая, что вы ввели ошибку :) Я обновил код для использованияmemset как следует использовать:memset(array,0,size * sizeof *array) -- sizeof(array) в этом случае размерpointer, а не указанные данные.
 25 февр. 2018 г., 01:40
Это хорошая практикаnot to Тип приведите возвращаемое значение malloc. увидетьhere

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

//this is bad
char* getname()
{
  char name[100];
  return name;
}

//this is better
char* getname()
{
  char *name = malloc(100);
  return name;
  //remember to free(name)
}

В простом C вы можете использовать комбинацию указатель / размер в вашем API.

void doSomething(MyStruct* mystruct, size_t numElements)
{
    for (size_t i = 0; i < numElements; ++i)
    {
        MyStruct current = mystruct[i];
        handleElement(current);
    }
}

Использование указателей наиболее близко к обращению по ссылке, доступному в C.

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

void SomeMethod(Coordinate Coordinates[]){Coordinates[0].x++;};
int main(){
  Coordinate tenCoordinates[10];
  tenCoordinates[0].x=0;
  SomeMethod(tenCoordinates[]);
  SomeMethod(&tenCoordinates[0]);
  if(0==tenCoordinates[0].x - 2;){
    exit(0);
  }
  exit(-1);
}

Два вызова эквивалентны, и значение выхода должно быть 0;

Привет, ребята, вот простая тестовая программа, которая показывает, как распределять и передавать массив, используя new или malloc. Просто вырезать, вставить и запустить его. Повеселись!

struct Coordinate
{
    int x,y;
};

void resize( int **p, int size )
{
   free( *p );
   *p = (int*) malloc( size * sizeof(int) );
}

void resizeCoord( struct Coordinate **p, int size )
{
   free( *p );
   *p = (Coordinate*) malloc( size * sizeof(Coordinate) );
}

void resizeCoordWithNew( struct Coordinate **p, int size )
{
   delete [] *p;
   *p = (struct Coordinate*) new struct Coordinate[size];
}

void SomeMethod(Coordinate Coordinates[])
{
    Coordinates[0].x++;
    Coordinates[0].y = 6;
}

void SomeOtherMethod(Coordinate Coordinates[], int size)
{
    for (int i=0; i<size; i++)
    {
        Coordinates[i].x = i;
        Coordinates[i].y = i*2;
    }
}

int main()
{
    //static array
    Coordinate tenCoordinates[10];
    tenCoordinates[0].x=0;
    SomeMethod(tenCoordinates);
    SomeMethod(&(tenCoordinates[0]));
    if(tenCoordinates[0].x - 2  == 0)
    {
        printf("test1 coord change successful\n");
    }
    else
    {
        printf("test1 coord change unsuccessful\n");
    }


   //dynamic int
   int *p = (int*) malloc( 10 * sizeof(int) );
   resize( &p, 20 );

   //dynamic struct with malloc
   int myresize = 20;
   int initSize = 10;
   struct Coordinate *pcoord = (struct Coordinate*) malloc (initSize * sizeof(struct Coordinate));
   resizeCoord(&pcoord, myresize); 
   SomeOtherMethod(pcoord, myresize);
   bool pass = true;
   for (int i=0; i<myresize; i++)
   {
       if (! ((pcoord[i].x == i) && (pcoord[i].y == i*2)))
       {        
           printf("Error dynamic Coord struct [%d] failed with (%d,%d)\n",i,pcoord[i].x,pcoord[i].y);
           pass = false;
       }
   }
   if (pass)
   {
       printf("test2 coords for dynamic struct allocated with malloc worked correctly\n");
   }


   //dynamic struct with new
   myresize = 20;
   initSize = 10;
   struct Coordinate *pcoord2 = (struct Coordinate*) new struct Coordinate[initSize];
   resizeCoordWithNew(&pcoord2, myresize); 
   SomeOtherMethod(pcoord2, myresize);
   pass = true;
   for (int i=0; i<myresize; i++)
   {
       if (! ((pcoord2[i].x == i) && (pcoord2[i].y == i*2)))
       {        
           printf("Error dynamic Coord struct [%d] failed with (%d,%d)\n",i,pcoord2[i].x,pcoord2[i].y);
           pass = false;
       }
   }
   if (pass)
   {
       printf("test3 coords for dynamic struct with new worked correctly\n");
   }


   return 0;
}

Чтобы немного расширить некоторые ответы здесь ...

В C, когда идентификатор массива появляется в контексте, отличном от операнда или & amp; или sizeof, тип идентификатора неявно преобразуется из «N-элементного массива T»; на «указатель на T», и его значение неявно устанавливается на адрес первого элемента в массиве (который совпадает с адресом самого массива). Вот почему, когда вы просто передаете идентификатор массива в качестве аргумента функции, функция получает указатель на базовый тип, а не на массив. Поскольку вы не можете сказать, насколько большой массив, просто взглянув на указатель на первый элемент, вы должны передать размер в качестве отдельного параметра.

struct Coordinate { int x; int y; };
void SomeMethod(struct Coordinate *coordinates, size_t numCoordinates)
{
    ...
    coordinates[i].x = ...;
    coordinates[i].y = ...; 
    ...
}
int main (void)
{
    struct Coordinate coordinates[10];
    ...
    SomeMethod (coordinates, sizeof coordinates / sizeof *coordinates);
    ...
}

Есть несколько альтернативных способов передачи массивов в функции.

Существует такая вещь, как указатель на массив T, в отличие от указателя на T. Вы бы объявили такой указатель как

T (*p)[N];

В этом случае p является указателем на массив из N элементов из T (в отличие от T * p [N], где p является массивом из N элементов с указателем на T). Таким образом, вы можете передать указатель на массив, а не указатель на первый элемент:

struct Coordinate { int x; int y };

void SomeMethod(struct Coordinate (*coordinates)[10])
{
    ...
    (*coordinates)[i].x = ...;
    (*coordinates)[i].y = ...;
    ...
}

int main(void)
{
    struct Coordinate coordinates[10];
    ...
    SomeMethod(&coordinates);
    ...
}

Недостаток этого метода заключается в том, что размер массива является фиксированным, поскольку указатель на массив из 10 элементов T отличается от указателя на массив из 20 элементов T.

Третий метод - обернуть массив в структуру:

struct Coordinate { int x; int y; };
struct CoordinateWrapper { struct Coordinate coordinates[10]; };
void SomeMethod(struct CoordinateWrapper wrapper)
{
    ...
    wrapper.coordinates[i].x = ...;
    wrapper.coordinates[i].y = ...;
    ...
}
int main(void)
{
    struct CoordinateWrapper wrapper;
    ...
    SomeMethod(wrapper);
    ...
}

Преимущество этого метода состоит в том, что вы не копаетесь в указателях. Недостатком является то, что размер массива является фиксированным (опять же, массив из 10 элементов T отличается от массива из 20 элементов T).

 16 дек. 2015 г., 15:10
Еще один недостаток вашей рецептуры обертки заключается в том, чтоwrapper проходит мимоvalue, 80 байт (-ише), а присвоение внутриSomeMethod() не влияет наwrapper объявлено вmain, Похоже на ошибку.

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