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

Если Вы уже знаете C, Objective C довольно легко изучить.

Ruby и Python оба жизнеспособны для "реальных" приложений Mac. ADC имеет несколько статей о тема . MacRuby похож на него, будет RubyCocoa замены.

я все еще рекомендовал бы изучить Objective C все же. Большая часть примера кода Вы, которыми находка будет в Objective C и книгах, склонны быть Objective C (хотя Прагматически настроенные Программисты имеют книга RubyCocoa в работах. Большинство приложений Какао записано в Objective C.

И Objective C является динамичным. Бросьте более внимательный взгляд в нем, это не почти столь пугающе, как люди думают. Это - Какао, которое имеет тенденцию иметь более крутое изучение (или разучивание) кривая.

63
задан templatetypedef 5 January 2014 в 22:18
поделиться

6 ответов

В 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 = 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

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

typedef struct Coordinate {
   int x;
   int y;
} Coordinate;
125
ответ дан 24 November 2019 в 16:10
поделиться

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

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

в отличие от указателя на 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).

в отличие от указателя на 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).

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

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

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

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

10-элементный массив T - это другой тип, чем 20-элементный массив T).

10-элементный массив T - это другой тип, чем 20-элементный массив T).

11
ответ дан 24 November 2019 в 16:10
поделиться

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

//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)
}
7
ответ дан 24 November 2019 в 16:10
поделиться

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

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

API в стиле C ++

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

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

void UpdateValue(int *i) {
  *i = 42;
}
9
ответ дан 24 November 2019 в 16:10
поделиться

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

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;

6
ответ дан 24 November 2019 в 16:10
поделиться
  1. Определите расстояние от точки E до каждой точки A, B, C, D
  2. Цвет точки E будет сочетанием красного / зеленого / синего цветов. Вычислите каждую цветовую ось как среднее значение той же цветовой оси для A, B, C, D, взвешивая по расстоянию.

    distance_a = sqrt ((xa-xe) ^ 2 + (ya-ye) ^ 2)

    distance_b = ....

6
ответ дан 24 November 2019 в 16:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: