Распечатать связанный список до определенного числа в C

Предположим, у меня есть связанный список неизвестной длины. Я хотел бы иметь функцию для печати всего списка, если длина меньше 10, а если его длина больше 10, то отображать только первые 10 узлов.

Однако, поскольку я сравниваю указатель и целое число для вывода первых 10 узлов, я получаю следующую ошибку:

ordered comparison between pointer and integer ('NodeT *' (aka 'struct node *') and 'int')
        for (current = list; current < 30; current = current->next)

Если я изменю его, чтобы иметь счетчик и цикл, пока счетчик меньше 10, я получаю ошибку сегментации.

Как я могу отобразить первые 10 узлов, если длина списка больше 10?

У меня есть следующая функция:

void *printNodes(NodeT *list) {
    
    int length = countNodes(list); // finds length of a linked list
    int count = 0; 

    NodeT *current;

    if (list == NULL) {
        printf("Empty list.\n");
    }

    if (length < 10) {
        // Display all if number of nodes is less than 10
        for (current = list; current != NULL; current = current->next) {
            printf("%s\n", current->data); 
        }

    } else {
        // Display first 10 if number of nodes more than 10 
        for (current = list; current < 10; current = current->next) {
            printf("%s\n", current->data);

        // for (current = list; count < 10; current = current->next) {
        //     printf("%s\n", current->data);
        //     count++; 

        }
    }
    return 0; 
}

person J Szum    schedule 26.01.2021    source источник
comment
Я сравниваю указатель и целое число. Так что не делай этого. Почему вы думаете, что это может работать в любом случае? Вместо этого используйте отдельный счетчик для сравнения с 10. Или вы даже можете использовать length напрямую, уменьшая его до 0.   -  person kaylum    schedule 26.01.2021
comment
Запустите его с помощью отладчика, который сообщит вам, где именно происходит segfauklt. Потратьте некоторое время на изучение отладчика. Поверьте, вложенное время очень быстро окупится.   -  person Jabberwocky    schedule 26.01.2021
comment
Затем вам нужно показать полный минимальный проверяемый пример. Возможно, countNodes ошибается. Возможно, список неправильно сформирован. Мы не можем сказать с таким неполным кодом.   -  person kaylum    schedule 26.01.2021
comment
Код, который вы закомментировали, мне кажется правильным. Поэтому, если этот код дает вам ошибку сегментации, то я подозреваю, что либо (1) функция countNodes (которую вы не показываете) предоставляет неверную информацию, либо (2) current->data не всегда указывает на допустимую строку с нулевым символом в конце. , или (3) сам связанный список поврежден. Поскольку вы не предоставили минимально воспроизводимый пример, у нас нет возможности это узнать.   -  person Andreas Wenzel    schedule 27.01.2021


Ответы (4)


Для начала тип возвращаемого значения void * функции printNodes

void *printNodes(NodeT *list) {

не имеет смысла.

Вы должны объявить функцию, по крайней мере, как

void printNodes( const NodeT *list) {

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

Если условие этого оператора if

if (list == NULL) {
    printf("Empty list.\n");
}

оценивается как логическое истинное значение, которое функция должна вернуть.

Условие цикла for, в котором указатель сравнивается с целым числом

    for (current = list; current < 10; current = current->next) {

не имеет смысла.

Функция может быть объявлена ​​и определена следующим образом.

void printNodes( const NodeT *list ) 
{
    size_t n = 10;
    
    if ( list == NULL ) 
    {
        printf("Empty list.\n");
    }
    else
    {
        for ( ; list != NULL && n--; list = list->next )
        {
            printf( "%s\n", list->data );
        }
    }
}

Другой подход — объявить еще один параметр, который будет указывать, сколько узлов списка вы хотите вывести. Например

void printNodes( const NodeT *list, size_t n ) 
{
    if ( list == NULL ) 
    {
        printf("Empty list.\n");
    }
    else
    {
        for ( ; list != NULL && n--; list = list->next )
        {
            printf( "%s\n", list->data );
        }
    }
}
person Vlad from Moscow    schedule 26.01.2021

Рассмотрите возможность адаптации основного цикла for для использования в качестве счетчика:

void printNodes(NodeT *list) {
  if (list == NULL) {
    printf("Empty list.\n");

    return; // Note no more useless "pointer" return
  }

  int limit = 10; // Could easily be an argument
  NodeT *current = list;

  for (int i = 0; current && i < limit; ++i, current = current->next) {
      printf("%s\n", current->data);
  }
}

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

В своей адаптации вы сбились с конца цепочки, не обратив внимания на свой указатель current.

person tadman    schedule 26.01.2021
comment
Я получаю следующее предупреждение - incompatible pointer to integer conversion initializing 'int' with an expression of type 'NodeT *' (aka 'struct node *') for (int i = 0, current = list; current && i < 30; i++, current = current->next) { - person J Szum; 26.01.2021
comment
Я адаптировал код, чтобы он был более последовательным. Проблема заключалась в ошибочном использовании объявления int, когда оператор , не мог справиться. - person tadman; 26.01.2021

Вы можете попробовать часть else таким образом:

for (current = list; count< 10; count++, current = current->next)
    ///your code
person Nitai Chandra Banik    schedule 26.01.2021

Вы можете использовать цикл for, как указано tadman, или цикл while, подобный этому

int counter = 0;
NodeT *current = list;
while (counter < 10 && current != NULL)
{
  /* Do your stuff */
  current = current->next;
  counter += 1;
}

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

person Germann Atakpa    schedule 26.01.2021