Незаконное использование селектора в C

В рамках более крупного проекта я пытаюсь написать функцию C, которая ищет в реализованном отсортированном связанном списке значение в структуре olnode. Однако я получаю несколько ошибок. Я новичок в C, и я борюсь с указателями и двойными указателями и когда что использовать, поэтому я думаю, что это часть проблемы, но я не уверен, как решить проблему. Все необходимые заголовки включены. Это на Minix 2.0.4 с использованием cc в качестве компилятора.

Могу предоставить любой дополнительный необходимый код; поскольку я не знаком с C, я не уверен, сколько мне нужно показать, поэтому я предоставляю то, что, по моему мнению, необходимо, и ничего больше, чтобы быть кратким.

Глобальный код (кроме заголовков):

#define POOLSZ 53
struct olnode {
    int eventnr;
    int eventfq;
    struct olnode *next;
};
typedef struct olnode olnode;
olnode pool[POOLSZ];
olnode *avail;    /* points to first available node */

Функция, которая возвращает ошибки (ищет переданный int, после завершения *current должен быть olnode, который содержит текущее значение):

void
srchfreq(olnode *list, int xfrequency, olnode **current)
{
    olnode *previous, *newnext;

    while(current->eventfq > xfrequency) {
        *previous = &current;
        *newnext = current->next;
        *current = *newnext;
    }
}

Вызов функции srchfreq() (в другой функции):

/* *list points to the first node in the list
   (*current).eventfq is the value being searched for
*/

srchfreq(*list, (*current).eventfq, &current);

Ошибки (номера строк отредактированы относительно строк в srchfreq(), как указано выше):

line 6: illegal use of selector eventfq
line 7: cannot convert pointer to struct
line 8: illegal use of selector next
line 8: cannot convert pointer to struct
line 9: cannot convert struct to pointer

person vaindil    schedule 30.01.2015    source источник


Ответы (3)


void
srchfreq(olnode *list, int xfrequency, olnode **current)
{
    olnode *previous, *newnext;

    while((*current)->eventfq > xfrequency) {
        previous = *current;
        newnext = (*current)->next;
        *current = newnext;
    }
}

Вторая часть зависит от типов аргументов. Если list объявлено как olnode *list, нет необходимости разыменовывать его, так как функция ожидает указатель. Второй и третий аргументы неверны (один из них — чтобы определить, какой из них нам нужно знать, как объявляется current).

person keltar    schedule 30.01.2015
comment
list изначально объявлен как olnode *list;, а current объявлен как olnode *current;. - person vaindil; 30.01.2015
comment
Тогда последняя строка должна быть srchfreq(list, (*current)->eventfq, &current);. Это означает, что current, конечно же, правильно установлен в первый элемент. - person keltar; 30.01.2015
comment
После объявления *current следующая строка — *current = **list;. olnode **list — это то, что передается функции (назовем ее A()), которая вызывает srchfreq(), а A() — это то, что объявляет current. Я пытаюсь понять концепцию указателей; Я не совсем понимаю, как добавление *s к параметрам меняет действие этого параметра в функции. Если бы current было передано srchfreq() как *current вместо существующего **current, как бы это изменило ситуацию? (Не обязательно с точки зрения кода, но концептуально.) - person vaindil; 30.01.2015
comment
Ваш поиск должен где-то сохранить результат. Результатом поиска является указатель. По какой-то причине вы решили использовать выходной параметр вместо возвращаемого значения - это странно, но вполне нормально. Но в C все параметры передаются по значению - это означает, что ваша функция может их изменять, но вызывающая сторона никогда не увидит изменений. Чтобы действительно что-то изменить, вы передаете указатель туда, где хотите сохранить результат. Тип результата, который вы хотите, - olnode*, поэтому указатель на olnode* будет olnode**. Общий совет здесь: не добавляйте дополнительные слои указателей (и, следовательно, дополнительные *), если они вам не нужны. - person keltar; 30.01.2015
comment
Хорошо, это имеет большой смысл. Я не хочу напрямую запрашивать код, так как хочу понять концепции, но я не могу понять - что мне тогда нужно, чтобы установить *current внутри A()? Я думал, что это должно быть **current = *list; на основе вашего комментария, но я получаю ошибки с этим. Поскольку **list объявлено как olnode, должно ли оно быть **current = ***list;? (Логика: current должен быть типа olnode**, поэтому это **current, а так как **list передается в функцию, то ***list необходим, чтобы сделать его правильным указателем. Я действительно не уверен.) - person vaindil; 30.01.2015
comment
Нет, это не так. Вы хотите, чтобы результат указателя был current, поэтому его тип должен быть olnode* (и, следовательно, &current, которое вы передаете функции, становится olnode**), поэтому функция может изменить значение этого указателя. Но он также считывает свое значение перед его изменением, поэтому вам нужно правильно установить значение. Это current=list, если оба типа olnode*. По сути, тип &current - это olnode**, но тип *current - это olnode - оператор * имеет разное значение для объявления переменной и ее использования. cdecl может помочь вам разобраться в концепциях. - person keltar; 31.01.2015

current имеет тип olnode** или указатель на указатель на старый узел. Чтобы получить указатель на olnode, разыменуйте указатель один раз:

*current;

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

**current;

Итак, в вашем случае, чтобы захватить поле eventfq

(**current).eventfq

C также предоставляет ярлык, где операция (*ptr).field точно эквивалентна prt->field.

В вашем случае вы можете применить это с помощью

(*current)->eventfq
person Chris Rice    schedule 30.01.2015

Ошибки в порядке появления:

  • Поскольку current является указателем на указатель на olnode, он не может напрямую ссылаться ни на какие поля; но *current может.
  • *previous — это olnode, &current — это указатель на указатель на указатель на olnode.
  • Смотри первую ошибку
  • *newnext is a olnode
  • *current является указателем на olnode
person Scott Hunter    schedule 30.01.2015
comment
Я исхожу из Python и Java; Я пытаюсь понять концепцию указателей. current передается в функцию как **current. Следовательно, если я правильно понимаю, именно тот факт, что у него есть два *, делает его указателем на указатель. Почему же тогда добавление третьего * приводит к прямой ссылке на olnode? Я бы подумал, что это сделало бы его указателем на указатель на указатель, хотя вы сказали, что это &current. (Я пытаюсь понять это, я извиняюсь, если это покажется вам ошибкой. Я действительно понятия не имею, поэтому я не пытаюсь быть таким.) - person vaindil; 30.01.2015
comment
* — это оператор разыменования: следуйте указателю. (И, как вы, кажется, понимаете, & является противоположным оператором, так что *&x совпадает с x.) Таким образом, объявление clnode **current следует читать как clnode, которое вы получите после двукратного разыменования current. - person Scott Hunter; 30.01.2015