У меня есть простая программа для вставки элементов в конец связанного списка с помощью вызова функции.
Мой код:

struct Date{
    int data;
    struct Date *next;
};
void print(struct Date *date_head);
void add(int date, struct Date *date_head);

int main(){
    struct Date *date_head=NULL;
    add(12,date_head);
    add(15,date_head);
}
void print(struct Date *date_head){
    struct Date *ptr=date_head;
    printf("Dates: ");
    while(ptr!=NULL){
        printf("%d ",ptr->data);
        ptr=ptr->next;
    }
    printf("\n");
}
void add(int date, struct Date *date_head){
    //newDate
    struct Date *newDate;
    newDate = (struct Date *)malloc(sizeof(struct Date));
    newDate->data=date;
    newDate->next=NULL;

    //inserting newDate at end
    struct Date *date_ptr;
    date_ptr=date_head;
    if (date_ptr==NULL) {date_head=newDate;}
    else{
        while(date_ptr->next!=NULL){
            date_ptr=date_ptr->next;
        }
        date_ptr->next=newDate;
    }
    print(date_head);
}

Что я хочу:
Даты: 12
Даты: 12 15

Что я получаю:
Даты: 12
Даты: 15

Структура становится NULL вне функции добавления. Даже когда я использую указатели. Почему?
Не знаю, совершаю ли я ошибку новичка.

1
Shruti Bansal 26 Янв 2022 в 15:56
1
Помните, что аргументы функции передаются по значению. Это означает, что значение, используемое в вызове, будет скопировано в переменную аргумента функции. Изменение этой копии не изменяет оригинал. Таким образом, с присваиванием типа date_head=newDate вы присваиваете только локальную переменную аргумента, переменная или выражение, которые вы использовали в вызове, не изменят значение. Пожалуйста, изучите тему эмуляции передачи по ссылке в C. Подсказка: здесь используются указатели, оператор указателя на & и оператор разыменования *.
 – 
Some programmer dude
26 Янв 2022 в 16:01
Также и несколько не по теме: функция add очень неэффективна. Представьте, что ваш список содержит 100 000 элементов, тогда для добавления еще одного элемента вам нужно просмотреть все 100 000 существующих элементов. Обычно для связанного списка вы также должны поддерживать хвостовой указатель (указатель на последний элемент). Тогда добавление элемента происходит мгновенно.
 – 
Jabberwocky
26 Янв 2022 в 16:04
Также прочитайте это: stackoverflow.com/questions/766893/…
 – 
Jabberwocky
26 Янв 2022 в 16:08

2 ответа

Лучше хотя бы поменять местами параметры функции типа

void add(int date, struct Date *date_head, int date );

Функция принимает указатель на головной узел, объявленный в main по значению. То есть функция имеет дело с копией значения указателя. Изменение копии внутри функции отражается на исходном указателе.

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

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

С учетом всего этого объявление и определение функции будут выглядеть следующим образом.

int add( struct Date **date_head, int date )
{
    struct Date *newDate = malloc( sizeof( struct Date ) );
    int success = newDate != NULL;

    if ( success )
    {
        newDate->data = date;
        newDate->next = NULL;

        while ( *date_head != NULL ) date_head = &( *date_head )->next;

        *date_head = newDate;
    }

    return success;
}

В main вы должны написать

struct Date *date_head=NULL;
add( &date_head, 12 );
add( &date_head, 15 );

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

void print( const struct Date *date_head );

И если вы хотите добавить новый узел в конец списка, то лучше объявить двусторонний односвязный список.

0
Vlad from Moscow 26 Янв 2022 в 16:42

Вы передаете значение указателя date_head в функцию добавления, поэтому функция добавления будет иметь другую копию этого указателя, и даже если вы измените значение этого указателя в функции добавления и установите его на какой-то номер адреса, он не будет влияет на date_head, который вы создали в main, поэтому он всегда будет нулевым, вместо этого вы можете передать его по адресу:

int main(){
    struct Date *date_head=NULL;
    add(12,&date_head);
    add(15,&date_head);
}

И отредактируйте функцию добавления следующим образом:

void add(int date, struct Date **date_head){
    //newDate
    struct Date *newDate;
    newDate = (struct Date *)malloc(sizeof(struct Date));
    newDate->data=date;
    newDate->next=NULL;

    //inserting newDate at end
    struct Date *date_ptr;
    date_ptr=*date_head;
    if (date_ptr==NULL) {*date_head= newDate;}
    else{
        while(date_ptr->next!=NULL){
            date_ptr=date_ptr->next;
        }
        date_ptr->next=newDate;
    }
    print(*date_head);
}
0
Abdellah Maarifa 26 Янв 2022 в 16:54