Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 14.10.2010, 23:57   #1
maryan.vetrov
Пользователь
 
Регистрация: 07.06.2010
Сообщений: 75
По умолчанию Связанный список на СИ

Доброго времени суток! Разбираюсь со связанными списками. Написал простой код, который должен создавать простой связанный список, в котором будут храниться имена вводимые пользователем. После окончания ввода, список выводиться на экран. При выполнении моего кода, весь список , заполняется тем именем, котрое было введено последним. Т.е. если я вводил три имени, то выводятся три одинаковые последние. Подскажите где ошибка? Только начал работать со списками, видно чего-то не допонимаю. Выкладываю свой код
Код:
#include <stdio.h>
#include <stdlib.h>

struct example{
    char *name;
    struct example *nextPtr;
};

typedef struct example EXAMPLE;

main()
{
    EXAMPLE *newPtr=NULL,*currentPtr=NULL,*previousPtr=NULL,*startPtr=NULL;
    char c,b[25];
    
    printf("Vvedite imia: ");
    scanf("%s",b);
    while((c=getchar())!=EOF){
        newPtr=malloc(sizeof(EXAMPLE));
        if(newPtr!=NULL){
            newPtr->name=b;
            newPtr->nextPtr=NULL;
            previousPtr=NULL;
            currentPtr=startPtr;

            /*while(currentPtr!=NULL){
                previousPtr=currentPtr;
                currentPtr=currentPtr->nextPtr;
            }*/
            if(previousPtr==NULL){
                newPtr->nextPtr=startPtr;
                startPtr=newPtr;
            }
            else{
                previousPtr->nextPtr=newPtr;
                newPtr->nextPtr=currentPtr;
            }
        }

            else
                printf("Nedostatochno pamiaty.\n");
    printf("Vvedite imia: ");
    scanf("%s",b);
    }
    
    printf("\nThis is thei list: \n");
    while(startPtr!=NULL){
        printf("%s->",startPtr->name);
            startPtr=startPtr->nextPtr;
    }

       
    return 0;
}
Заранее благодарен.
maryan.vetrov вне форума Ответить с цитированием
Старый 15.10.2010, 00:26   #2
sergey.d
Пользователь
 
Регистрация: 23.08.2010
Сообщений: 98
По умолчанию

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

Чтобы исправить, нужно вместо
Код:
newPtr->name=b;
написать что-то вроде такого:
Код:
newPtr->name = strcpy((char*)malloc(strlen(b) + 1), b);
и, соответственно, позаботиться о освобождении выделяемой памяти при удалении списка. Кстати, я вообще не увидел освобождения памяти при завершении программы.

Последний раз редактировалось sergey.d; 15.10.2010 в 00:35.
sergey.d вне форума Ответить с цитированием
Старый 15.10.2010, 02:46   #3
maryan.vetrov
Пользователь
 
Регистрация: 07.06.2010
Сообщений: 75
По умолчанию

Цитата:
Сообщение от sergey.d Посмотреть сообщение
Чтобы исправить, нужно вместо
Код:
newPtr->name=b;
написать что-то вроде такого:
Код:
newPtr->name = strcpy((char*)malloc(strlen(b) + 1), b);
Спасибо, так действительно работает. Хочу уточнить правильно ли я понял, приведенный вами оператор. Мы используем функцию malloc, для того чтобы выделить память размером - длинна введенной строки +1, куда и будет скопированна введенная пользователем строка из массива b, после чего функция strcpy вернет указатель на свеже выделенную память, и он уже присвоиться указателю name. В результате чего в каждом узле списка name будет указывать на определенный отрезок памяти, а не на массив b в котором всегда хранится, последняя введенная пользователем строка.? Еще вопрос, для чего здесь применяется (char*), как я понял, это приведение к типу? Но и без него все работает!?
И последний вопрос, когда я должен освобождать память, если я правильно понимаю, только после того, как список будет распечатан, в самом конце программы ? Т.е. мне нужно освободить список в цикле, узел за узлом, с помощью функции free, или достаточно free передать указатель на начало списка? А как поступать с той памятью что выделялась для копии строки из массива b, и на которую ссылался элемент структуры name. Как и когда ее высвобождать?
Блогадарю.
maryan.vetrov вне форума Ответить с цитированием
Старый 15.10.2010, 10:14   #4
sergey.d
Пользователь
 
Регистрация: 23.08.2010
Сообщений: 98
По умолчанию

Цитата:
Хочу уточнить правильно ли я понял..
Абсолютно правильно.

Цитата:
для чего здесь применяется (char*), как я понял, это приведение к типу? Но и без него все работает!?
Автоматическое приведение void * к char * работает не во всех компиляторах, так что это перестраховка

Цитата:
И последний вопрос, когда я должен освобождать память, если я правильно понимаю, только после того, как список будет распечатан, в самом конце программы ? Т.е. мне нужно освободить список в цикле, узел за узлом, с помощью функции free, или достаточно free передать указатель на начало списка? А как поступать с той памятью что выделялась для копии строки из массива b, и на которую ссылался элемент структуры name. Как и когда ее высвобождать?
Да, память выделенную под список, нужно освободить в конце работа программы, когда список более не будет использоваться. Функция free ничего не знает о списках вообще и о данной реализации в частности, поэтому освобождать нужно узел за узлом, передавая free указатель на каждый блок, выделенный ранее вызовами malloc. Память, выделенную под копию строки для элемента списка, нужно также освобождать отдельным вызовом free, причем до того, как будет освобождена память, выделенная для хранения экземпляра соответствующей структуры example.

Маленький нюанс: в принципе, в данном конкретном случае неосвобождение памяти ни к чему страшному не приведет -- большинство ОС "почистят мусор", отставшийся после завершения программы. Но привыкать думать о освобождении памяти необходимо сразу, иначе в более-менее крупном проекте неизбежно возникнут переполнения и утечки памяти. Да и преподаватель наверняка обратит внимание на это уже сейчас
sergey.d вне форума Ответить с цитированием
Старый 15.10.2010, 14:45   #5
maryan.vetrov
Пользователь
 
Регистрация: 07.06.2010
Сообщений: 75
По умолчанию

Благодарю за помощь, все понял. Преподователя к сожалению у меня нет, но отрадно, что есть сообщество готовое помогать. За что благодарен вам и этому форуму.
maryan.vetrov вне форума Ответить с цитированием
Старый 18.10.2010, 04:53   #6
maryan.vetrov
Пользователь
 
Регистрация: 07.06.2010
Сообщений: 75
По умолчанию

Я написал следующую функцию для очистки памяти, хотел бы знать на сколько она корректна? И если я правильно понимаю, при печати списка после освобождения памяти, могут отображаться наборы неких символов, это то что попало в эту память уже после освобождения?
Код:
void eraseList(EXAMPLE *startPtr)
{
          EXAMPLE *temPtr;

      while(startPtr!=NULL){
          temPtr=startPtr;
          free(temPtr->name);
          free(temPtr);
          startPtr=startPtr->nextPtr;
      }
}
maryan.vetrov вне форума Ответить с цитированием
Старый 18.10.2010, 08:49   #7
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,709
По умолчанию

Код:
temPtr=startPtr->nextPtr;
free(startPtr->name);
free(startPtr);
startPtr=temPtr;
А то после
Код:
free(temPtr);
у вас уже не будет
Код:
startPtr=startPtr->nextPtr;
. Вернее может быть и будет, потому что никто еще не успел затереть, но надеятся на это не стоит.
p51x вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Связанный список (Linked list). lnter Помощь студентам 0 12.04.2010 17:58
База данных. Связанный список. 4uJIaBekTonop C/C++ Базы данных 3 29.12.2009 10:42
Еще один вопрос, связанный с БД Sweta Общие вопросы C/C++ 3 09.11.2009 17:10
Вопрос связанный с выводом графики BuT@JL Мультимедиа в Delphi 2 24.10.2009 12:54