Хотя вы обычно используете библиотеку C ++ iostream
для файлового ввода / вывода, нет ничего, что говорило бы о том, что вы не можете использовать функции C cstdio
, такие как fscanf
- при условии, что вы используете их правильно (и часто они будут быстрее, чем iostream
подход)
В вашем случае у вас много цифр с текстом в середине, которые вы пытаетесь прочитать с помощью fscanf
в цикле. Это нормально, это достаточно просто сделать, но ... вы должны правильно обработать сбой сопоставления случай , который произойдет, когда вы попытка чтения 's'
с помощью спецификатора преобразования "%08x"
.
Когда совпадает с ошибкой , извлечение символа из потока останавливается в точке сбоя, оставляя все, начиная с символа, вызывающего сбой (и что следует за ним) непрочитанным во входном буфере. Если вы правильно не извлечете символы, вызывающие сбой совпадения из входного потока, вы, скорее всего, столкнетесь с бесконечным циклом, поскольку символы, вызывающие сбой, остаются непрочитанными, просто ожидая, чтобы вас снова укусили при следующей попытке чтения.
Итак, как справиться с ошибкой совпадения ? Заголовок cctype
предоставляет макрос isdigit
, который позволяет просто проверить, является ли следующий символ во входном потоке цифрой. Вы проверяете символ, сначала читая с fgetc
(или getc
- то же самое, но часто реализуемое как макрос), а затем с isdigit
, например,
int c = fgetc(in_file); /* read next char */
while (c != EOF && !isdigit(c)) /* check EOF and isdigit */
c = fgetc(in_file); /* get next char */
Выше вы читаете следующий символ, затем вводите цикл, подтверждающий, что вы не достигли EOF
, и затем проверяете, является ли c
Не цифрой. Если эти условия выполняются, вы снова проверяете следующий символ, пока не достигнете EOF
Или не найдете следующую цифру во входном потоке. Но теперь у вас есть проблема, вы уже прочитали цифру из потока, как fscanf
сможет прочитать ее как часть следующего целого числа?
Простой - положить его обратно в поток ввода:
if (c != EOF) /* if not EOF, then digit */
ungetc (c, in_file); /* put back for next read */
Теперь вы можете прочитать все 64 целочисленных значения из in_file
с помощью простого цикла, например,
while (1) { /* loop continually until EOF */
int rtn = fscanf (in_file,"%08x", &number1); /* validate return */
if (rtn == EOF) /* if EOF, break loop */
break;
else if (rtn == 0) { /* handle matching failure */
int c = fgetc(in_file); /* read next char */
while (c != EOF && !isdigit(c)) /* check EOF and isdigit */
c = fgetc(in_file); /* get next char */
if (c != EOF) /* if not EOF, then digit */
ungetc (c, in_file); /* put back for next read */
}
else /* good read, output number */
fprintf (out_file, "%08x\n", number1);
}
( примечание: ваш выходной файл был переименован из in_file1
в out_file
- всегда используйте значимые имена переменных)
Теперь некоторые убираются. Когда вы открываете in_file
, вы подтверждаете, что файл открыт для чтения. Хорошо, но для условия ошибки вы exit (-1);
. Не возвращайте отрицательные значения в оболочку. У вас есть две константы для обозначения имен успехов / неудач EXIT_SUCCESS
(0
) и EXIT_FAILURE
(значение 1
, не -1
).
Хотя вы проверяли, что in_file
был открыт для чтения, вы не смогли проверить, открыт ли ваш выходной файл для записи? Всегда проверяйте возврат всех потоков ввода / вывода и функций ввода / вывода. В противном случае попытка записи в поток в состоянии ошибки вызывает неопределенное поведение.
В целом, вы можете сделать:
#include <cstdio>
#include <cstdlib>
#include <cctype>
using namespace std;
int main (void) {
unsigned int number1;
FILE* in_file = fopen ("example.txt", "r");
FILE* out_file = fopen ("wrte.txt", "w");
if (!in_file) { /* validate file open for reading */
printf ("oops, file can't be read\n");
exit (1); /* don't return negative values to the shell */
}
if (!out_file) { /* validate file open for writing */
printf ("oops, file can't be read\n");
exit (1); /* don't return negative values to the shell */
}
while (1) { /* loop continually until EOF */
int rtn = fscanf (in_file,"%08x", &number1); /* validate return */
if (rtn == EOF) /* if EOF, break loop */
break;
else if (rtn == 0) { /* handle matching failure */
int c = fgetc(in_file); /* read next char */
while (c != EOF && !isdigit(c)) /* check EOF and isdigit */
c = fgetc(in_file); /* get next char */
if (c != EOF) /* if not EOF, then digit */
ungetc (c, in_file); /* put back for next read */
}
else /* good read, output number */
fprintf (out_file, "%08x\n", number1);
}
fclose (in_file);
fclose (out_file);
}
Пример выходного файла
$ cat wrte.txt
01000000
01000000
01000000
01000000
...
01000000
Записаны все 64 значения, которые можно подтвердить с помощью wc -l
, например,
$ wc -l < wrte.txt
64
Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы. Та же логика применима, если вы используете библиотеку iostream
, имена функций немного отличаются (некоторые идентичны), но вместо этого реализованы как функции-члены.