Использование структур для доступа к массивам в C - PullRequest
2 голосов
/ 12 декабря 2011

Я понимаю, как создать структуру, которая может использоваться для доступа к массиву, например:

#include <stdio.h>

typedef struct {
  int i;
  int j;
  int k;
} MyStruct;

int main()
{
  MyStruct *ms;
  int array[9];
  int i;

  for(i=0;i<9;++i) array[i] = i;

  ms = (MyStruct *)array;

  for(i=0;i<3;++i) printf("%d %d %d %d\n",i,ms[i].i,ms[i].j,ms[i].k);
  return 0;
}

, которая позволяет мне получить доступ к массиву [0] как ms [1] .i и массиву [1] as ms [1] .j и т. Д. Однако, как я могу сделать то же самое, если я хочу использовать массив в структуре, которая известна во время выполнения, но не во время компиляции?Что-то вроде:

#include <stdio.h>

typedef struct {
  int *myArgs;
} MyStruct;

int main()
{
  MyStruct *ms;
  int array[9];
  int i;

  for(i=0;i<9;++i) array[i] = i;

  ms = (MyStruct *)array;

  for(i=0;i<3;++i) printf("%d %d %d %d\n",i,ms[i].myArgs[0],ms[i].myArgs[1],ms[i].myArgs[2]);
  return 0;
}

, который в этом примере я знал бы во время выполнения, что myArgs имеет длину 3. Но также возможно, что myArgs имеет длину 9, в этом случае ms должен быть длиной 1.

Редактировать:

Я храню набор решений для решателя PDE, который имеет ряд известных значений во время компиляции, а затем неизвестное число дополнительных функций.Например, мой массив будет иметь X, Y, Z, но тогда он может иметь еще 3, 5 или 10 вещей после этого.Итак, я хотел предоставить структуру, которая позже предоставит доступ к полям для удобства чтения, например, solution.x, solution.y, solution.z, solution.chemicalSpecies [0], solution.chemicalSpecies [1] и т. Д.Количество видов полностью неизвестно во время компиляции.

Я использую внешнюю библиотеку, которая хранит число неизвестных в виде массива, и я могу вернуть массив в виде [k] [j] [i] [numUnknowns], и было бы неплохопредоставить доступ как решение [k] [j] [i]. что-то.

Ответы [ 3 ]

1 голос
/ 12 декабря 2011

Нет.

В первом случае размер вашей структуры равен размеру 3 int переменных.Когда вы приводите указатель вашего массива к указателю вашей структуры, каждые 3 int элемента будут совпадать с одним MyStruct элементом, что делает магию в вашем коде (который теоретически непереносим).

Во втором случае размер структуры равен размеру 1 указателя на int.Вы должны знать, что указатели имеют некоторые сходства с массивами в отношении использования, но это не одно и то же.Указатели - это всего лишь одна переменная с одним значением, которое указывает на адрес памяти.Содержимое этого адреса затем может быть использовано в качестве массива.

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

Возможно, хорошим решением для вас было бы использование абстрактного типа данных, например:

typedef struct {
  int m; /* number of lines */
  int n; /* number of columns */
  int *data; /* pointer to the actual data */
} Matrix;

Тогда вы могли бысоздайте вспомогательные функции для использования структуры:

void matrix_new(Matrix *m, int rows, int columns);
int matrix_get(Matrix *m, int i, int j);
void matrix_set(Matrix *m, int i, int j, int value);
void matrix_free(Matix *m);

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

int matrix_get(Matrix *m, int i, int j)
{
  return m->data[i * m->n + j];
}

int main()
{
  Matrix m;
  int array[9];
  int i;

  for(i=0;i<9;++i) array[i] = i;

  m.m = m.n = 3;
  m.data = array;

  for(i=0;i<3;++i)
    printf("%d %d %d %d\n", i,
                            matrix_get(&m, i, 0),
                            matrix_get(&m, i, 1),
                            matrix_get(&m, i, 2));
  return 0;
}
1 голос
/ 12 декабря 2011

Тривиально, при заданном размере массива N и myArgs < N у вас будет N/myArgs полных наборов данных с остатком N%myArgs элементов.Вы можете основывать индексирование вашего массива на этом факте.

Однако этот код выглядит как кошмар обслуживания.Что вы пытаетесь достичь?Возможно, есть лучший способ.

0 голосов
/ 12 декабря 2011

Учитывая ваше разъяснение, я бы сказал о проблеме следующим образом. У меня была бы структура, в которой были бы фиксированные x, y и z, а затем указатель на массив, который можно было бы указать для местоположения соответствующей точки в массиве решений. Примерно так:

struct MyStruct {
    int x, y, z;
    int *extras;
};

...
int solutions[9];
struct MyStruct ms;
ms.x = solutions[0];
ms.y = solutions[1];
ms.z = solutions[2];
ms.extras = (solutions + 3);
...

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

ms.extras[0]

По крайней мере, это должно сработать, с моей головы.

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

Редактировать: Если вы хотели, чтобы они были отражены, вы могли бы вместо этого сделать:

struct MyStruct {
    int *x, *y, *z;
    int *extras;
};

А затем: 1016 *

...
int solutions[9];
struct MyStruct ms;
ms.x = &solutions[0];
ms.y = &solutions[1];
ms.z = &solutions[2];
ms.extras = (solutions + 3);
...

Но это очень похоже на то, что вы имели раньше, не так ли?

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