Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.73/22: Рейтинг темы: голосов - 22, средняя оценка - 4.73
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
1

Функция getc (FILE*) при первом вызве считывает НЕ ПЕРВЫЙ символ файла.Почему?

13.08.2009, 08:11. Показов 4231. Ответов 18
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Друзья! Здравствуйте! Вот код.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;
int main () {
 
 FILE* zapis_v_fail;
 FILE* chetnie_iz_faila;
 
 //Записываем сыимолы в файл
   zapis_v_fail= fopen ("fail.txt", "w");
   fputc('a', zapis_v_fail);
   fputc('b', zapis_v_fail);
   fputc('c', zapis_v_fail);
   fputc('d', zapis_v_fail);
 
 //Считываем на экран первый символ
   chetnie_iz_faila= fopen ("fail.txt", "r");
   printf ("simvol= %d", getc (chetnie_iz_faila));
 
 getchar ();
 
 return 0;
}
Выводит -1 при том что должен (по моему разумению вывести (int)'a').
Трудно назвать такую работу корректной или предсказуемой. Может, я чего не так делаю? Упоминания о такой тонкости работы getc- то, что значение считываемого символа будет зависеть от работы fputc я нигде не встретил, ни в одном описании.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
13.08.2009, 08:11
Ответы с готовыми решениями:

Почему getline не считывает строку при первом проходе цикла?
В данной функции: void ArrayStr::InputArr(void) { cout &lt;&lt; &quot;Введите строки длинной не более &quot; &lt;&lt;...

Функция getline считывает несколько строк из файла, игнорируя символ новой строки
Всем доброго дня! В С++ я новичок, сам себе придумываю задачки, просто для тренировки....

Почему функция putchar(); выводит только первый символ?(Короткий код)
#include &lt;stdio.h&gt; #include &lt;conio.h&gt; int main() { int c; c=getchar(); putchar(c); ...

Функция getc() и удаление из файла всего, что было считано
Функция getc() она считывает по символьно, как сохранить этот считанный текст в переменную ? И как...

18
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
13.08.2009, 08:54 2
Здравствуй, друг.
Я, конечно, хз, но, блин, вас, учили файлы закрывать? Вам рассказывали, что существует fclose? Вы когда-нибудь слышали про буферизованный ввод/вывод?..
C
1
2
3
4
5
6
   zapis_v_fail= fopen ("fail.txt", "w");
   fputc('a', zapis_v_fail);
   fputc('b', zapis_v_fail);
   fputc('c', zapis_v_fail);
   fputc('d', zapis_v_fail);
 fclose(zapis_v_fail);
simvol= 97
Везде всегда пишут по работе с файлами "закрывайте после использования". А фигли нам... Упоминания об этой "тонкости" тоже нигде нет?
1
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
13.08.2009, 10:20  [ТС] 3
Спасибо конечно, но я тоже хз когда его закрывать надо, этот файл, а помнить-то я об этом помню. Пишут везде, так примерно:
Когда вы закончите все операции с файлом, то не забывайте закрыть файл
(Стефан Кочан)
Нормальная формулировка? K&R не цитирую, там вообще чёрт ногу сломит.
Ну, вот, а программа подразумевает, что я и далее буду в файл что-то записывать. То есть я э... не все операции закончил. А будет ещё запись в файл, считывание, снова запись.


Теперь же есть я буду делать так, как Вы сказали, но честно говоря, я не понял, почему неправильны мои действия. Разве что потому, что не достигнут желаемый результат. Что ж, на том и остановимся. А учусь я сам. Спасибо ещё раз.

C++
1
2
3
4
5
6
7
8
9
10
11
12
//Записываем символы в файл     
fputc ('b', zapis_v_fail);       
 
//Считываем на экран первый символ
printf ("simvol= %d", getc (chetnie_iz_faila));       
 
//Снова записываем символы в файл  
fputc ('f', zapis_v_fail);
 
//Вот тут-то я и закрыл бы файл
fclose (zapis_v_fail);      
fclose (chetnie_iz_faila)
Добавлено через 8 минут 30 секунд
Пршу прощения, редактирую

Добавлено через 48 минут 15 секунд
Вот, вопрос-то всё равно остался открытым. В это примере после считывания файла считывание продолжается не с того, места, на котором закончилось, а с начала, хотя файл НЕ БЫЛ закрыт

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
//Пусть в текущем каталоге есть файл "fail.txt" с содержанием "abcdef"
#include <iostream>
using namespace std;
int main () {
 
FILE* odin_raz;
FILE* vtoroi_raz;
 
odin_raz= fopen ("fail.txt", "r");
vtoroi_raz= fopen ("fail.txt", "r");
 
//Считаем что-нибудь из file.tx. Считаем первые 4 символа
getc (odin_raz);
getc (odin_raz);
getc (odin_raz);
getc (odin_raz);
 
/*А теперь, НЕ ЗАКРЫВАЯ файл, продолжим считывание. М.. Судя по всему, должен считаться символ 'e'
*/
printf ("simvol= %c\n", getc (vtoroi_raz));
 
//Но считался не 'e', а 'a'
getchar ();
return 0;
}
Вот что хочешь, то и думай.
0
Эксперт С++
3071 / 1409 / 425
Регистрация: 19.01.2009
Сообщений: 3,880
13.08.2009, 10:41 4
Ты же открываешь его два раза. функция fopen() возвращает указатель на структуру описывающую данный файл (FILE). Среди прочих элементов, в этой структуре, есть указатель на текущий элемент в файле, изначально, когда файл открывается, то он указывает на самое начало. функция getc() воздействует на указатель при чтении, увеличивая его на единицу, (только для той структуры, адрес которой передан ей в виде аргумента).
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
13.08.2009, 10:50 5
C
1
2
odin_raz= fopen ("fail.txt", "r");
vtoroi_raz= fopen ("fail.txt", "r");
пипец...
На те, без закрытия:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
int main () {
 
 FILE* zapis_v_fail;
 FILE* chetnie_iz_faila;
 
//Записываем сыимолы в файл
   zapis_v_fail= fopen ("fail.txt", "w");
      fputc('a', zapis_v_fail);
         fputc('b', zapis_v_fail);
            fputc('c', zapis_v_fail);
               fputc('d', zapis_v_fail);
  fflush(zapis_v_fail);
                //Считываем на экран первый символ
                    chetnie_iz_faila= fopen ("fail.txt", "r");
                      printf ("simvol= %d", getc (chetnie_iz_faila));
 
                        getchar ();
 
                           return 0;
                           }
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
13.08.2009, 11:38  [ТС] 6
Цитата Сообщение от Vourhey Посмотреть сообщение
Код C
1 2 odin_raz= fopen ("fail.txt", "r"); vtoroi_raz= fopen ("fail.txt", "r");

пипец...
На те, без закрытия:
А что, собственно говоря, смешного?
Мне необходимо считывать текстовый файл не символ за символом подряд, а в другом порядке. Поэтому 2 раза открываю. Используя один указатель, считываю с одного места, используя другой указатель- с другого места.
...Получается, знаете ли.
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
13.08.2009, 11:43 7
kravam, охотно верю, что получается. Смешно то, что это все реализуется и без двойного отрытия файла на чтение.
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
13.08.2009, 11:48  [ТС] 8
Ну, тут дело, наверное в затратах разных.
Смотреть, где код больше (и исходный и бинарный), где памяти больше расходуется.
Я не разбираюсь в этом ещё пока.
Кстати, для моей задачи функция fflush вряд ли подойдёт.
Там так надо.

Содержание файла такое примерно (то есть файл заполняется не программно, вот в чём дело. То есть fflush не подойдёт, наверное)
"air almost any by fly for from gate"
Словарь то есть. Вот считывать надо так:
Считываем посимвольно первое слово и второе и сравниваем символы. Когда находим разные символы... далее по тексту.

Так что тут именно надо два раза открыть его на чтение, потом считать первое слово (первым FILE*) а потом считывать посимвольно и сравнивать.
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
13.08.2009, 11:52 9
kravam, на самом деле, затрат больше на открытие файлового дескриптора и работу с ними двумя, чем на просто сложение/вычитаение.
где памяти больше расходуется.
На переменную FILE больше
где код больше (и исходный и бинарный)
Самая большая ошибка думать, что размер кода влияет на его производительность. Связи никакой.

Если интересно будет потом, то почитай про функции lseek, fseek. А так, работает и ладно.
0
Эксперт С++
7175 / 3234 / 81
Регистрация: 17.06.2009
Сообщений: 14,164
13.08.2009, 17:13 10
Кстати, для моей задачи функция fflush вряд ли подойдёт
А без flush() будут проблемы с буферизацией.

далее по тексту
Давай ты сразу целиком напиши задачу, чтобы нам не гадать.
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
13.08.2009, 21:29  [ТС] 11
Цитата Сообщение от odip Посмотреть сообщение
Давай ты сразу целиком напиши задачу, чтобы нам не гадать.
Не, ну, так-то нет необходимости, я её решил. Мне осталось только разобраться, в том, что мне написали выше и проанализировать (щас пока некогда, не вникал ещё)

А вообще задача такая:

Дан текстовый файл slovar.txt, представляющий из себя перечень слов (английских) в алфавитном порядке. Между словами- по одному пробелу, после последнего слова EOF
Требуется "сжать" этот файл (создать другой файл *txt) по такому правилу:
Допустим, слова такие:
air almost any by fly for from gate

Первое слово копируем полностью. Потом так. Смотрим сколько букв из второго слова совпадают с буквами из первого В данном случае 1 буква 'a' пишем 1, потом most. Получается
air1lmost

Потом смотрим на слова "almost" и "any". Ага, одна буква совпадает, пишем один и остаток слова "ny", уже получится
air1lmost1ny

И так до конца. Пробелы, естествено опускаем. В условии я и алгоритм рассказал почти весь. Вот мой код. Теперь пишу "расифровыватель"

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
#include <iostream>
using namespace std;
 
 
int main () {
 
//Первое что сделаем, объявим два указателя на файл    
 FILE* pravi_ukazatel;
 FILE* levi_ukazatel;
 
//Это указатель на файл-результат
 FILE* fail_rez;
 
 //Вспомогательные переменные
 int  bukva_v_pravom__slove;
 int  bukva_v_levom__slove;
 
 //Это будет счётчик одинаковых букв
 int chotchik_odinakovih_bukv;
 
 int i= 0;
 
 
 //Откроем файл-словарь
 pravi_ukazatel= fopen ("slovar.txt", "r");
 levi_ukazatel= fopen ("slovar.txt", "r");
 
 //Откроем файл-результат, чтобы записывать в него результат.
 fail_rez= fopen ("rezultat.txt", "w");
 
 /*Прежде всего в rezultat.txt полностью считаем первое слово так, чтобы
 fail_rez указывал на следующую за этим словом позицию в файле rezultat.txt  
 */
 while ((bukva_v_pravom__slove=(getc(pravi_ukazatel)))!=32){
  fputc (bukva_v_pravom__slove, fail_rez);
 }
 
 //Это пусть будет условием продолжения цикла.Сам цикл ниже
 bukva_v_pravom__slove= 32;
 
 
 //Ну, то есть после правого слова либо пробел, либо конец файла
 //Если будет конец файла, кина не будет!
 while (bukva_v_pravom__slove== 32){
 
 //Теперь такой вот циклик. Считываем символ за символом из второго и первого слов
  chotchik_odinakovih_bukv= 0;
  while ((bukva_v_pravom__slove= getc(pravi_ukazatel))== (bukva_v_levom__slove= getc(levi_ukazatel))) {
   //Не забываем инкриминировать счётчик
   chotchik_odinakovih_bukv++;
 
  } 
 
 //Всё цикл закончился. Теперь bukva_v_pravom__slove> bukva_v_levom
 //Теперь запишем количество одинаковых символов в фал-результат
 //Предполагаем, что chotchik_odinakovih_bukv< 10, иначе кранты
  fputc ((chotchik_odinakovih_bukv+ 48), fail_rez);
 //Записали. Ноль, так ноль или чего там.
 
 
 /*Теперь символ за символом считываем правое слово, пока не наткнёмся на первый символ
 не являющийся буквой. Одновременно записываем считанные символы в файл-результат
 */
  do {
   fputc (bukva_v_pravom__slove, fail_rez); 
  }
  while (isalpha(bukva_v_pravom__slove= getc(pravi_ukazatel)));
 //Всё, теперь bukva_v_pravom__slove либо 32, либо -1 (либо пробел, либо конец файла)
 //Если пробел, продолжаемрассматривать слова, если EOF, всё на этом
 
 //Но перед этим сделаем так, чтобы и bukva_v_levom__slove== 32.
 //Тогда следующий символ, считагнный getc(levi_ukazatel) будет первой буквой следующего слова.
 //Последнее символ, считанный с помощью levi_ukazatel, находится сейчас в
 //bukva_v_levom__slove. Это либо пробел, либо буква
  while (bukva_v_levom__slove!=32)  {
   bukva_v_levom__slove= getc(levi_ukazatel);
  }
  ;
  i++;
 }
 
 return 0;
}
Добавлено через 1 минуту 42 секунды
Ребята, я напортачил с переменной i, она не нужна вообще.
0
Эксперт С++
7175 / 3234 / 81
Регистрация: 17.06.2009
Сообщений: 14,164
13.08.2009, 21:44 12
Тебе вообще не нужен fgetc() !
Прочитай весь файл в одну строку и работай со строкой.
Это намного удобнее и быстрее, чем прыгать по файлу,
да еще иметь несколько FILE *f1, *f2, *f3.

Когда закодируешь строку - записывай в выходной файл все сразу.
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
13.08.2009, 21:52  [ТС] 13
Цитата Сообщение от odip Посмотреть сообщение
Тебе вообще не нужен fgetc() !
Прочитай весь файл в одну строку и работай со строкой.
Кстати, очень важный вопрос. Меня месяца 2 назад как торкнуло- так и делать, копируем файл в строку и с ней работаем, можно всяко изменять. Манёвренность действительно та ещё. НАвскидку- много удобнее, нежели работы с файлом
...Ну, а ВООБЩЕ это грамотный подход? Или каждый случай в отдельности рассматривать? Я сам учусь, ТАКИХ вещей спросить не у кого.
0
Эксперт С++
7175 / 3234 / 81
Регистрация: 17.06.2009
Сообщений: 14,164
13.08.2009, 21:58 14
это грамотный подход?
Это очень грамотный поход. Файловые операции намного медленнее чем работа со строкой в памяти. К тому же ты сразу наткнулся на кучу глюков, которые описал нам в этой теме
Или каждый случай в отдельности рассматривать?
Всегда читай в память строку из файла чтобы работать c ней. Это верно на 99.99%
Когда ты столкнешься со случаем, когда этого делать не нужно - ты УЗНАЕШЬ сам.

Добавлено через 1 минуту 33 секунды
Вообщем эту тему нужно закрывать.
Если с задачей справился, то ничего делать не нужно
Если не справился - заводить новую тему с другими вопросами
1
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
14.08.2009, 02:17  [ТС] 15
Да, всё так. Единственное неудобство- никогда не знаешь заранее длину файла. Придётся делать строку очень длинной, на всякий случай, чтобы весь файл туда влез.
Спасибо всем, тему можно закрывать.

Добавлено через 3 часа 55 минут 11 секунд
Нет, мне всё-таки одному не разобраться. Извините.
Вот код из самого первого поста.
Я его чуть-чуть изменил. Теперь он ещё выводит 2 значения- адреса структур,
Так вот эти адреса разнятся. Предсказуемо? Вполне. Но я понять не могу,
коль скоро адреса разнятся, chetnie_iz_faila не имеет НИКАКОГО отношения
к zapis_v_fail. (Содержат разные адреса) А значит когда мы записали в файл
символы, указатель на текущую позицию находится где-то там, в недрах
структуры, соответствующей zapis_v_fail.
Но каким-то образом этот указатель, находящийся в структуре, соттветствующей
zapis_v_fail влияет на указатель, находящийся в абсолютно ДРУГОЙ структуре.
(Это всё странно даже с учётом того, что файл zapis_v_fail не закрыт после
записи. Ну, не закрыт- не закрыт, ведь начинается работа со совсем другой
сруктурой)

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
#include <iostream>
using namespace std;
int main () {
 
 FILE* zapis_v_fail;
 FILE* chetnie_iz_faila;
 
 //Записываем сыимолы в файл
   zapis_v_fail= fopen ("fail.txt", "w");
   fputc('a', zapis_v_fail);
   fputc('b', zapis_v_fail);
   fputc('c', zapis_v_fail);
   fputc('d', zapis_v_fail);
 
 //Считываем на экран первый символ
   chetnie_iz_faila= fopen ("fail.txt", "r");
   printf ("simvol= %d", getc (chetnie_iz_faila));
 
 //А вот адреса структур. Они РАЗНЫЕ
   printf ("adres strukturi zapis_v_fail= %d", zapis_v_fail);
   printf ("adres strukturi chetnie_iz_faila= %d", chetnie_iz_faila);
 
 
 fclose (zapis_v_fail);
 fclose (chetnie_iz_faila);
 
 getchar ();
 
 return 0;
}
0
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
14.08.2009, 02:50 16
Когда ты открываешь файл и используешь fputc,то ты продвигаешь каждый раз указатель в связанном с файлом потоке.Когда ты открываешь его с fopen,то файл уже открыт,и возможно что он открывается с той же позиции указателя,которую установил fputc,а это значит,что файловый буфер у них общий.Попробуй сначала закрыть файл,а потом уже
C
1
chetnie_iz_faila= fopen ("fail.txt", "r");
Советую поглядеть описание функций.

Добавлено через 14 минут 5 секунд
Попробуй перед открытием использовать функцию
C
1
void rewind ( FILE * stream );
Или fseek,или нечто в этом роде.
А вычитал я это здесь http://www.cplusplus.com/refer... ry/cstdio/
То есть примерно так:
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
#include <iostream.h> 
 
int main (void) {
 
 FILE* zapis_v_fail;
 FILE* chetnie_iz_faila;
 
 //Записываем сыимолы в файл
   zapis_v_fail= fopen ("fail.txt", "w");
   fputc('a', zapis_v_fail);
   fputc('b', zapis_v_fail);
   fputc('c', zapis_v_fail);
   fputc('d', zapis_v_fail);
 
   rewind ( zapis_v_fail );
 //Считываем на экран первый символ
   chetnie_iz_faila= fopen ("fail.txt", "r");
   printf ("simvol= %d", getc (chetnie_iz_faila));
 
 //А вот адреса структур. Они РАЗНЫЕ
   printf ("adres strukturi zapis_v_fail= %d", zapis_v_fail);
   printf ("adres strukturi chetnie_iz_faila= %d", chetnie_iz_faila);
 
 
  fclose (zapis_v_fail);
  fclose (chetnie_iz_faila);
 
  getchar ();
 
  return 0;
}
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
14.08.2009, 02:51  [ТС] 17
Да... Вот именно, что "возможно что он открывается с той же позиции указателя,которую установил fputc"
А вот если осуществляем запись одним указатель на файл, а потом другим, а файл один и тот же, то ничего подобного не происходит.
Вторая запись в файл начнётся сначала файла.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
 [FONT=monospace][FONT=verdana,geneva,lucida,'lucida grande',arial,helvetica,sans-serif]//Записываем в файл
   zapis_v_fail= fopen ("qqq.txt", "w");
   fputc('a', zapis_v_fail);
   fputc('b', zapis_v_fail);
   fputc('c', zapis_v_fail);
   fputc('d', zapis_v_fail);
 
 //И ещё раз
   chetnie_iz_faila= fopen ("qqq.txt", "w");
   fputc('w', chetnie_iz_faila);
   fputc('e', chetnie_iz_faila);
   fputc('r', chetnie_iz_faila);
   fputc('t', chetnie_iz_faila);[/FONT][/FONT]

Только и остаётся, что пометить себе куда-нибудь и вызубрить. А почему так- непонятно. А с закрытием получится, да
rewind, да... Спасибо, пойду учиться. Да хоть бы где-то подобную тонкость описали, а то у меня K&R, Стефан Кочан, ещё что-то. И нигде такое дело не оговорено.
0
Временно недоступен
957 / 228 / 14
Регистрация: 12.04.2009
Сообщений: 926
14.08.2009, 03:00 18
Непонял,а в чём разница с примером выше ? ...А,понял,ты продолжаешь запись вместо чтения..Значит чтение-запись связаны особыми узами,и когда ты записываешь,а потом читаешь,то читаешь с того места,где записали последний раз.
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
14.08.2009, 03:09  [ТС] 19
Ну да. Так получается.
Просто и неохота людей беспокоить- форумчан то есть, но и НЕ СПРОСИТЬ НЕЛЬЗЯ.
Потому и ругаюсь про себя на авторов книг.
0
14.08.2009, 03:09
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
14.08.2009, 03:09
Помогаю со студенческими работами здесь

Сканер считывает штрихкод и теряет первый символ
Всем привет. С такой проблемой столкнулись... В общем ситуация: сканер Honeywell metrologic 9540....

Поменять местами первый и последний символ в первом слове
дана строка, поменять местами первый и последний символ в первом слове... uses crt; const ...

Поменять местами первый и последний символ в первом слове
Напишите плиз прогу: дана строка, поменять местами первый и последний символ в первом слове...

Почему при чтении файла последний символ выводится 2 раза?
если структура файла: 1\nEOF. То почему не выполняется условие if(Ch != '\n') { ...


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

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