Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Kravch
0 / 0 / 0
Регистрация: 21.12.2010
Сообщений: 7
#1

Чтение из файла - C++

30.05.2011, 16:41. Просмотров 978. Ответов 12
Метки нет (Все метки)

Есть текстовый файл, с n строк. Нужно записать содержимое каждой строки в массив char table[n][6]. Длина каждой строки известна и одинакова, так же известно количество строк. Написал функцию, но есть проблема с переходом на новую строку файла, из-за этого происходит неправильная запись в массив. Была мысль записать весь файл в string, а оттуда записывать в массив, но это как-то не рационально.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void read() {
    int IndexSeg, i;
    char c[6];
 
    IndexSeg = 0;
    
    FILE * pFile;
    pFile = fopen ("1.txt","r");
    while (IndexSeg != HashSize) {
        fgets (c, 6, pFile);
        if(c[0] == empty) {
            table[IndexSeg][0] = empty;
        }
        else {
            for(i = 0; i < 6; i++) {
                table[IndexSeg][i] = c[i];
            }
        }
        IndexSeg++;
    }
    fclose (pFile);
}
Код всей программы. На всякий случай ;-)

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
#include <iostream>
#include <string>
#include <cstdio>
using namespace std;
 
const int HashSize = 10;
const char empty = 'E'; 
const char deleted = 'D'; 
const int c = 1; // Шаг перебора
const int MaxCase = 2; // Максимальное количество попыток
 
char table[10][6]; // Хеш
 
void hash_clean();
int hash_search(char x[]);
bool add_element(char x[]);
int hash1(char key[]);
int hash2(char key[]);
void read();
void del(char x[]);
int menu();
 
int main() {
 
    setlocale(LC_ALL, "rus");
 
    return menu();
}
 
// Меню
int menu() {
 
    int i, c = 0;
    char x[6];
 
    while(1) {
        cout << "\n";
            cout << "1. Добавить элемент в таблицу \n";
            cout << "2. Найти элемент в таблице \n";
            cout << "3. Удалить элемент из таблицы \n";
            cout << "4. Очистить таблицу \n\n";
            cout << "5. Выйти \n\n";
            cout << "Выберите команду: ";
            cin >> c;
        
        switch(c) {
            case 1: 
                cout << "Введите ключ вида цццАцц : ";
                for(i = 0; i < 6; i++) {
                    cin >> x[i];
                }
                
                read();
                add_element(x);
                cout << "\n\nЭлемент добавлен" << endl;
                break;
 
            case 2: 
                cout << "Введите ключ вида цццАцц : ";
                for(i = 0; i < 6; i++) {
                    cin >> x[i];
                }
                
                read();
                c = hash_search(x);
                cout << "\n\nНайденный элемент : " << table[c] << endl;
                break;
 
            case 3: 
                cout << "Введите ключ вида цццАцц : ";
                for(i = 0; i < 6; i++) {
                    cin >> x[i];
                }
                
                read();
                del(x);
                cout << "\n\nЭлемент удалён" << endl;
                break;
 
            case '\n':
                break;
 
            case 4: 
                cout << "\n\nВы уверены что хотите очистить хеш? (Введите 42 если да)" << endl;
                cin >> c;
 
                if(c == 42)
                    hash_clean();
                break;
 
            case 5: 
                system("pause");
                return 0;
        }
    }
}
 
// Очищаем хеш.
void hash_clean() {
    int IndexSeg;
 
    for(IndexSeg = 0; IndexSeg < HashSize; IndexSeg ++) {
        table[IndexSeg][0] = empty;
    }
}
 
// Функция поиска элемента х в хеш-таблице. 
// Возвращаем номер элемента, если найден и -1, если не найден.
int hash_search(char x[]) {
    int IndexSeg, i, h1, h2;
    
    i = 0;
    h1 = hash1(x);
    h2 = hash2(x);
    
    do {
        IndexSeg = (((h1 + i * h2) % HashSize + (h1 + i * h2) / 2) % HashSize);
        i++;
    } while((table[IndexSeg][0] == x[0] && table[IndexSeg][1] == x[1] && table[IndexSeg][2] == x[2] && table[IndexSeg][3] == x[3] && table[IndexSeg][4] == x[4] && table[IndexSeg][5] == x[5]) || table[IndexSeg][0] != empty || i > MaxCase);
 
    if (table[IndexSeg][0] == x[0] && table[IndexSeg][1] == x[1] && table[IndexSeg][2] == x[2] && table[IndexSeg][3] == x[3] && table[IndexSeg][4] == x[4] && table[IndexSeg][5] == x[5]) {
        return(IndexSeg); // Нашли. Возвращаем номер найденного.
    }
    else 
        return -1; // Не нашли. Возвращаем -1.
}
 
// Функция добавления элемента в таблицу.
bool add_element(char x[]) {
    int i, h1, h2;
    int IndexSeg;
 
    i = 0;
    h1 = hash1(x);
    h2 = hash2(x);
 
    if(hash_search(x) < 0) {
        do {
            IndexSeg = (((h1 + i * h2) % HashSize + (h1 + i * h2) / 2) % HashSize;
            i++;
        } while(table[IndexSeg][0] != empty || table[IndexSeg][0] == deleted || i > MaxCase);
 
        if(table[IndexSeg][0] == empty || table[IndexSeg][0] == deleted) {
            table[IndexSeg][0] = x[0];
            table[IndexSeg][1] = x[1];
            table[IndexSeg][2] = x[2];
            table[IndexSeg][3] = x[3];
            table[IndexSeg][4] = x[4];
            table[IndexSeg][5] = x[5];
            FILE * pFile;
            pFile = fopen ("1.txt","w");
            for(IndexSeg = 0; IndexSeg < HashSize; IndexSeg++) {
                for(i = 0; i < 6; i++) {
                    fprintf(pFile, "%c", table[IndexSeg][i]);
                }
                fprintf(pFile, "\n");
 
            }
 
            fclose (pFile);
 
            cout << "All Ok" << endl; 
            return true;
        }
    }
    cout << "False" << endl;
    return false;
}
 
// Функция удаления элемента из таблицы
void del(char x[]) {
    int IndexSeg;
    IndexSeg = hash_search(x);
 
    if(IndexSeg != -1)
        table[IndexSeg][0] = deleted;
}
 
// Функция для считывания содержимого хеша из файла
void read() {
    int IndexSeg, i;
    char c[6];
    char * buffer;
 
    IndexSeg = 0;
    
    FILE * pFile;
    pFile = fopen ("1.txt","r");
    while (IndexSeg != HashSize) {
        fgets (c, 6, pFile);
        if(c[0] == empty) {
            table[IndexSeg][0] = empty;
        }
        else {
            for(i = 0; i < 6; i++) {
                table[IndexSeg][i] = c[i];
            }
        }
        IndexSeg++;
    }
    fclose (pFile);
}
 
// Вычисляем хеш-функцию первым способом
int hash1(char key[]) {
    int ascii[6];
    int i, h;
 
    for(i = 0; i < 6; i++) {
        ascii[i] = key[i];
    }
 
    h = ((ascii[0] + 3*ascii[1] + 9*ascii[2] + 27*ascii[3] + 81*ascii[4] + 243*ascii[5])) ;
 
    h = h%HashSize;
 
    return(h);
}
 
// Вычисляем хеш-функцию вторым способом
int hash2(char key[]) {
    int ascii[6];
    int i, h;
 
    for(i = 0; i < 6; i++) {
        ascii[i] = key[i];
    }
 
    h = ((ascii[0] + 3*ascii[1] + 9*ascii[2] + 27*ascii[3] + 81*ascii[4] + 243*ascii[5]))/2 ;
 
    h = h%HashSize;
 
    return(h);
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
30.05.2011, 16:41
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Чтение из файла (C++):

Переделать в коде чтение из файла в чтение с клавиатуры - C++
Переделайте что бы текст считывался с клавиатуры, а не с файла! Буду благодарен за помощь! //файл должен начинаться со слова, между...

Чтение из файла. Повторное чтение файла - C++
Добрый день. Необходимо реализовать в программе функцию повторного чтения данных из файла, в случае некорректного ввода их в оный. Вот...

Преобразование текстового файла в двоичный и чтение исходных данных из двоичного файла. - C++
#include&lt;iostream&gt; #include&lt;fstream&gt; #include&lt;locale.h&gt; #include&lt;iomanip&gt; #include &lt;cstdlib&gt; using namespace std; struct...

Чтение нескольких структур и одной переменной из бинарного файла. Формат файла имеется - C++
Формат файла состоит из 3 структур и одной переменной. Подробное описание формата во вложении, просьба посмотреть его. У меня возникла...

как может корректно выполняющийся оператор >> (чтение из текстового файла) негативно влиять на открытие другого файла? - C++
Друзья! Создадим два текстовых файла, f_0.txt и f_1.txt и что-нибудь в них запизаем, например в первый запихаем 1234 а во второй 5678 и...

Чтение файла с несколькими знаками конца файла - C++
В файле несколько раз встречается ноль, и ни как не получается прочитать его полностью. Как можно решить данную проблему ?

12
DeadRipper
64 / 70 / 3
Регистрация: 25.06.2009
Сообщений: 244
30.05.2011, 19:19 #2
так сразу не понятно, но нельзя забывать что перенос строки это еще 2 символа в файле, либо один, когда как
если в блокноте то два, то есть строка состоит из 8 символов в данном примере как я понял
1
Kravch
0 / 0 / 0
Регистрация: 21.12.2010
Сообщений: 7
30.05.2011, 19:25  [ТС] #3
Цитата Сообщение от DeadRipper Посмотреть сообщение
так сразу не понятно, но нельзя забывать что перенос строки это еще 2 символа в файле, либо один, когда как
если в блокноте то два
На сколько я понимаю там должен быть \n. Вопрос как его учитывать при чтении не делая дополнительной проверки. Возможно есть какая-то функция которая сразу это делает? И только ли он там. Когда пробовал найти ошибку в массив сваливался 10 символ из ASCII (возврат каретки). Это равносильно \n? и после этого массив разъезжался.
Массив и файл такие:
0
Миниатюры
Чтение из файла   Чтение из файла  
DeadRipper
64 / 70 / 3
Регистрация: 25.06.2009
Сообщений: 244
30.05.2011, 19:37 #4
ну там по ходу 1 символ это новая строка а следующий - возврат каретки)

ну не делая проверки это взять вхолостую два символа из файла после шести, либо сдвинуть указатель в файле функцией fseek на два байта относительно текущей позиции, но сказать не могу как работает...
1
Kravch
0 / 0 / 0
Регистрация: 21.12.2010
Сообщений: 7
30.05.2011, 21:58  [ТС] #5
Ок. Буду разбираться с fseek и fsetpos. Брать 1 или 2 символа после 6 не сработало ;-) Спасибо!

Добавлено через 2 часа 2 минуты
Решил проблему считыванием 8 символов, вместо необходимых 6. Элементы встают на свои места, но есть проблема (см. аттач). По непонятной причине элементы дописываются в 2 строки сразу, если подряд идёт 2 элемента занимающих 6 символов. Не понимаю почему так происходит.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void read() {
    int IndexSeg, i;
    char c[8];
 
    IndexSeg = 0;
    
    FILE * pFile;
    pFile = fopen ("1.txt","r");
    while (IndexSeg != HashSize) {
        fgets (c, 8, pFile);
        if(c[0] == empty) {
            table[IndexSeg][0] = empty;
        }
        else {
            for(i = 0; i < 6; i++) {
                table[IndexSeg][i] = c[i];
            }
        }
        IndexSeg++;
    }
    fclose (pFile);
}
0
Миниатюры
Чтение из файла  
Kravch
0 / 0 / 0
Регистрация: 21.12.2010
Сообщений: 7
30.05.2011, 22:19  [ТС] #6
При этом на работоспособность программы это никак не влияет. Интересно понять почему так происходит и что это вообще такое.
0
accept
4823 / 3244 / 165
Регистрация: 10.12.2008
Сообщений: 10,682
31.05.2011, 06:02 #7
C++
1
2
    for(i = 0; i < 6 && (ch = c[i]) != '\n'; i++)
        table[IndexSeg][i] = ch;
1
Kravch
0 / 0 / 0
Регистрация: 21.12.2010
Сообщений: 7
31.05.2011, 11:10  [ТС] #8
Так не работает. Вероятно, там 2 символа \n и \r (как я понимаю признак конца строки и перевода каретки, если забирать 8 символов, то в массив кладётся 10 и 0 из ASCII). Оставил вариант с чтением 8 символов. Забирает всё правильно.

Появилась другая проблема. Если при выборе ввести в меню любую букву, то меню уходит в бесконечный цикл, проскакивая "cin >> c;". Вероятно, нужно перегрузить cin, только не понятно как это сделать.
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
int menu() {
 
    int i, j, c = 0;
    char x[6];
 
    while(1) {
        cout << "\n";
            cout << "1. Добавить элемент в таблицу \n";
            cout << "2. Найти элемент в таблице \n";
            cout << "3. Удалить элемент из таблицы \n";
            cout << "4. Очистить таблицу \n\n";
            cout << "5. Выйти \n\n";
            cout << "Выберите команду: ";
            cin >> c; // Этот cin не всегда срабатывает
        
        switch(c) {
            case 1: 
                cout << "Введите ключ вида цццАцц : ";
                for(i = 0; i < 6; i++) {
                    cin >> x[i];
                }
                
                read();
                add_element(x);
                cout << "\n\nЭлемент добавлен" << endl;
                break;
 
            case 2: 
                cout << "Введите ключ вида цццАцц : ";
                for(i = 0; i < 6; i++) {
                    cin >> x[i];
                }
                
                read();
                c = hash_search(x);
                if (c == -1) cout << "Строчка не найдена!!!";
                else {
                    cout << "\n\nНайденный элемент : ";
                    for (i = 0; i < 6; i++) {
                        cout << table[c][i];
                    }
                }
                cout << "\n\n";
                break;
 
            case 3: 
                cout << "Введите ключ вида цццАцц : ";
                for(i = 0; i < 6; i++) {
                    cin >> x[i];
                }
                
                read();
                del(x);
                cout << "\n\nЭлемент удалён" << endl;
                break;
 
            case '\n':
                break;
 
            case 4: 
                cout << "\n\nВы уверены что хотите очистить хеш? (Введите 42 если да)" << endl;
                cin >> c;
 
                if(c == 42)
                    hash_clean();
                break;
 
            case 5: 
                system("pause");
                return 0;
        }
    }
}
зы: мб кому-то будет интересно. проблема с отображением 2х элементов подряд в дебаггере связана с его особенностями. Для удобного представления элементов массива типа char он выводит его элементы в заголовке как строку. И не найдя признак конца строки после 1 элемента, выводит и следующий, т.к. в памяти они лежат друг за другом. На запись элементов в массиве и их использование в программе это никак не влияет.
0
accept
4823 / 3244 / 165
Регистрация: 10.12.2008
Сообщений: 10,682
31.05.2011, 11:16 #9
Цитата Сообщение от Kravch
Вероятно, там 2 символа \n и \r
если файл открыт в двоичном режиме
если в текстовом, то \r\n будет преобразовываться в \n

Цитата Сообщение от Kravch
если забирать 8 символов, то в массив кладётся 10 и 0 из ASCII).
fgets() останавливается на \n, записывая его
можно делать отдельную функцию rstrip(), которая удаляет символы справа
в цикле нужно ограничение, которое не даст записывать \n, если он встретился посередине
1
Kravch
0 / 0 / 0
Регистрация: 21.12.2010
Сообщений: 7
31.05.2011, 11:32  [ТС] #10
Смотри, сейчас я записываю в char с[8] 8 символов из строки, потом только нужные 6 передаю в основной массив. Это работает я правильно заполняю массив и не делаю дополнительных проверок. В середине строки могут быть только буквы, цифры и пробел. Чем это плохо? По хорошему, стоило бы сделать проверку того, что вводит пользователь, но это можно сделать сразу после ввода избегая неправильной записи.
0
DeadRipper
64 / 70 / 3
Регистрация: 25.06.2009
Сообщений: 244
31.05.2011, 18:32 #11
когда вы вводите 'c' в цикле как вы вводите значения равные 1,2,3,4,5?
может быть все таки нужно поставить '1','2','3','4','5' ?

так как переменная типа Char то и вводятся соответственно ASCII данные, число 1 не соответствует символу '1'
0
Kravch
0 / 0 / 0
Регистрация: 21.12.2010
Сообщений: 7
31.05.2011, 21:59  [ТС] #12
Цитата Сообщение от DeadRipper Посмотреть сообщение
когда вы вводите 'c' в цикле как вы вводите значения равные 1,2,3,4,5?
может быть все таки нужно поставить '1','2','3','4','5' ?
Не сразу понял что имеется ввиду. Сейчас нет возможности проверить, чуть позже попробую сделать char c и переделать case. Спасибо.

Цитата Сообщение от DeadRipper Посмотреть сообщение
так как переменная типа Char то и вводятся соответственно ASCII данные, число 1 не соответствует символу '1'
Разумеется. Только вот переменная c, которая забирает выбор меню типа int, поэтому case 1: а не case '1':.
0
accept
4823 / 3244 / 165
Регистрация: 10.12.2008
Сообщений: 10,682
01.06.2011, 02:48 #13
Цитата Сообщение от Kravch
В середине строки могут быть только буквы, цифры и пробел.
я имею в виду, что файл может оказаться повреждённым
в таком случае нельзя допускать, чтобы в массив писались неправильные данные
0
01.06.2011, 02:48
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.06.2011, 02:48
Привет! Вот еще темы с ответами:

Чтение из файла - C++
Народ напишите любую программу по чтению из файла, но что бы использовалось fopen_s, fscanf_s, код должен быть написан на C++

Чтение из файла - C++
Подскажите как вывести на экран содержимое файла на Си, если данные разделены &quot;;&quot;. Файл имеет вид: 1;23233233;1234-43;иванов...

Чтение из файла. - C++
Здравствуйте. Учусь языку С++. Отказываюсь напрочь понимать как в оконном приложении осуществить чтение из файла с условием, что мне...

Чтение из файла - C++
Есть задание: написать программу,которая считывыает числа из файла, написанные в нем через пробел. Числа кодируются и записываются в новый...


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

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru