Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/4: Рейтинг темы: голосов - 4, средняя оценка - 4.75
0 / 0 / 0
Регистрация: 19.08.2016
Сообщений: 23
1

Segfault при прасинге файла

19.08.2016, 17:37. Показов 800. Ответов 9

Author24 — интернет-сервис помощи студентам
С++ знаю плоховато. Решил написать себе генератор to-do list`a, вроде даже начало было неплохим, но потом обнаружил неприятную ошибку. Суть программы в том, что на основе секций в текстовом файле вида:
{
title строка
level натуральное число
depends строка
description строка
urgency число от 1 до 20
importance число от 1 до 20
}
программа формировала бы список дел и записывала его в файл. Заступорился я на этапе парсинга файла с секциями: если секция в файле одна, то всё парсится в переменные нормально, но если больше, то происходит ошибка сегментации.
Код программы (незавершённый):
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
#include <iostream>
#include <fstream>
#include <cstring>
 
#define DAILY "todo.daily"
 
using namespace std;
ofstream fout;
ifstream fin;
 
struct item {
    string title;
    int level;
    string depends;
    string description;
    int urgency;
    int importance;
};
 
void get (item *task) {
    fin.open (DAILY);
    char *tmp = new char;
    int i = 0;
    bool section = false;
    while (fin >> tmp) {
        if (!(strcmp("{",tmp)))
            section = true;
        else if (!(strcmp("title",tmp)) && section == true) {
            fin.get();
            getline(fin,task[i].title);
        }    
        else if (!(strcmp("level",tmp)) && section == true) {
            fin >> task[i].level;
        }    
        else if (!(strcmp("depends",tmp)) && section == true) {
            fin.get();
            getline(fin,task[i].depends);
        }    
        else if (!(strcmp("description",tmp)) && section == true) {
            fin.get();
            getline(fin,task[i].description);
        }    
        else if (!(strcmp("urgency",tmp)) && section == true) {
            fin >> task[i].urgency;
            if (task[i].urgency > 20)
                task[i].urgency = 20;
            else if (task[i].urgency < 1)
                task[i].urgency = 1;
        }    
        else if (!(strcmp("importance",tmp)) && section == true) {
            fin >> task[i].importance;
            if (task[i].importance > 20)
                task[i].importance = 20;
            else if (task[i].importance < 1)
                task[i].importance = 1;
        }    
        else if (!(strcmp("}",tmp)) && section == true) {
            section = false;
            i++;
        }  
    }
    //delete tmp;
}
 
int main (int argc, char **argv) {
    item *task = new item;
    get (task);
   /*
    for (int i(0); i < 1; i++) {
        cout << task[i].title << endl;
        cout << task[i].level << endl;
        cout << task[i].depends << endl;
        cout << task[i].description << endl;
        cout << task[i].urgency << endl;
        cout << task[i].importance << endl;
    }
    */
    //delete task;
    return 0;
}
Если между 25 и 26 строкой добавить cout << tmp << endl;, то при одной секции в todo.daily вывод команды будет:
{
title
level
depends
description
urgency
importance
}
А если увеличить количество секций до 2 или больше, то вывод будет таким:
{
title
level
depends
description
urgency
importance
}
{
title
Ошибка сегментирования (core dumped)
Т. е. сегфолт в функции get во время обработки заголовка второй секции. Я сам не особо понимаю, в чём может быть проблема, прошу объяснить, что происходит, и как это пофиксить.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
19.08.2016, 17:37
Ответы с готовыми решениями:

SegFault при вводе стрококвого поля структуры
struct vuz { char name; int yearOfOpening; int numberOfFaculties; int...

QDoubleSpinBox - segfault при вызове value(), setValue()
Доброго времени суток. Странная проблема, не ожидал, что она может здесь вообще возникнуть. Гугл...

Segfault при присвоении значения массиву
Доброго времени суток. #include &lt;stdio.h&gt; void del_char(char *str0, const char *str1); /*...

GC+SEGFAULT
Всем трям. Вопрос продвинутым. Посещаю курсы по Питону и задали нам хитрое задание - сделать...

9
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
19.08.2016, 17:48 2
Цитата Сообщение от JustOneProblem Посмотреть сообщение
char *tmp = new char;
Сколько тут памяти выделилось по-твоему?
0
0 / 0 / 0
Регистрация: 19.08.2016
Сообщений: 23
19.08.2016, 17:55  [ТС] 3
Не знаю...
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
19.08.2016, 17:58 4
Цитата Сообщение от JustOneProblem Посмотреть сообщение
Не знаю...
1 байт.
А пытаешься ты читать в него целую строку.
В итоге получаешь ошибку времени исполнения.
Используй std::string. Он сам следит за перераспределением памяти, и обеспечит чтение строки произвольного размера.
0
0 / 0 / 0
Регистрация: 19.08.2016
Сообщений: 23
19.08.2016, 18:12  [ТС] 5
Цитата Сообщение от DrOffset Посмотреть сообщение
1 байт.
А пытаешься ты читать в него целую строку.
В итоге получаешь ошибку времени исполнения.
Используй std::string. Он сам следит за перераспределением памяти, и обеспечит чтение строки произвольного размера.
Как понять "читать строку в него"? Почему первый цикл проходит нормально? Пробовал делать char *tmp = new char [число], ничего не изменяется. Если со string делать, то что использовать вместо strcmp("text",tmp))?

Добавлено через 9 минут
Сегфолт происходит даже если tmp -- это просто массив из N символов.
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
19.08.2016, 18:19 6
Цитата Сообщение от JustOneProblem Посмотреть сообщение
Как понять "читать строку в него"?
Да очень просто, у тебя выделен один байт.
Оператор >> потока принимает указатель на этот один байт и считает, что это указатель на начало буфера, и пытается записать в него строку. Но т.к. реально в нашем "буфере" только один байт, он пишет за пределы выделенной нам памяти. Что в конечном итоге приводит к падению.

Цитата Сообщение от JustOneProblem Посмотреть сообщение
Почему первый цикл проходит нормально?
Везет.

Цитата Сообщение от JustOneProblem Посмотреть сообщение
Сегфолт происходит даже если tmp -- это просто массив из N символов.
Правильно, потому что у тебя точно такая же проблема в main.
Там ты опять выделил память только для одного объекта item. А внутри функции get пытаешься работать с указателем так, как будто бы у тебя массив. В итоге опять тот же сценарий. Пишем за пределы выделенной памяти - получаем сегфолт.

Цитата Сообщение от JustOneProblem Посмотреть сообщение
Если со string делать, то что использовать вместо strcmp("text",tmp))?
C++
1
else if ("title" == tmp && section == true) {
Ну и т.д.
1
0 / 0 / 0
Регистрация: 19.08.2016
Сообщений: 23
19.08.2016, 18:36  [ТС] 7
Ладно, понял. А как тогда сделать, чтобы элементы массива структур данных создавались по мере надобности (каждый инкремент переменной i), а не сразу в определённом количестве при объявлении item *task = new item[N];?
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
19.08.2016, 18:56 8
Цитата Сообщение от JustOneProblem Посмотреть сообщение
А как тогда сделать, чтобы элементы массива структур данных создавались по мере надобности
Посмотри std::vector или std::list.

Добавлено через 3 минуты
JustOneProblem,
Кликните здесь для просмотра всего текста

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
void get (std::vector<item> & tasks) {
    fin.open (DAILY);
    string tmp;
    bool section = false;
 
    item current;
    while (fin >> tmp) {
        if("{" == tmp) {
            current = item();
            section = true;
        }
        else if ("title" == tmp && section) {
            fin.get();
            getline(fin, current.title);
        }
        else if ("level" == tmp && section) {
            fin >> current.level;
        }
        else if ("depends" == tmp && section) {
            fin.get();
            getline(fin, current.depends);
        }
        else if ("description" == tmp && section) {
            fin.get();
            getline(fin, current.description);
        }
        else if ("urgency" == tmp && section) {
            fin >> current.urgency;
            if (current.urgency > 20)
                current.urgency = 20;
            else if (current.urgency < 1)
                current.urgency = 1;
        }
        else if ("importance" == tmp && section) {
            fin >> current.importance;
            if (current.importance > 20)
                current.importance = 20;
            else if (current.importance < 1)
                current.importance = 1;
        }
        else if ("}" == tmp && section) {
            section = false;
            tasks.push_back(current);
        }
    }
}
0
0 / 0 / 0
Регистрация: 19.08.2016
Сообщений: 23
20.08.2016, 23:44  [ТС] 9
Цитата Сообщение от DrOffset Посмотреть сообщение
Посмотри std::vector или std::list.

Добавлено через 3 минуты
JustOneProblem,
Кликните здесь для просмотра всего текста

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
void get (std::vector<item> & tasks) {
    fin.open (DAILY);
    string tmp;
    bool section = false;
 
    item current;
    while (fin >> tmp) {
        if("{" == tmp) {
            current = item();
            section = true;
        }
        else if ("title" == tmp && section) {
            fin.get();
            getline(fin, current.title);
        }
        else if ("level" == tmp && section) {
            fin >> current.level;
        }
        else if ("depends" == tmp && section) {
            fin.get();
            getline(fin, current.depends);
        }
        else if ("description" == tmp && section) {
            fin.get();
            getline(fin, current.description);
        }
        else if ("urgency" == tmp && section) {
            fin >> current.urgency;
            if (current.urgency > 20)
                current.urgency = 20;
            else if (current.urgency < 1)
                current.urgency = 1;
        }
        else if ("importance" == tmp && section) {
            fin >> current.importance;
            if (current.importance > 20)
                current.importance = 20;
            else if (current.importance < 1)
                current.importance = 1;
        }
        else if ("}" == tmp && section) {
            section = false;
            tasks.push_back(current);
        }
    }
}
А что означает строчка current = item();, и можно ли обойтись без создания ещё одного элемента структуры (current)?

Добавлено через 13 минут
Ах, да почему & tasks, а не просто tasks?
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
21.08.2016, 00:20 10
Цитата Сообщение от JustOneProblem Посмотреть сообщение
можно ли обойтись без создания ещё одного элемента структуры (current)?
Можно. Придется немного менять алгоритм разбора.

Цитата Сообщение от JustOneProblem Посмотреть сообщение
А что означает строчка current = item();
Это сброс значений полей, нужно в случае, если у нас i-я итерация с неполностью заполненным полями - чтобы не записались значения предыдущей записи.

Цитата Сообщение от JustOneProblem Посмотреть сообщение
Ах, да почему & tasks, а не просто tasks?
Ну мы вектор внутри функции заполняем же.
1
21.08.2016, 00:20
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
21.08.2016, 00:20
Помогаю со студенческими работами здесь

Segfault at 0 .error
1. Debian 8 64bit 2. Все, что нашла lib32 загружены 3. Гугл не помог Та же сборка стояла на...

Segfault на ровном месте
Доброго времени суток. Пишу достаточно простую программку под Linux. Вот кусок кода в котором...

Segfault после WriteProcessMemory
#include &lt;windows.h&gt; #include &lt;string&gt; using namespace std; int main() { string s =...

std::max segfault
Программа пытается найти максимально больше слово в векторе. Не пойму в чём дело: #include...

Большой массив данных и segfault
Есть струтура ( порядка 4 uint32_t + 8 байт char ) Нужно хранить 32000 таких структур постоянно...

Один из способов вызвать segfault.
Вот код: #include &lt;stdio.h&gt; int main(){ char b = 1; register int c=0; ...


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

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru