#c #file
#c #файл
Вопрос:
Этот код в основном должен считывать число из двух файлов, определять, какой из них меньше, записывать это меньшее число в выходной файл, захватывать новое число, промывать и повторять. По большей части это хорошо, но когда дело доходит до конца, оно не останавливается. Я пытался использовать EOF, чтобы указать ему остановиться, как только он достигнет конца файла, но он просто бесконечно зацикливается и добавляет последнее число в выходной файл, поэтому вместо того, чтобы выглядеть как «123456789», как и должно быть, он выглядит как «123456788999999999999», 8 печатается дважды, а 9просто повторяется бесконечно. Я неправильно использую EOF? Или мне нужно сделать что-то совсем другое, имейте в виду, что я очень новичок в c и не знаю очень многих вещей.
#include <stdio.h>
#include <stdlib.h>
void mergeFuncs(FILE* num1txt, FILE* num2txt, FILE* outtxt);
int main(int argc, char* argv[]) {
FILE* num1txt;
num1txt = fopen("numbers1.txt", "r");
if (num1txt == NULL) {
printf("Error opening numbers1.txt!");
exit(1);
}
FILE* num2txt;
num2txt = fopen("numbers2.txt", "r");
if (num2txt == NULL) {
printf("Error opening numbers2.txt!");
exit(1);
}
FILE* outtxt;
outtxt = fopen("output.txt", "w");
if (outtxt == NULL) {
printf("Error opening output.txt!");
exit(1);
}
mergeFuncs(num1txt, num2txt, outtxt);
return 0;
}
void mergeFuncs(FILE* num1txt, FILE* num2txt, FILE* outtxt) {
int num1, num2, loop = 1, endOfFile1, endOfFile2;
endOfFile1 = fscanf(num1txt, "%d", amp;num1);
printf("in getNum1 - %dn", num1);
endOfFile2 = fscanf(num2txt, "%d", amp;num2);
printf("in getNum2 - %dn", num2);
while (loop) {
printf("nStart of a new loop! num1 is [%d], and num2 is [%d]n", num1, num2);
if (endOfFile1 == EOF amp;amp; endOfFile2 == EOF) {
if (num1 < num2) {
fprintf(outtxt, "%d", num1);
printf("num1 is smallern");
fprintf(outtxt, "%d", num2);
printf("done :) //uwu//");
fclose(num1txt);
fclose(num2txt);
fclose(outtxt);
}
else if (num2 < num1) {
fprintf(outtxt, "%d", num2);
printf("num2 is smallern");
fprintf(outtxt, "%d", num1);
printf("done :) //uwu//");
fclose(num1txt);
fclose(num2txt);
fclose(outtxt);
}
loop = 0;
}
else if (endOfFile1 == EOF) {
fprintf(outtxt, "%d", num1);
while (endOfFile2 !=EOF) {
fprintf(outtxt, "%d", num2);
}
fprintf(outtxt, "%d", num2);
loop = 0;
fclose(num1txt);
fclose(num2txt);
fclose(outtxt);
}
else if (endOfFile2 == EOF) {
fprintf(outtxt, "%d", num2);
while (endOfFile1 != EOF) {
printf(outtxt, "%d", num1);
}
printf(outtxt, "%d", num1);
loop = 0;
fclose(num1txt);
fclose(num2txt);
fclose(outtxt);
}
else if (num1 < num2) {
fprintf(outtxt, "%d", num1);
printf("num1 is smallern");
endOfFile1 = fscanf(num1txt, "%d", amp;num1);
printf("in getNum1 - %dn", num1);
}
else if (num2 < num1) {
fprintf(outtxt, "%d", num2);
printf("num2 is smallern");
endOfFile2 = fscanf(num2txt, "%d", amp;num2);
printf("in getNum2 - %dn", num2);
}
}
return;
}
Комментарии:
1. Такие вещи, как
while (endOfFile1 != EOF) { printf(outtxt, "%d", num1); }
должны привлечь ваше внимание.endOfFile1
никогда не обновляется в этом цикле, так как же цикл может когда-либо закончиться? Также аргументы неверныprintf
, что, по-видимому, должно бытьfprintf
. Неужели компилятор действительно позволил вам это сделать?2. Возможно, проверка документации для fscanf и того, что она возвращает, может дать некоторое представление.
Ответ №1:
Вы хотите иметь единственное место, в котором вы читаете из файлов. Читайте оба, пока каждый из них не будет исчерпан. Если сначала будет исчерпан один файл, заполните его значение фиктивным большим значением (INT_MAX из limits .h — хороший выбор), чтобы другое значение использовалось как минимальное. Ваша функция может быть реализована как:
void
mergeFuncs(FILE* num1txt, FILE* num2txt, FILE* outtxt)
{
int a, b, c = INT_MAX, d = INT_MAX;
while(
a = fscanf(num1txt, "%d", amp;c),
b = fscanf(num2txt, "%d", amp;d),
a == 1 || b == 1
){
fprintf(outtxt, "%d,", c > d ? d : c);
c = d = INT_MAX;
}
return;
}
Обратите внимание, что приведенное выше не делает различий между достижением конца файла, неверным вводом или ошибкой чтения. Если вас волнует это различие, используйте feof
и / или ferror
, чтобы решить, выдавать или нет соответствующее сообщение об ошибке. Хорошим упражнением является изменение приведенного выше для обработки недопустимого ввода.
Кроме того, вероятно, не идеально пытаться считывать данные из файла после scanf
сбоя, поэтому вы можете закоротить чтение в более коротком файле (или файле с ошибкой чтения или неверным вводом) чем-то вроде:
void
mergeFuncs(FILE* num1txt, FILE* num2txt, FILE* outtxt)
{
int a = 1, b = 1, c = INT_MAX, d = INT_MAX;
while(
a = a == 1 ? fscanf(num1txt, "%d", amp;c) : 0,
b = b == 1 ? fscanf(num2txt, "%d", amp;d) : 0,
a == 1 || b == 1
){
fprintf(outtxt, "%d,", c > d ? d : c);
c = d = INT_MAX;
}
return;
}
Обратите внимание, что при этом коротком замыкании становится трудно отличить ошибку чтения от неверного ввода. Исправление этого оставлено в качестве упражнения для читателя.
Также обратите внимание, что если ваши входные файлы выглядят как 1523
and 3181
, выходной файл не будет 1121
but 1523
, поскольку каждый из этих входных данных представляет собой всего одно целое число. scanf
не считывает отдельные цифры. Если вы хотите прочитать отдельные цифры, вам нужно будет что-то изменить. Ваше замечание о том, что ваш выходной файл выглядит так 123456788999999999999
, предполагает, что вы, возможно, хотите использовать спецификатор %c
преобразования для чтения отдельных цифр. Я добавил запятую после каждого значения в выходных данных, чтобы прояснить этот момент.
Ответ №2:
вместо того, чтобы полагаться на возвращаемое значение fscanf
, которое может или не может фактически возвращать EOF, используйте feof
, чтобы точно знать, пуст ли файл.
согласно спецификации fscanf
EOF возвращается только тогда, когда файл уже пуст, но в вашем случае у вас может быть конечный пробел в конце файла, который fscanf
не будет использоваться, поскольку после него нет данных для сопоставления.