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

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

Восстановить пароль Регистрация
 
Kravch
0 / 0 / 0
Регистрация: 21.12.2010
Сообщений: 7
30.05.2011, 16:41     Чтение из файла #1
Есть текстовый файл, с 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);
}
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
30.05.2011, 16:41     Чтение из файла
Посмотрите здесь:

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

ну не делая проверки это взять вхолостую два символа из файла после шести, либо сдвинуть указатель в файле функцией fseek на два байта относительно текущей позиции, но сказать не могу как работает...
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);
}
Миниатюры
Чтение из файла  
Kravch
0 / 0 / 0
Регистрация: 21.12.2010
Сообщений: 7
30.05.2011, 22:19  [ТС]     Чтение из файла #6
При этом на работоспособность программы это никак не влияет. Интересно понять почему так происходит и что это вообще такое.
accept
4837 / 3236 / 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;
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 элемента, выводит и следующий, т.к. в памяти они лежат друг за другом. На запись элементов в массиве и их использование в программе это никак не влияет.
accept
4837 / 3236 / 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, если он встретился посередине
Kravch
0 / 0 / 0
Регистрация: 21.12.2010
Сообщений: 7
31.05.2011, 11:32  [ТС]     Чтение из файла #10
Смотри, сейчас я записываю в char с[8] 8 символов из строки, потом только нужные 6 передаю в основной массив. Это работает я правильно заполняю массив и не делаю дополнительных проверок. В середине строки могут быть только буквы, цифры и пробел. Чем это плохо? По хорошему, стоило бы сделать проверку того, что вводит пользователь, но это можно сделать сразу после ввода избегая неправильной записи.
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'
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':.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.06.2011, 02:48     Чтение из файла
Еще ссылки по теме:

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

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

Или воспользуйтесь поиском по форуму:
accept
4837 / 3236 / 165
Регистрация: 10.12.2008
Сообщений: 10,682
01.06.2011, 02:48     Чтение из файла #13
Цитата Сообщение от Kravch
В середине строки могут быть только буквы, цифры и пробел.
я имею в виду, что файл может оказаться повреждённым
в таком случае нельзя допускать, чтобы в массив писались неправильные данные
Yandex
Объявления
01.06.2011, 02:48     Чтение из файла
Ответ Создать тему
Опции темы

Текущее время: 08:31. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru