Подтвердить что ты не робот

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

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

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

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

Ответ 1

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

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 = (int*) malloc( size * sizeof(int) );
}
int main() {
   int *p = (int*) 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

Вы можете напечатать тип при его объявлении (и это общая идиома в C):

typedef struct Coordinate {
   int x;
   int y;
} Coordinate;

Ответ 2

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

В C, когда идентификатор массива появляется в контексте, отличном от операнда для одного или и 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:

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).

Ответ 3

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

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

API стиля С++

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

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

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

Ответ 4

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

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

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

Ответ 5

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

//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)
}

Ответ 6

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

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;

Ответ 7

Привет, ребята, это простая тестовая программа, которая показывает, как распределить и передать массив с помощью 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;
}