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

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

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 20, средняя оценка - 4.60
kravam
быдлокодер
1700 / 887 / 45
Регистрация: 04.06.2008
Сообщений: 5,494
#1

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

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

Друзья! Здравствуйте! Вот код.

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
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
13.08.2009, 08:11
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Функция getc (FILE*) при первом вызве считывает НЕ ПЕРВЫЙ символ файла.Почему? (C++):

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

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

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

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

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

Почему печатает только первый символ из argv[i]? - C++
Почему печатает только первый символ из argv? Как написать чтобы печатало всю строку argv? // #include &quot;stdafx.h&quot; #include...

18
Vourhey
Почетный модератор
6485 / 2259 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
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
kravam
быдлокодер
1700 / 887 / 45
Регистрация: 04.06.2008
Сообщений: 5,494
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
schdub
2955 / 1300 / 239
Регистрация: 19.01.2009
Сообщений: 3,413
Завершенные тесты: 1
13.08.2009, 10:41 #4
Ты же открываешь его два раза. функция fopen() возвращает указатель на структуру описывающую данный файл (FILE). Среди прочих элементов, в этой структуре, есть указатель на текущий элемент в файле, изначально, когда файл открывается, то он указывает на самое начало. функция getc() воздействует на указатель при чтении, увеличивая его на единицу, (только для той структуры, адрес которой передан ей в виде аргумента).
0
Vourhey
Почетный модератор
6485 / 2259 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
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
kravam
быдлокодер
1700 / 887 / 45
Регистрация: 04.06.2008
Сообщений: 5,494
13.08.2009, 11:38  [ТС] #6
Цитата Сообщение от Vourhey Посмотреть сообщение
Код C
1 2 odin_raz= fopen ("fail.txt", "r"); vtoroi_raz= fopen ("fail.txt", "r");

пипец...
На те, без закрытия:
А что, собственно говоря, смешного?
Мне необходимо считывать текстовый файл не символ за символом подряд, а в другом порядке. Поэтому 2 раза открываю. Используя один указатель, считываю с одного места, используя другой указатель- с другого места.
...Получается, знаете ли.
0
Vourhey
Почетный модератор
6485 / 2259 / 123
Регистрация: 29.07.2006
Сообщений: 12,635
13.08.2009, 11:43 #7
kravam, охотно верю, что получается. Смешно то, что это все реализуется и без двойного отрытия файла на чтение.
0
kravam
быдлокодер
1700 / 887 / 45
Регистрация: 04.06.2008
Сообщений: 5,494
13.08.2009, 11:48  [ТС] #8
Ну, тут дело, наверное в затратах разных.
Смотреть, где код больше (и исходный и бинарный), где памяти больше расходуется.
Я не разбираюсь в этом ещё пока.
Кстати, для моей задачи функция fflush вряд ли подойдёт.
Там так надо.

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

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

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

далее по тексту
Давай ты сразу целиком напиши задачу, чтобы нам не гадать.
0
kravam
быдлокодер
1700 / 887 / 45
Регистрация: 04.06.2008
Сообщений: 5,494
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
odip
Эксперт С++
7158 / 3220 / 59
Регистрация: 17.06.2009
Сообщений: 14,164
13.08.2009, 21:44 #12
Тебе вообще не нужен fgetc() !
Прочитай весь файл в одну строку и работай со строкой.
Это намного удобнее и быстрее, чем прыгать по файлу,
да еще иметь несколько FILE *f1, *f2, *f3.

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

Добавлено через 1 минуту 33 секунды
Вообщем эту тему нужно закрывать.
Если с задачей справился, то ничего делать не нужно
Если не справился - заводить новую тему с другими вопросами
1
kravam
быдлокодер
1700 / 887 / 45
Регистрация: 04.06.2008
Сообщений: 5,494
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
14.08.2009, 02:17
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.08.2009, 02:17
Привет! Вот еще темы с ответами:

Функция,которая считывает из файла только n последних строк - C++
Привет! Подскажите как прописать функцию, перед этим уже прописала потоковое чтение из файла и посчитала количество строк в файле. Спасибо!

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

вопрос к спецам: почему функция fputc при работе не устанавливает счётчик файла в конец? - C++
Друзья! То есть написана программка. С клавы вводится ОДИН символ и он запихивается в файл. А потом этот файл с помощью функции fread...

Функция, находящая в строке первый символ, который входит в другую заданную строку - C++
Доброго времени суток! Есть такое задание: написать функцию, которая находит в строке первый символ, который входит в другую заданную...


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

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

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