Печать только некоторых элементов списка с помощью указателей - PullRequest
0 голосов
/ 23 апреля 2019

Создание функции, которая получает два списка (L1, L2), инициализирует L2 и вставляет в L2 элементы L1, за исключением элементов в нечетном положении (предположим, что первый элемент списка находится в нулевой позиции).Затем напечатайте L2.

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

Я попытался инициализировать L1 и затем вызвать функцию, но все, что я получил, это огромное количество ошибок.

Это последняя функция:

struct list{
    int value;
    struct list * nextPtr;
};
void createSubList(struct list * l1Ptr, struct list ** l2PtrPtr) {
    init(l2PtrPtr);
    while(l1Ptr!=NULL) {
        pre_insert(l2PtrPtr, l1Ptr­>value);
        l1Ptr = l1Ptr­>nextPtr;
        if (l1Ptr != NULL)
            l1Ptr = l1Ptr­>nextPtr;
    }
}

Я ожидаю увидетьL2 печатается после вызова функции.Это мой окончательный файл:

#include <stdlib.h> 
#include <string.h> 



struct list {
    int value;
    struct list *nextPtr;

    };


void init( struct list **ptrptr){
    *ptrptr!=NULL;

}
void prn (struct list * lptr) { 
    while (lptr) { 
        printf (" %d", lptr->value); 
        lptr = lptr->nextPtr; 
    } 
    putchar ('\n'); }
void pre_insert(struct list ** ptrptr, int value){
    struct list * tmp_ptr;
    tmp_ptr=*ptrptr;
    *ptrptr=(struct list *)malloc(sizeof(struct list));
    (*ptrptr)->value=value;
    (*ptrptr)->nextPtr=tmp_ptr;
}

   void createSubList(struct list* l1Ptr, struct list** l2PtrPtr) {
    init(l2PtrPtr);
    while(l1Ptr!=NULL) {
        pre_insert(l2PtrPtr, l1Ptr->value);
        l1Ptr = l1Ptr->nextPtr;
        if (l1Ptr != NULL)
            l1Ptr = l1Ptr->nextPtr;
    }
    prn(l1Ptr);
    }



void main(){
    struct list* l1Ptr; 
    init(&l1Ptr);
    struct list* l2ptr; 
    init(&l2ptr);
    pre_insert(&l1Ptr , 1);
    pre_insert(&l1Ptr , 2);
    pre_insert(&l1Ptr , 3);
    pre_insert(&l1Ptr , 4);
    pre_insert(&l1Ptr , 5);
    pre_insert(&l1Ptr , 6);
    createSubList(l1Ptr,&l2ptr);


}



Ошибки, которые я получаю:

[Finished in 0.1s with exit code -11]
[shell_cmd: gcc "/home/vittorio/Scrivania/CProjects/new.c" -o "/home/vittorio/Scrivania/CProjects/new" && "/home/vittorio/Scrivania/CProjects/new"]
[dir: /home/vittorio/Scrivania/CProjects]
[path: /home/vittorio/bin:/home/vittorio/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin]

Ответы [ 2 ]

0 голосов
/ 23 апреля 2019
  • Вам необходимо добавить #include <stdio.h>

  • В функции init код *ptrptr!=NULL; должен быть *ptrptr=NULL;, т. Е. Нет !

  • Затем измените void main(){ на int main(){

Это должно устранить предупреждения.

Тогда вам нужно сделать фактическую печать. Так что в main сделать:

prn(l1Ptr);
createSubList(l1Ptr,&l2ptr);
prn(l2ptr);

Кстати: обратите внимание, что prn(l1Ptr); внутри createSubList не будет ничего печатать, поскольку l1Ptr уже имеет значение NULL, когда вы звоните prn. Поэтому вы должны просто удалить эту строку.

С указанным выше изменением ваш результат должен быть:

 6 5 4 3 2 1
 2 4 6

Созданный подсписок возвращается по сравнению с исходным списком из-за использования pre_insert, добавляющего новые узлы впереди.

0 голосов
/ 23 апреля 2019

Как только вы получите не-ASCII символы в квадрате. Возьмите свою реализацию по частям. Для начала, если вы не используете несоответствующую систему, правильные объявления для main: int main (void) и int main (int argc, char **argv) (которые вы увидите написанными с эквивалентом char *argv[]). примечание: main является функцией type int и возвращает значение. См .: Стандарт C11 §5.1.2.2.1 Запуск программы p1 (черновик n1570) . См. Также: Что должно возвращать main () в C и C ++? .

Итак, для соответствующей реализации main() без аргументов должно быть:

int main (void) {

    struct list *l1Ptr = NULL; 
    struct list *l2ptr = NULL; 
    ...

( примечание: просто отключите вашу init() функцию, вам не нужно использовать служебный вызов только для установки указателя NULL)

Следующая проблема на этом пути - ваш pre_insert должен различать добавление 1-го узла в список и добавление всех остальных. Для 1-го узла просто установите *ptrptr на инициализацию tmp_ptr, чтобы установить заголовок списка. Для остальных узлов вы используете chaining , где вы устанавливаете tmp_ptr->nextPtr = *ptrptr;, чтобы следующий указатель в новом узле указывал на старое начало вашего списка, затем устанавливаете *ptrptr = tmp_ptr;, чтобы сделать его новым начало списка, например

void pre_insert (struct list **ptrptr, int value)
{
    struct list *tmp_ptr = malloc (sizeof *tmp_ptr); /* don't cast malloc */
    if (tmp_ptr == NULL) {                  /* validate EVERY allocation */
        perror ("malloc-tmp_ptr");
        exit (EXIT_FAILURE);
    }
    tmp_ptr->value = value;         /* initialize struct members */
    tmp_ptr->nextPtr = NULL;

    if (!*ptrptr)                   /* if 1st node, simply assign */
        *ptrptr = tmp_ptr;
    else {
        tmp_ptr->nextPtr = *ptrptr; /* otherwise, set tmp->next to 1st */
        *ptrptr = tmp_ptr;          /* now set list to point to tmp */
    }
}

У вашего createSubList была похожая избыточная логика, показывающая, что вы боролись. Все, что вам нужно, это просто 1/0 переключатель , чтобы добавить или пропустить узлы из списка1. Например:

void createSubList (struct list *l1Ptr, struct list **l2PtrPtr)
{
    int i = 0;

    while (l1Ptr != NULL) {
        if (i == 0) {       /* only store even nodes */
            pre_insert (l2PtrPtr, l1Ptr->value);
            i = 1;
        }
        else
            i = 0;
        l1Ptr = l1Ptr->nextPtr;
    }
}

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

void prnlist (struct list *lptr)
{
    while (lptr) {
        printf (" %d", lptr->value);
        lptr = lptr->nextPtr;
    }
    putchar ('\n');
}

void freelist (struct list *lptr)
{
    while (lptr) {
        struct list *victim = lptr;
        lptr = lptr->nextPtr;
        free (victim);
    }
}

( примечание: видите ли вы, почему вы должны сохранить указатель на текущий узел, а затем переместить узел перед вызовом free на вашем victim?)

Вот и все, кроме моих дополнительных комментариев в строке. Сложив все это, вы можете сделать:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct list {
    int value;
    struct list *nextPtr;
};

void pre_insert (struct list **ptrptr, int value)
{
    struct list *tmp_ptr = malloc (sizeof *tmp_ptr); /* don't cast malloc */
    if (tmp_ptr == NULL) {                  /* validate EVERY allocation */
        perror ("malloc-tmp_ptr");
        exit (EXIT_FAILURE);
    }
    tmp_ptr->value = value;         /* initialize struct members */
    tmp_ptr->nextPtr = NULL;

    if (!*ptrptr)                   /* if 1st node, simply assign */
        *ptrptr = tmp_ptr;
    else {
        tmp_ptr->nextPtr = *ptrptr; /* otherwise, set tmp->next to 1st */
        *ptrptr = tmp_ptr;          /* now set list to point to tmp */
    }
}

void createSubList (struct list *l1Ptr, struct list **l2PtrPtr)
{
    int i = 0;

    while (l1Ptr != NULL) {
        if (i == 0) {       /* only store even nodes */
            pre_insert (l2PtrPtr, l1Ptr->value);
            i = 1;
        }
        else
            i = 0;
        l1Ptr = l1Ptr->nextPtr;
    }
}

void prnlist (struct list *lptr)
{
    while (lptr) {
        printf (" %d", lptr->value);
        lptr = lptr->nextPtr;
    }
    putchar ('\n');
}

void freelist (struct list *lptr)
{
    while (lptr) {
        struct list *victim = lptr;
        lptr = lptr->nextPtr;
        free (victim);
    }
}

int main (void) {

    struct list *l1Ptr = NULL; 
    struct list *l2ptr = NULL; 

    for (int i = 1; i < 10; i++)
        pre_insert (&l1Ptr , i);

    createSubList (l1Ptr, &l2ptr);

    prnlist (l2ptr);    /* print list 2 */

    freelist (l1Ptr);   /* don't forget to free what you allocate */
    freelist (l2ptr);
}

Пример использования / вывода

$ ./bin/llcreatesublist
 1 3 5 7 9

Использование памяти / проверка ошибок

В любом написанном вами коде, который динамически распределяет память, у вас есть 2 обязанности в отношении любого выделенного блока памяти: (1) всегда сохраняйте указатель на начальный адрес для блока памяти, таким образом, (2) он может быть освобожден , когда он больше не нужен.

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

Для Linux valgrind - нормальный выбор. Для каждой платформы есть похожие проверки памяти. Все они просты в использовании, просто запустите вашу программу через него.

$ valgrind ./bin/llcreatesublist
==23324== Memcheck, a memory error detector
==23324== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==23324== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==23324== Command: ./bin/llcreatesublist
==23324==
 1 3 5 7 9
==23324==
==23324== HEAP SUMMARY:
==23324==     in use at exit: 0 bytes in 0 blocks
==23324==   total heap usage: 14 allocs, 14 frees, 224 bytes allocated
==23324==
==23324== All heap blocks were freed -- no leaks are possible
==23324==
==23324== For counts of detected and suppressed errors, rerun with: -v
==23324== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

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

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...