@ZIK1337

Почему в VS программа на СИ работает неправильно, хотя в онлайн компиляторе все в порядке?

Код:
spoiler
#include <stdio.h>
#include <string.h>
#include <locale.h>

// для задания 1.4 (посимвольное копирования из входного файла в выходной)
void getputChar(FILE* infile, FILE* outfile)
{
	char cha;

	cha = fgetc(infile);
	fputc(cha, outfile);
}

// для задания 1.4
int reverseOrder(FILE* infile, int pos, FILE* outfile)
{
	int npos = pos;
	char ch1;
	int count;
	int n;

	while (1) {
		ch1 = fgetc(infile);
		if (ch1 == '\n') {
			count = reverseOrder(infile, npos + 1, outfile) + 1;
			fseek(infile, pos, SEEK_SET);
			for (n = 0; n < count; ++n)
				getputChar(infile, outfile);
			fputc('\n', outfile);
			return count;
		}
		else if (ch1 == EOF) {
			if (npos - pos == 0)
				return 0;
			else {
				fseek(infile, pos, SEEK_SET);
				getputChar(infile, outfile);
				fputc('\n', outfile);
				return 1;
			}
		}
		else {
			npos++;
		}
	}
}

int main(int argc, char **argv)
{
	setlocale(LC_ALL, "Ru");
	FILE *file_ptr; // указатель на файл (задание 1.1)
	int N; // количество строк и символов в строках (задание 1.1)
	int count = 0; // для подсчета количества строк (задание 1.2)
	char ch; // для подсчета количества строк (задание 1.2)
	char text[50] = "0"; // строка для чтения из файла
	FILE *file_ptr1; // указатель на f2 (задание 1.4)
	int a; // для задания 1.3
	char tmp; // для задания 1.3
	FILE *file_ptr2; // вспомогательный файл для задания 1.3
	int c = 0; // для задания 1.4 (определение, какая строка считалась)

	file_ptr = fopen("D:\\f1.txt", "w+");
	file_ptr1 = fopen("D:\\f2.txt", "w+");
	file_ptr2 = fopen("D:\\f3.txt", "w+");

	if (file_ptr != NULL) {
		printf("Введите количество строк в файле и символов в них (не более 10): \n");
		scanf("%d", &N);

		if (N > 10) {
			do {
				printf("Нужно ввести число не более 10! Повторите ввод: \n");
				scanf("%d", &N);
			} while (N > 10);
		}

		printf("Введите строки не более %d символов.\n", N);

		for (int i = 0; i < N; i++)
		{
			printf("Введите %d-ю строку: \n", (i + 1));
			scanf("%s", text);
			if (strlen(text) > N) {
				do {
					printf("Нельзя вводить больше %d символов! Введите строку еще раз: \n", N);
					scanf("%s", text);
				} while (strlen(text) > N);
				fputs(text, file_ptr);
				fputs("\n", file_ptr);
			}
			else
			{
				fputs(text, file_ptr);
				fputs("\n", file_ptr);
			}
		}


		// вывод числа строк в файле (задание 1.2)
		fseek(file_ptr, 0, SEEK_SET);
		while ((ch = fgetc(file_ptr)) != EOF) {
			if (ch == '\n')
				++count;
		}
		printf("Количество строк в файле: %d\n", count);


		// реверс строк в файле (задание 1.3)
		fseek(file_ptr, 0, SEEK_SET);
		while (fgets(text, 50, file_ptr)) {
			count = strlen(text) - 1;
			for (a = 0; a < count / 2; a++) {
				tmp = text[a];
				text[a] = text[count - 1 - a];
				text[count - 1 - a] = tmp;
			}
			fputs(text, file_ptr2);
		}
		// копирование из вспомогательного файла в исходный
		fseek(file_ptr, 0, SEEK_SET);
		fseek(file_ptr2, 0, SEEK_SET);
		if (file_ptr2 != NULL) {
			while (fgets(text, 50, file_ptr2)) {
				fputs(text, file_ptr);
			}
		}
		else {
			printf("Невозможно открыть файл f3\n");
			return 1;
		}


		// вывод в f2 (задание 1.4)
		if (file_ptr1 != NULL) {
			fseek(file_ptr, 0, SEEK_SET);
			fseek(file_ptr1, 0, SEEK_SET);
			reverseOrder(file_ptr, 0, file_ptr1);
		}
		else {
			printf("Невозможно открыть файл f2\n");
			return 1;
		}
		/*fseek(file_ptr, 0, SEEK_SET);
		if (file_ptr1 != NULL) {
			while (fgets(text, 50, file_ptr)) {
				c++;
				fseek(file_ptr1, strlen(text), SEEK_CUR);
				fputs(text[strlen(text) - c - 1], file_ptr1);
				fputs("\n", file_ptr1);
			}
		}
		else {
			printf("Невозможно открыть файл f2\n");
			return 1;
		}*/


		// вывод содержимого f2 на экран (задание 1.5)
		printf("Содержимое файла f2:\n");
		fseek(file_ptr1, 0, SEEK_SET);
		while (fgets(text, 50, file_ptr1)) {
			printf("%s", text);
		}

		fclose(file_ptr);
		fclose(file_ptr1);
		fclose(file_ptr2);
		_getch();
		return 0;
	}
	else {
		printf("Невозможно открыть файл f1\n");
		return 1;
	}
}

Как выводит VS:
spoiler
k4Ys4Y6.jpg

Как выводит https://www.jdoodle.com/ (как это и должно быть):
spoiler
VHcsg1MuSWM.jpg
  • Вопрос задан
  • 171 просмотр
Решения вопроса 1
WNeZRoS
@WNeZRoS
Онлайн компилятор компилирует при помощи GCC, и скорее всего на Linux системе.
В Visual Studio компилятор Visual C и система Windows.
В Windows строка в текстовых файлых файлах заканчивается двумя символами - \r\n.
В Linux строка заканчивается одним символом - \n.
При записи в текстовый файл символа \n в Windows автоматически добавляется символ \r.
При чтении текстового файла он пропускается.

Соответственно, у вас в reverseOrder получается неправильный pos на который делается fseek т.к. считается в ручную.
Починить это можно двумя способами: или сказать системе что файл бинарный, или вместо ручного подсчёт npos использовать ftell.
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
tsarevfs
@tsarevfs
C++ developer
В С++ есть понятие неопределенного поведения. Когда вы делаете что-то сильно неправильно, компилятор может делать все что ему захочется, вплоть до запуска межконтинентальных баллистических ракет.
В вашем случае некорректное поведение воспроизводится локально, вам повезло. Студия содержит отладчик, который позволит вам исполнить программу по шагам и найти момент в который все идет не по плану.
Ответ написан
CityCat4
@CityCat4
Кошки не похожи на людей, кошки - это кошки!
Вангую, что ответа на этот вопрос Вы не получите :)

Почему?

Потому что никому неинтересно продираться через очередную нубскую лабу по потоковому вводу-выводу или чему-нибудь еще такому же.
Ответ написан
@res2001
Developer, ex-admin
У вас куча операций с файлами, любая может вернуть ошибку. У вас в коде нет ни одной проверки ошибок.
Были бы проверки ошибок, возможно это вам бы помогло.
В reverseOrder() - используется рекурсия, по тексту заданий я вообще не понял, где там можно было бы применить рекурсию. Возможно ошибка где-то тут.
В 1.3 вы странно вычисляете count - strlen() возвращает количество символов уже без учета нулевого символа. Зачем вы еще вычитаете 1?

Вообще задания у вас линейные. Я бы немного видоизменил решение, что значительно бы упростило код.
А именно - вводите строку и сразу делаете над ней всю обработку и распихивание по файлам. Потом следующую вводите и обрабатываете и так до конца.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы