Доступ к массивам в указателе на структуру - PullRequest
0 голосов
/ 22 апреля 2011

У меня есть простая структура:

typedef struct {
    void *things;
    int sizeOfThings;
} Demo;

вещи предназначены для хранения массива отдельных "вещей", например, строк или целых.Я создаю указатель на него:

Demo * Create(int value) {
    Demo *d = malloc(sizeof(Demo));
    if (d != NULL) {
        d->sizeOfThings = value;
        d->things = malloc(20 * value); // We'll have a max of 20 things
    }
}

value - это sizeof (int) для массива целых чисел, например.

Если в другой функции я хочу вставить что-то в d-> вещи (если не считать, что я просто добавляю его в первый слот, управление позициями выполняется в другом месте):

char * thing = "Me!";
strncpy(d->things[0], &thing, d->sizeOfThings);

Я обхожу область strncpy

test.c:10: warning: pointer of type ‘void *’ used in arithmetic
test.c:10: warning: dereferencing ‘void *’ pointer
test.c:10: error: invalid use of void expression

Я просто пытаюсь понять использование void * как способ обобщить мои функции.Я подозреваю, что что-то не так с d->things[0].

Ответы [ 4 ]

3 голосов
/ 22 апреля 2011

В соответствии со стандартом C, void не имеет размера - sizeof (void) не определен.(Некоторые реализации делают это sizeof (int), но это несовместимо.)

Если у вас есть массив типа foo, это выражение:

array[3]

Добавляет 3 * sizeof (foo) по адресу, хранящемуся в массиве, а затем задерживает это.Это потому, что все значения упакованы в памяти.Поскольку sizeof (void) не определен, вы не можете сделать это для пустых массивов (на самом деле вы не можете даже иметь пустые массивы, только пустые указатели.)

Вы должны разыграть любоеvoid указатель на другой тип указателя перед обработкой его как массива:

d->things = malloc(20 * sizeof(int));
(int *)(d->things)[0] = 12;

Однако имейте в виду, что вам даже не нужно это делать, чтобы использовать strncpy для него.Strncpy может принимать указатель void просто отлично.Но вы использовали strncpy неправильно.Ваш вызов strncpy должен выглядеть следующим образом:

strncpy(d->things, thing, d->sizeOfThings);

Ваша версия сделала бы попытку обработать первый член массива d-> вещей как указатель, когда это не так, и обработал бы & вещь, котораяэто символ **, как если бы это был просто символ *.

0 голосов
/ 22 апреля 2011

Две вещи:

Во-первых, определенно что-то не так с использованием d-> вещи [0] . На самом деле d-> items - это указатель, а соглашение состоит в том, что указатели и массивы в основном взаимозаменяемы (за некоторыми исключениями), а имя массива всегда будет указывать на первый элемент массива.

Во-вторых, функциональная сигнатура strncpy: char * strncpy (char * destination, const char * source, size_t num); . Поэтому, чтобы это работало, мы должны привести d-> thing из void * к char * и убедиться, что мы передаем вещь как char * (просто вещь) против char ** (который есть вещь &).

поэтому мы хотим вместо этого следующее утверждение:

strncpy ((char *) d-> вещи, вещи, d-> sizeOfThings);

После внесения изменений остальная часть кода компилируется и запускается, как и ожидалось.

0 голосов
/ 22 апреля 2011

Попробуй посмотреть, решит ли это твою проблему:

char *thing = "Me!";
strncpy(&d->things[0], thing, d->sizeOfThings);

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

char *thing = "Me!";
strncpy((char *) &d->things[0], (const char *) thing, d->sizeOfThings);
0 голосов
/ 22 апреля 2011
Demo *d = malloc(sizeof(Demo));
if (d != NULL) {
    d->things = malloc(20 * sizeOfThings); // We'll have a max of 20 things
}

Для чего инициализируется sizeOfThings? Вероятно, это может иметь мусор и вызывает ошибку. Даже если он по умолчанию инициализирован на 0 , тогда malloc возвращает NULL (malloc( 20 * 0 ) ;). И так, я подозреваю -

strncpy(d->things[0], &thing, d->sizeOfThings);
      // ^^^^^^^^^^ causing the error.
...