Привет я работаю с C, и у меня есть вопрос о присваивающихся указателях.
struct foo
{
int _bar;
char * _car[SOME_NUMBER]; // this is meant to be an array of char * so that it can hold pointers to names of cars
}
int foofunc (void * arg)
{
int bar;
char * car[SOME_NUMBER];
struct foo * thing = (struct foo *) arg;
bar = thing->_bar; // this works fine
car = thing->_car; // this gives compiler errors of incompatible types in assignment
}
автомобиль и _car имеют то же объявление итак, почему я получаю ошибку о несовместимых типах? Мое предположение - то, что это имеет некоторое отношение к ним являющийся указателями (потому что они - указатели на массивы символа *, правильно?), но я не вижу, почему это - проблема.
когда я объявил char * car;
вместо char * car[MAXINT];
это компилирует прекрасный. но я не вижу, как это было бы полезно для меня позже, когда я должен получить доступ к определенной информации с помощью индекса, это было бы очень раздражающим для доступа к той информации позже. на самом деле я даже не уверен, иду ли я о правильном пути, возможно, существует лучший способ сохранить набор строк вместо того, чтобы использовать массив символа *?
Править: Я не означал использовать INT_MAX (максимальное значение интервала), просто некоторый другой интервал, - приблизительно 20.
Вы создаете новый массив размером MAXINT. Я думаю, вы хотите создать указатель на массив размером MAXINT.
Создание указателя на массив элементов char *:
Ниже приведен массив размером MAXINT для элементов char *:
char * car[MAXINT];
Ниже приведен указатель на: массив размера MAXINT для элементов char * :
char* (*car)[MAXINT];
следующим образом вы устанавливаете указатель на: массив размера MAXINT на элементы char *:
char* (*car)[MAXINT];
car = &arg->_car;
Другие синтаксические ошибки в вопросе:
foo *
, а не foo
. Так должно быть: struct foo * thing = (struct foo *) arg;
thing
, а не arg
: bar = thing- > _bar;
car = thing -> _ car;
car
и _car
оба являются массивами, и вы не можете назначать массивы в C (кроме случаев, когда массив встроен в структуру (или объединение), и вы выполняете присваивание структуры).
Они также являются массивами указателей на char, а не указателями на массивы char. То, что вы написали в коде, вероятно, именно то, что вам нужно - вы можете хранить указатели до MAXINT имен в массиве. Однако вы должны правильно описать тип - как массив указателей на указатели char или char.
Указатель на массив символов будет выглядеть так:
char (*car)[MAXINT];
А точка на массив символьных указателей (спасибо, Брайан) будет выглядеть так:
char *(*car)[MAXINT];
Будьте осторожны с MAXINT; это может быть очень большой массив (в Linux
определяет MAXINT
как INT_MAX
, что составляет не менее 2 31 ] -1).
Код выглядит так:
struct foo
{
int _bar;
char * _car[MAXINT];
}
int foofunc (void * arg)
{
int bar;
char * car[MAXINT];
struct foo thing = (struct foo *) arg;
bar = arg->_bar; // this works fine
car = arg->_car; // this gives compiler errors of incompatible types in assignment
}
Ни присвоение bar, ни car не должны компилироваться вообще - arg
является void *
. Вы, вероятно, хотели использовать вещь
в той или иной форме. Как заметил Брайан, здесь тоже есть проблемы:
Вы либо хотите:
int foofunc(void *arg)
{
int bar;
char *car[MAXINT];
struct foo thing = *(struct foo *)arg;
bar = thing._bar; // this works fine
car = thing._car; // this is still an array assignment
...other code using bar and car...
}
Или вы хотите:
int foofunc(void *arg)
{
int bar;
char *car[MAXINT];
struct foo *thing = (struct foo *) arg;
bar = thing->_bar; // this works fine
car = thing->_car; // this is still an array assignment
...other code using bar and car...
}
Или, действительно:
int foofunc(void *arg)
{
struct foo *thing = (struct foo *) arg;
int bar = thing->_bar; // this works fine
char *car[MAXINT] = thing->_car; // this is still an array assignment
...other code using bar and car...
}
Наконец, имея дело с присваиванием массива, в C вы можете разумно использовать memmove ()
для этого:
int foofunc(void *arg)
{
struct foo *thing = (struct foo *) arg;
int bar = thing->_bar; // this works fine
char *car[MAXINT];
memmove(car, thing->_car, sizeof(car));
...other code using bar and car...
}
Аналогичная функция memcpy ()
не имеет надежной семантики, если области, которые нужно скопировать, перекрываются, тогда как memmove ()
делает; проще всегда использовать memmove ()
, потому что он всегда работает правильно.В C ++ следует проявлять осторожность при использовании memmove ()
(или memcpy ()
). В этом коде это было бы достаточно безопасно, но понять почему нетривиально.
Вы должны знать, что вы просто копируете здесь указатели - вы не копируете строки, на которые они указывают. Если что-то еще изменяет эти строки, это влияет как на значения, видимые через car
, так и на переменную в вызывающем коде.
И последнее замечание - пока: вы уверены, что вам нужен аргумент функции как void *
? Он открывает код для всех видов злоупотреблений, которые можно предотвратить, если объявить, что функция принимает вместо этого ' struct foo *
' (или даже ' const struct foo *
' ).
Вы не можете назначить массив так, как вы это делаете. Можно делать поэлементное копирование.
for(int i = 0; i < MAXINT; i++)
{
car[i] = (arg->_car)[i]
}
Обратите внимание: если строки не являются постоянными, вам может потребоваться использовать strcpy
.
Нотация массивов в C закономерно сбивает с толку; ваш код не означает то, что вы думаете.
arg -> _ car
означает «адрес массива _car
». Аналогично, car
означает «адрес массива car
». Если вы пытаетесь скопировать содержимое _car в car, это сделает это:
memcpy(car, _car, MAXINT);
Но ваш настоящий вопрос, я думаю, таков: «Как лучше всего хранить список строк?» Этот ответ: динамический список (который автоматически увеличивается по мере добавления элементов).
Вы бы объявили это так:
#define CARSIZE 65
int numCars = 0;
char **car; /* a list of addresses, each one will point to a string */
Чтобы добавить машину:
char *newCar = malloc(CARSIZE); /* make room */
strncpy(newCar, "Mercedes", CARSIZE); /* newCar has the address of the string */
car[numCars++] = newCar; /* store it */
Чтобы перечислить машины:
int n;
for (n = 0; n < numCars; ++n)
printf("%s\n", car[n]);
Чтобы удалить машину в позиции n:
free(car[n]); /* release the memory */
/* condense the list of pointers */
for ( ; n < numCars - 1; ++n)
car[n] = car[n+1];
Это обычная процедура в C. ПРИМЕЧАНИЕ: Вышесказанное не принадлежит мне в голову и не скопировано из работающей программы, поэтому я не могу обещать, что все * находятся в нужном месте. Я подозреваю, что это домашнее задание, поэтому я не хочу давать вам все ...