Недопустимое lvalue в ошибке присваивания при попытке сделать указатель NULL

У меня есть указатель структурного типа, который я сделал. При запуске программы он начинается как NULL, а затем я использую malloc/realloc, поскольку мне нужно добавить/удалить эти структуры, и я просто собирался использовать свой указатель, чтобы указать на первую структуру и перемещаться по ней как по массиву.

Когда я malloc/realloc, я всегда делаю размер «массива»/области в памяти на единицу больше, чем нужно. Я делаю это, чтобы установить для «последнего индекса»/области в памяти значение NULL, чтобы я мог сказать что-то вроде while (указатель! = NULL).

Я получаю сообщение об ошибке: неверное lvalue в назначении, когда пытаюсь присвоить NULL последней позиции в массиве/области памяти со строками:

  // Realloc remotelist by adding one to connrhosts
  connrhosts++;
  remotelist = realloc(remotelist, sizeof(rhost)*(connrhosts + 1));
  (remotelist + connrhosts) = NULL;

Я думаю, что я говорю:

  • Пришло время добавить новую структуру в мой массив, поэтому я увеличу число connrhosts на единицу.
  • Перераспределите память, указанную в remotelist, в новую область памяти размером с connrhosts (сколько структур я буду использовать), а также одно дополнительное пространство, чтобы я мог сделать его NULL
  • Укажите remotelist на новую область памяти
  • Используйте мой указатель remotelist и добавьте смещение connrhosts, которое теперь будет указывать на последний индекс области памяти и сделает этот указатель NULL.

Насколько я могу судить (или чувствовать), я все сделал правильно, но я уже некоторое время работаю над этим проектом и у меня сложилось впечатление, что у меня узкое зрение. Я бы хотел, чтобы свежий взгляд взглянул на мою логику/код и дал мне знать, что они думают и что я сделал неправильно. Спасибо еще раз. :D

Изменить. Часть моей проблемы заключается в том, что я неправильно понимаю, что я могу делать с указателями.

Вот моя структура:

typedef struct {
  char address[128]; // Buffer that holds our address of the remote host
  int port; // Port of the remote host
  int conn; // FD to the connection of our remote host
  int ofiles; // Open files associated with the remote host
} rhost;

Я надеялся, что смогу прокрутить свой массив/область памяти и сказать, что если это не NULL, то сделайте что-нибудь с ним. Итак, мой исходный оператор цикла - это while (NULL != remotelist). Теперь я считаю, что читаю ответы и комментарии о том, что эта логика неверна, потому что я проверяю, является ли указатель нулевым? Я должен проверить, является ли область памяти/структуры, на которую указывает указатель, нулевой? Если это так, то должно быть что-то вроде while (NULL != *(remotelist + someoffset))?

Я делаю это так, как мой учитель предложил/говорил об этом в классе.

Мое первоначальное объявление/инициализация удаленного списка было следующим: rhost *remotelist = NULL;


person Chris    schedule 07.03.2010    source источник
comment
Кстати, почему вы делаете ++connrhosts, а затем используете connrhosts + 1 в распределении? Какова цель этого дополнительного + 1?   -  person AnT    schedule 08.03.2010
comment
connrhosts — это текущее количество удаленных хостов, к которым я тоже могу подключиться. Так что в моем массиве, если бы их было два и я не делал connrhosts + 1, у меня было бы только два индекса, 0 и 1, и оба указывали бы на структуру. Я делаю + 1, поэтому у меня может быть три индекса: 0, 1 и 2, где 0 и 1 указывают на структуру, а 2 может быть равно NULL. Таким образом, у меня могут быть такие операторы, как while (NULL != remotelist)   -  person Chris    schedule 08.03.2010
comment
рост - это структура. Созданное вами выделение, на которое указывает remotelist, представляет собой массив этих структур, а не массив указателей. Вы не можете установить структуру в NULL, поэтому вам понадобится другой способ обозначить конец списка. Один из способов — сохранить целое число вместе со счетчиком и передать его вместе с указателем. Другой способ - использовать одно из полей rhost в качестве маркера конца данных, например сказать, что если ofiles равно -1, это означает конец массива. Вы можете использовать фактический массив указателей с нулевым завершением. Я не рекомендую это: вам придется выделять их отдельно.   -  person Steve Jessop    schedule 08.03.2010
comment
Что, если я скажу что-то вроде rhost **remotelist; Затем remotelist = realloc(remotelist, sizeof(*rhost)*(connrhosts + 1)); Смогу ли я тогда установить эти указатели в NULL?   -  person Chris    schedule 08.03.2010
comment
Вы бы это сделали, но все, что вы получите, это массив указателей. Затем вы можете выделить несколько объектов rhost отдельно. Это sizeof(rhost*), или sizeof(*remotelist), а не sizeof(*rhost).   -  person Steve Jessop    schedule 08.03.2010


Ответы (5)


Ошибочные присваивания lvalue возникают, когда LHS является оцениваемым выражением, которое не становится переменной, которую можно присвоить. То, что вы делаете, выглядит как операция (арифметика указателя), которая должна быть на RHS.

Что вы можете сделать, это:

remotelist[connrhosts] = NULL;  // array notation asuming 
                                // remotelist is an array of pointers

предполагая, что connrhosts - это int или size_t, или вы можете сделать:

remotelist += connrhost; // pointer arithmetic
*remotelist = NULL; // assuming remotelist is an array of pointers.
person Community    schedule 07.03.2010
comment
Не будет удаленного списка += connrhost; // арифметика указателя *remotelist = NULL; на самом деле изменить адрес, на который указывает мой указатель? Если да, то это будет проблемой для меня. Я добавлял смещение или connrhosts, чтобы я мог сказать, что это много мест вдали от начала делают NULL. Я также предоставил дополнительную документацию по своей структуре и тому, что, как мне казалось, я делал. - person Chris; 08.03.2010
comment
Да, увеличивает указатель на блоки connrhost типа remotelist. После этого вам придется переместить его обратно. Я включил оба варианта для полноты. Я дал +1 к ответу ниже, который предположил, что обозначение [] было чище - это так. - person ; 08.03.2010
comment
Я пошел дальше и попытался использовать нотацию [], но затем получил ошибку несовместимых типов в присваивании. Значит, я раньше что-то делал не так, или я просто понятия не имею, что делаю? - person Chris; 08.03.2010
comment
Похоже, вы где-то перепутали типы, но взгляните на комментарий Стива Джессопа к вашему вопросу. Похоже, вы пытаетесь эмулировать строки, которые заканчиваются символом \0. Это на самом деле равно 0, поэтому последнее целое равно 0, если это имеет смысл, что отличается от NULL, который является void * ничем. - person ; 08.03.2010

Вам также необходимо разыменовать указатель.

*(remotelist + connrhosts) = NULL;

Хотя я думаю

 remotelist[connrhosts] = NULL; 

яснее.

person John Knoeller    schedule 07.03.2010

Вам нужно разыменовать указатель с помощью *, чтобы получить доступ к тому, что хранится в памяти, адресуемой указателем.

*(remotelist + connrhosts) = NULL;
person Jason Kresowaty    schedule 07.03.2010

Выражение pointer != NULL относится к самому указателю, а не к памяти, на которую ссылается указатель. Даже если вы можете присвоить ему значение NULL, это не решит проблему.

После увеличения указателя он не равен NULL, в нем есть адрес, адрес вашего последнего дополнительного слота структуры.

Я полагаю, вы могли бы установить эту область в 0 с помощью:

memset(remotelist + connrhosts, 0, sizeof(rhost));

Затем вы можете сделать что-то вроде p->field == 0, если это поле никогда не равно 0 в реальной структуре...

Лично я бы справился с этой проблемой, если я правильно понял, либо выделением второго массива указателей на структуры, либо просто отслеживанием их количества, либо, что наиболее вероятно, использованием коллекции типа связанной список или дерево, то есть что-то с более изящными операциями раскрытия, чем realloc().

person DigitalRoss    schedule 07.03.2010

«Область памяти/структуры» нельзя присвоить NULL и нельзя сравнивать с NULL. NULL используется только с указателями.

Если вы хотите установить все поля [нововыделенной] структуры в нули, в C89/90 распространена идиома — сделать это с помощью инициализатора = { 0 }:

const rhost ZERO_HOST = { 0 };
...
connrhosts++; 
remotelist = realloc(remotelist, connrhosts * sizeof *remotelist); 
remotelist[connrhosts] = ZERO_HOST; 

Или вы можете просто использовать memset (это хак).

Что касается проверки того, является ли запись в вашем массиве нулевой... Для этого нет встроенной операции, хотя функция memcmp может помочь

if (memcmp(&remotelist[i], &ZERO_HOST, sizeof ZERO_HOST) == 0)
  /* All zeroes */;

(это тоже немного хак, хотя и менее "хакерский", чем memset).

но обычно так не делают. Да и смысла так делать нет. Как правило, вы должны просто выбрать только одно поле в своей структуре («основное»), которое может сказать вам, используется ли структура: или нет, и сравнить только это единственное поле с 0

if (remotelist[i].address[0] == '\0')
  /* Entry is not used */;
person AnT    schedule 07.03.2010