#c #pointers #linked-list #side-effects
#c #указатели #связанный список #побочные эффекты
Вопрос:
Я получаю этот странный побочный эффект при использовании operator ‘->’ в коде, который я написал на C. Указатель, который я использовал -> on , изменен, чтобы содержать некоторый мусор.
Более конкретно:
У меня есть следующие структуры:
typedef void* ListElement ;
typedef struct List_t* List ;
typedef struct Node_t* Node;
Struct Node_t {
ListElement data ;
Node next;
}
Struct List_t {
Node* head;
Node* current
}
когда я использую следующее ListGetFirst()
, я получаю проводное поведение :
ListElement ListGetFirst(List list)
{
if( list == NULL || list->head==NULL)
{
return NULL;
}
list->current=list->head;
Node* head =list->head; // here is the problem
ListElement data = (*head)->data;
return data;
}
когда я использовал debugger, я выяснил, что список указателей-> head изменен в отмеченной строке, упомянутой выше.
Я действительно понятия не имею, почему, и я не знал, что ‘->’ может иметь побочный эффект
заранее спасибо
Комментарии:
1. Скорее всего, вы неправильно интерпретируете происходящее.
2. Нет, -> не имеет побочных эффектов в C. Почему бы просто не сделать
return list->head->data
?3. Это ваш код, а не «побочный эффект»
->
. В этом можно не сомневаться.4. @meagar — если это мой код, пожалуйста, помогите мне найти ответ, я в отчаянии
5. Вы просто не должны использовать typedefs, которые скрывают тот факт, что типы являются указателями. Нас всех это смущает!
Ответ №1:
Вы уверены, что это именно то, что вы хотите сделать?
typedef struct Node_t* Node;
Node* head =list->head;
Поскольку вы определили Node как указатель на Node_t, разве вы не должны делать:
Node head =list->head;
Редактировать:
Подводя итог всему этому, я думаю, что этот typedef вводит вас в заблуждение:
typedef struct Node_t* Node;
Это имело бы больше смысла, если бы это было просто:
typedef struct Node_t Node;
Комментарии:
1. @karlphillip — посмотри на структуру . Я решил иметь в структуре list_t переменные Node* , а не Node.
2. Я думаю, что у Карла есть это; вы используете Node *, который является адресом указателя, а не значением указателей, которое было бы адресом списка.
3.@RanZilber То, что вы делаете в своем коде, эквивалентно
Node_t** head = list->head;
и вам явно нужно сделатьNode_t* head = list->head;
, что может быть достигнуто с помощьюNode head = list->head;
4. @karlphillip — но list-> head имеет тип Node * , или Node_t ** , вот как я это определил.
5. Да! Используйте
Node head =list->head;
вместо этого. Код поврежден. Если у вас это получилось таким образом, и вы хотите, чтобы это работало, вам придется это исправить.
Ответ №2:
Блин, указатели, скрытые за typedefs; если тип не должен быть полностью непрозрачным, это почти всегда плохой juju. Для моей пользы я собираюсь удалить typedefs, чтобы мне было легче видеть, с чем вы на самом деле играете.
struct Node_t {
void *data ;
struct Node_t *next;
};
struct List_t {
struct Node_t **head;
struct Node_t **current;
};
void *ListGetFirst(struct List_t *list)
{
if( list == NULL || list->head==NULL
{
return NULL;
}
list->current=list->head;
struct Node_t **head =list->head; // here is the problem
void *data = (*head)->data;
return data;
}
Я ничего не получил. Кажется, что все типы совпадают. ->
Оператор, что наиболее важно, не имеет никаких побочных эффектов; все, что он делает, это разыменовывает указатель. Дополнительный уровень косвенности для head
и current
в struct List_t
вызывает недоумение, и это заставляет меня задуматься, правильно ли они распределяются. Все, что я могу понять, это то, что list->head
указывает не на память, которой вы на самом деле владеете, и каким-то образом перезаписывается, когда вы достигаете этой точки (IOW, вы вызвали неопределенное поведение где-то еще в вашем коде).
Короче говоря, проблема не в коде, который вы опубликовали. Вероятно, именно здесь вы выделяете и присваиваете элементы списка.
Комментарии:
1. Спасибо, это ответ, который я искал
Ответ №3:
Вы используете указатели на указатели, где, скорее всего, вам нужны указатели.
В List_t вы определяете head как Node*, где Node уже является Node_t * .
hth
Марио
Комментарии:
1. Разве это не то, что я опубликовал в своем ответе 4 минуты назад? = P
2. @Mario The Spoon — Меня попросили создать список таким образом. Я знаю, что это странно, и лучшим решением было бы построить его всего с одним указателем — но я ограничен этим решением. Почему это должно быть проблемой?
3. @karlphillip: grrrrrrrrrrr 😉
4. @RanZilber: какое требование заставило вас это сделать? Это просто не имеет никакого смысла…
5. @Mario, они просили тебя создать двусвязный список ?)