Форум программистов, компьютерный форум, киберфорум
C для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.65/34: Рейтинг темы: голосов - 34, средняя оценка - 4.65
0 / 0 / 1
Регистрация: 22.08.2015
Сообщений: 3

Односвязный список и файл

13.05.2017, 21:00. Показов 7339. Ответов 2

Студворк — интернет-сервис помощи студентам
Всем привет. При написании программы реализующей создание записей о заказчиках (использую односвязный список) и последующей их записи в файл возникло пару проблем.

1. Считывание структур из файла при первом запуске программы (функции writeToList и addNodeFromFile) происходит не правильно.
Если запустить программу и попробовать удалить запись (4й пункт меню), то вывод будет не правильным (выводиться должны только имена заказчиков),
выведется имя первого заказчика, а дальше пойдут цифры.


1.1. Если раскомментировать 79-83 и 128-129 строки соответственно (проверка размера файла, если он пустой, то считывать ничего не будем),
то появится ошибка на строке 102 (Segmentation fault).

2. Удаление заказчика если файл уже создан. Если файл не создан и я запускаю программу, добавляю нового покупателя,
он добавляется в список и записывается в файл (функция addCustomer), потом я могу его удалить и никаких проблем не возникает.
Но если файл создан и мы считываем записи с файла и добавляем их в список (проблема 1), то удаление, а именно функции remove() и rename() внутри removeFromFile() не работают,
это видно на скриншоте:


2.1. Так же есть проблема при выводе списка заказчиков перед их удалением, если я удаляю последнего заказчика и потом захожу еще раз в 4й пункт меню,
то в списке выводится мусор, а на строке 169 ошибка (Segmentation fault) и тут возникает вопрос:
как проверить пустой у меня список или нет?

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

4. Изменение одного из параметров структуры (ну это я и сам могу сделать )

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

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
struct Customer{
    char fio[20];       // ФИО покупателя
    int id;             // порядковый номер
    char address[20];   // адрес покупателя
    char delivDate[20]; // дата доставки
    struct Customer *next;  //следующий покупатель
};
 
typedef struct Customer *PCust;   // массив структур
PCust Head = NULL;                // голова списка
 
char FILENAME[] = "C:\\Users\\Asus\\Desktop\\customers.txt";
 
 
PCust CreateCustomer(char *NewFio, char *NewAdress, char *NewData, int id);
PCust Find(PCust Head, char NewFio[]);
void AddFirst(PCust * Head, PCust NewCustomer);
void AddLast(PCust *Head, PCust NewCustomer);
void AddAfter(PCust p, PCust NewCustomer);
void DeleteNode(PCust *Head, PCust p);
 
 
int menu();
void writeToList(void);
void writeToFile(PCust customer);
void removeFromFile(PCust customer);
void addCustomer(void);
void deleteCustomer(void);
void sortCustomers(void);
 
void addNodeFromFile(char *fio, char *address, char *date, int id);
 
// TODO: Запись в список при старте программы
int main(){
    writeToList();
    while(1)
        switch (menu())
        {
            case 1:break;
            case 2:break;
            case 3:addCustomer();break;
            case 4:deleteCustomer();break;
            case 5:break;
            case 6:break;
            case 7:return 0;
            default:printf("Neverniy vibor\n");
        }
}
 
int menu()
{
    int choice = 0;
    do
    {
//        system("cls");//очищает содержание экрана
        printf("Menu\n");
        printf("1.New list\n");
        printf("2.Read from file\n");
        printf("3.Add customer\n");
        printf("4.Delete customer\n");
        printf("5.Change customer field\n");
        printf("6.Search in customers\n");
        printf("7.Exit\n");
        printf("Vash vibor? : ");
        scanf("%d", &choice);//ввод действия,которое хотим произвести
        system("cls");
    }while (choice>7);
    return choice;
}
 
void writeToList(void){
    FILE *f = fopen(FILENAME, "r");
 
//    if(f != NULL) {
//        fseek(f, 0, SEEK_END);
//        long size = ftell(f);
//
//        if (size != 0) {
            char line[512];
            int nullEtrCount = 0;
            PCust q = Head;
            int currentLine = 0;
 
            char fio[20];
            char id[20];
            char address[20];
            char delivDate[20];
 
            while (!feof(f)) {
                fgets(fio, 20, f);
                fgets(address, 20, f);
                fgets(delivDate, 20, f);
                fgets(id, 20, f);
 
                //Удаляет символ конца строки в фамилии
                int i = 0;
                while (fio[i] != '\n') {
                    i++;
                }
                fio[i] = '\0';
//        i = 0;
//        while(address[i] != '\n')
//        {
//            i++;
//        }
//        address[i] = '\0';
//        i = 0;
//        while(delivDate[i] != '\n')
//        {
//            i++;
//        }
//        delivDate[i] = '\0';
//        i = 0;
//        while(id[i] != '\n')
//        {
//            i++;
//        }
//        id[i] = '\0';
                addNodeFromFile(fio, address, delivDate, atoi(id));
            }
        }
//    }
//}
 
void addNodeFromFile(char *fio, char *address, char *date, int id) {
    PCust tempNode;
 
    tempNode = (PCust)malloc(sizeof(struct Customer));
    strcpy(tempNode->fio, fio);
    strcpy(tempNode->address, address);
    strcpy(tempNode->delivDate, date);
    tempNode->id = id;
 
    AddLast(&Head, tempNode);
}
 
void addCustomer(void) {
    struct Customer currentCustomer;
    printf("Vvedite FIO pokupatelya: ");
    scanf("%s",currentCustomer.fio);
    printf("Vvedite adres pokupatelya: ");
    scanf("%s",currentCustomer.address);
    printf("Vvedite datu dostavki: ");
    scanf("%s",currentCustomer.delivDate);
    printf("Vvedite nomer pokupatelya: ");
    scanf("%d",&currentCustomer.id);
    PCust customerNode = CreateCustomer(currentCustomer.fio, currentCustomer.address,
                                  currentCustomer.delivDate, currentCustomer.id);
    AddLast(&Head, customerNode);
    // Запись в файл
    writeToFile(customerNode);
}
 
 
void deleteCustomer(void) {
    char fio[20] = "\n";
 
    printf("-Spisok vseh familii-\n");
    // Выводим список всех фамилий в файле
    PCust q = Head;     // Начали с головы
    while(q != NULL)    // Пока не дошли до конца
    {
        if(q->fio != NULL){
            printf("%s\n",q->fio);
        }
        q = q->next;    // Переходим к следующему узлу
    }
 
    printf("Vvedite FIO pokupatelya dlya udaleniya: ");
    scanf("%s",fio);
 
    PCust target = Find(Head, fio);
    removeFromFile(target);
    DeleteNode(&Head, target);
    getch();
}
 
void sortCustomers(void) {
 
}
 
void writeToFile(PCust Head){
    FILE *f =fopen(FILENAME, "a");
    if( f != NULL)
    {
        PCust q = Head;     // Начали с головы
        while(q != NULL)    // Пока не дошли до конца
        {
            fprintf(f,"%s\n",q->fio);
            fprintf(f,"%s\n",q->address);
            fprintf(f,"%s\n",q->delivDate);
            fprintf(f,"%d\n",q->id);
            fprintf(f, "\n");
            q = q->next;    // Переходим к следующему узлу
        }
        fclose(f);
    }
}
 
void removeFromFile(PCust customer) {
 
    char str[512];
    char temp[512];
    int FioLineNumb = 1;
    int delLineNumb = 1;
    int currLineNumb = 0;
    int find_result = 0;
 
    FILE *f = fopen(FILENAME, "r");
 
    /**** Находим номер строки с искомым именем ****/
    while (fgets(temp, sizeof(temp), f) != NULL) {
        if ((strstr(temp, customer->fio)) != NULL) {
            delLineNumb = FioLineNumb;
            printf("Sovpadenie naideno na stroke: %d\n", FioLineNumb);
            //printf("\n%s\n", temp);
            find_result++;
        }
        FioLineNumb++;
    }
 
    if (find_result == 0) {
        printf("\nNichego ne naideno.\n");
    }
 
    /**** Создаем копию исходного файла ****/
    rewind(f);
    FILE *newF = fopen("C:\\Users\\Asus\\Desktop\\customers_new.txt", "w");
    while(fgets(str, sizeof(str), f) != NULL){
        currLineNumb++;
 
        // Если текущая строка не равняется строке, которую нужно удалить
        // удаляется 5 строк - одна структура
        if(currLineNumb != delLineNumb && currLineNumb != delLineNumb + 1 && currLineNumb != delLineNumb + 2 &&
                   currLineNumb != delLineNumb + 3 && currLineNumb != delLineNumb + 4) {
                       // Пишем массив в файл
                       fputs(str, newF);
                   }
    }
    fclose(f);
    fclose(newF);
    // Удаляем старый файл
    remove(FILENAME);
    // Переименовываем новый
    int result = rename("C:\\Users\\Asus\\Desktop\\customers_new.txt", FILENAME);
    if(result == 0){
        printf("Rename success.");
    } else{
        printf("Rename error.");        
    }
 
}
 
 
PCust CreateCustomer(char *NewFio, char *NewAdress, char *NewData, int id)
{
    PCust NewCustomer = malloc(sizeof *NewCustomer);
    strcpy(NewCustomer->fio, NewFio);
    strcpy(NewCustomer->address, NewAdress);
    strcpy(NewCustomer->delivDate, NewData);
    NewCustomer->id = id;
    NewCustomer->next = NULL;
    return NewCustomer;
}
 
// Добавление нового узла
void AddFirst(PCust * Head, PCust NewCustomer)
{
    NewCustomer->next = *Head;
    *Head = NewCustomer;
}
 
// Добавление узла между элементами
void AddAfter(PCust p, PCust NewCustomer)
{
    NewCustomer->next = p->next;
    p->next = NewCustomer;
}
 
// Добавить узел в конец списка
void AddLast(PCust *Head, PCust NewCustomer)
{
    PCust q = *Head;
 
    // Если список пустой
    if(*Head == NULL)
    {
//        printf("Add first");
        AddFirst(Head, NewCustomer);
        return;
    }
 
    // Цикл прохода до последнего узла списка
    while(q->next)
        q = q->next;
 
    // Добавление узла после заданного узла,
    // в данном случае после q
    AddAfter(q, NewCustomer);
}
 
// Поиск элемента в списке
PCust Find(PCust Head, char NewFio[]) // Ищем ФИО NewFio[], результат адрес узла
{
    PCust q = Head;
    // Пока не дошли до конца списка и слово не равно заданному
    while(q && strcmp(q->fio, NewFio))
        q = q->next;
    return q;
}
 
void DeleteNode(PCust *Head, PCust p)
{
    PCust q = *Head;
 
    if(*Head == p)          // Особый случай, если голова списка совпадает с удаляемым узлом
        Head = &(p->next);  // нужно поменять голову списка. Голова списка смещается на адрес следующего узла
    else{
        while(q && q->next != p)    // пока не находим предыдущий узел до удаляемого (p)
            q = q->next;            // делаем проход по списку
        if(q == NULL) return;
        q->next = p->next;          // если мы нашли узел перед удаляемым, переставляем ссылку ->next c узла перед удаляемым на следующий узел после удаляемого.
    }
    free(p); // освобождаем память под тот узел, который нам надо удалить.
}
Пример структуры файла customers.txt:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
max
1
2
3
 
artem
4
5
6
 
nikita
7
8
9
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
13.05.2017, 21:00
Ответы с готовыми решениями:

Переделать двусвязный список в односвязный список
//--------------------------------------------------------------------------- #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include...

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

Односвязный список
Вопрос может не по теме и не для форума, но я задам. Решил написать на СИ библиотеку для связного списка с динамическим(void*) типом...

2
0 / 0 / 1
Регистрация: 22.08.2015
Сообщений: 3
14.05.2017, 02:04  [ТС]
IDE: CLion
Compiler: gcc 5.3.0

Добавлено через 4 часа 54 минуты
С remove() и rename() разобрался. У меня не был закрыт файл (fclose) в функции writeToList() и когда я пытался удалить файл мне не хватало прав доступа (permission denied).
0
0 / 0 / 1
Регистрация: 22.08.2015
Сообщений: 3
17.05.2017, 22:05  [ТС]
Исправил чтение из файла и запись в односвязный список (1;1.1)
C
1
2
3
4
5
6
7
8
9
void writeToList(void){
    FILE *f = fopen(FILENAME, "r");
    struct Customer newCustomer;
    while(fscanf(f, "%s\n%s\n%s\n%d\n",newCustomer.fio, newCustomer.address, newCustomer.delivDate, &newCustomer.id) != EOF){
        PCust customerNode = CreateCustomer(newCustomer.fio, newCustomer.address, newCustomer.delivDate, newCustomer.id);
        AddLast(&Head, customerNode);
    }
    fclose(f);
}
Сделал сортировку по именам (3):
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// Сортировка по фамилии
void sortBy_fio(PCust Head){
    PCust a;
    PCust b;
    a = Head;
    char tmp_Fio[20];
    char tmp_address[20];
    char tmp_delivDate[20];
    int tmp_id;
 
    while(a->next) // пока существует следующий элемент
    {
        b = a->next;
        while(b)  // для каждого элемента перебираем все оставшееся справа
        {
            if(strcmp(a->fio,b->fio)>0)
            {
                // Меняем местамии фамилии
                strcpy(tmp_Fio, a->fio);
                strcpy(a->fio, b->fio);
                strcpy(b->fio, tmp_Fio);
 
                // Меняем местамии адреса
                strcpy(tmp_address, a->address);
                strcpy(a->address, b->address);
                strcpy(b->address, tmp_address);
 
                // Меняем местамии даты доставок
                strcpy(tmp_delivDate, a->delivDate);
                strcpy(a->delivDate, b->delivDate);
                strcpy(b->delivDate, tmp_delivDate);
 
                // Меняем местамии номера
                tmp_id = a->id;
                a->id = b->id;
                b->id = tmp_id;
            }
            b = b->next;
        }
        a = a->next;
    }
}
Теперь есть функция для вывода всех покупателей:
C
1
2
3
4
5
6
7
8
9
10
11
// Вывод списка
void DisplayList(PCust Head) {
    PCust current = Head;
 
    printf("--- Spisok vseh pokupatelei ---\n");
    while (current != NULL) {
        printf("%s\n", current->fio);
        current = current->next;
    }
    getch();
}
Однако, опять же, если я удаляю последнего покупателя и потом опять обращаюсь к функции DisplayList ,
то происходят те же траблы:
Цитата Сообщение от NovaSurfer Посмотреть сообщение
если я удаляю последнего заказчика и потом захожу еще раз в 4й пункт меню,
то в списке выводится мусор, а на строке 169 ошибка (Segmentation fault) и тут возникает вопрос:
как проверить пустой у меня список или нет?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
17.05.2017, 22:05
Помогаю со студенческими работами здесь

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

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

Разбить односвязный список на группы
разбить односвязный список на группы по 5 элементов + в каждой пятерке элементов поменять порядок на обратный ЗЫ.нужно срочно!!!

Прошить односвязный список указателями
Задание гласит: Организовать список, содержащий символы текста. Прошить этот список указателями так чтобы новые списки образовали...

Односвязный список, ошибка вывода
не пойму почему не работает вывод? пишет ошибку,якобы я залезаю в недопустимую часть памяти, условие temp != NULL не выполняется,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Новые блоги и статьи
Мысли в слух. Про "навсегда".
kumehtar 16.04.2026
Подумалось тут, что наверное очень глупо использовать во всяких своих установках понятие "навсегда". Это очень сильное понятие, и я только начинаю понимать край его смысла, не смотря на то что давно. . .
My Business CRM
MaGz GoLd 16.04.2026
Всем привет, недавно возникла потребность создать CRM, для личных нужд. Собственно программа предоставляет из себя базу данных клиентов, в которой можно фиксировать звонки, стадии сделки, а также. . .
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
Фиксация колонок в отчете СКД
Maks 14.04.2026
Фиксация колонок в СКД отчета типа Таблица. Задача: зафиксировать три левых колонки в отчете. Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) / / . . .
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations": true, . . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
Архитектура слоя интернета для сервера-слоя.
Hrethgir 11.04.2026
В продолжение https:/ / www. cyberforum. ru/ blogs/ 223907/ 10860. html Знаешь что я подумал? Раз мы все источники пишем в голове ветки, то ничего не мешает добавить в голову такой источник, который сам. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru