БлогNot. Visual C++: почему fscanf не читает числа в цикле

Visual C++: почему fscanf не читает числа в цикле

Решал человек в Visual Studio (C++) типовую задачку по форматному чтению данных из текстового файла. Например:

Файл text.txt в текущей папке приложения имеет следующий вид:
1 1.5 -3.5
2 3.5
Прочитать его как последовательность вещественных чисел.

Вот программа:

#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
 setlocale(LC_ALL,"Rus"); 
 SetConsoleCP(1251); SetConsoleOutputCP(1251);

 FILE *fp = fopen ("text.txt","r");
 if (fp==NULL) {
  printf ("\nне удалось открыть файл");  getchar(); exit (1); 
 }
 float a;
 while (1) {
  fscanf (fp,"%f",&a);
  if (feof(fp)) break; //Если файл кончился, выйти из цикла 
  //здесь выполняется обработка очередного значения a, например:
  printf ("%.2f ",a);
 }
 fclose(fp);
 
 fflush(stdin); getchar();  return 0;
}

Увы, при её запуске в консоли бесконечно "крутится" только прочитанная первой "единичка", будто и не работает цикл while.

В чём причина? Да она не одна. На самом деле, к такой программке требуется сделать минимум 5 пояснений:

1. Функции семейства scanf возвращают целое число - количество значений, которые успешно прочитаны в соответствии с указанным форматом. В реальных приложениях эту величину следует проверять в коде:

int i=fscanf (fp,"%f",&a);
if (i!=1) {
 //не удалось получить 1 значение
}

2. На "восприятие" программой данных может влиять установленная в приложении локаль. Например, если до показанного кода выполнен оператор

setlocale(LC_ALL,"Rus");

результат работы кода может измениться (для русской локали разделителем целой и дробной части числа является запятая, а не точка).

3. Очередное чтение данных изменяет внутренний файловый указатель. Этот указатель в любой момент времени, пока файл открыт, показывает на следующее значение, которое будет прочитано. Благодаря этому наш код с "бесконечным" while не зациклился.

4. Код показывает, как читать из файла заранее неизвестное количество значений – это позволяет сделать стандартная функция feof (проверка, достигнут ли конец файла; вернёт не 0, если прочитано всё).

5. Распространённый в примерах из Сети код вида

while (!feof(fp)) {
 fscanf (fp,"%f",&a);
 //обработка числа a
}

в ряде компиляторов может породить неточности при интерпретации данных. Например, этот код может прочитать как последнее значение завершающий перевод строки в файле, благодаря чему последнее прочитанное значение "удвоится".

Итак, убираем или комментируем

setlocale(LC_ALL,"Rus"); 

и всё заработало :)

15.10.2015, 15:55 [7917 просмотров]


теги: c++ ошибка форматы studio

К этой статье пока нет комментариев, Ваш будет первым