Table of Contents
- Автотест: Общий Шаблон и Рекомендации
- Общая Структура Решений
- Работа с qsort и Функцией Сравнения
- Частые Ошибки
- 1. Возврат локального массива
- 2. Игнорирование результатов fopen, fscanf, fprintf, fclose
- 3. Отсутствие проверок malloc / realloc
- 4. Неправильное разделение логики
- 5. Возврат любого другого числа кроме 0 и -1 в main
- Итог: На Чём Сделать Акцент
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Автотест: Общий Шаблон и Рекомендации
В этом разделе рассматриваются задачи, где нужно:
- Считать из файлов
ina.txtиinb.txtдва массива (неизвестной длины). - Обработать данные массивы.
- Записать результат в
output.txt.
При этом важно корректно работать с динамической памятью, файлами, проверять все возможные ошибки и аккуратно сортировать (часто через qsort). Ниже — основные моменты, на которые стоит обратить внимание.
Общая Структура Решений
-
Открытие файлов для чтения/записи:
FILE *fileA = fopen("ina.txt", "r"); // открываем для чтения if (fileA == NULL) { // Ошибка: не удалось открыть return -1; } FILE *fileOut = fopen("output.txt", "w"); // открываем для записи if (fileOut == NULL) { // Ошибка: не удалось открыть return -1; }"r"— открытие для чтения."w"— открытие для записи. (Содержимое файла затирается, если файл уже был.)
-
Чтение массива неизвестной длины:
// Допустим, в файле лежат вещественные числа (double), одно за другим: double current; int size = 2, len = 0; double *arr = malloc(size * sizeof(double)); if (!arr) return -1; // нет памяти while (fscanf(fileA, "%lf", ¤t) == 1) { // если достигли текущего размера, расширяем if (len >= size) { int newSize = size * 2; double *tmp = realloc(arr, newSize * sizeof(double)); if (!tmp) { free(arr); return -1; } arr = tmp; size = newSize; } arr[len++] = current; } if (len == 0) { // Файл может оказаться пустым или там нет корректных чисел free(arr); return -1; }"%lf"говоритfscanf, что считываем вещественное число (double).- Для целых чисел используется
"%d". - Проверять, что
fscanf(...) == 1, иначе — либо конец файла, либо ошибка формата.
-
Обработка массива:
- Сортировка, поиск, проверка условий и т.д. — в зависимости от задачи.
-
Запись результата:
// Например, нужно вывести слово "YES" или "NO" if (fprintf(fileOut, "YES") < 1) { // Ошибка записи free(arr); fclose(fileOut); return -1; } -
Закрытие файлов и освобождение памяти:
if (fclose(fileA) != 0 || fclose(fileOut) != 0) { // Ошибка при закрытии free(arr); return -1; } free(arr); return 0; // успешно
При любом сбое (не открылся файл, не считались данные, не хватило памяти, не закрылся файл и т.д.) программа должна возвращать -1 (по условию), не записывая результата в выходной файл.
Работа с qsort и Функцией Сравнения
В ряде задач удобно использовать стандартную функцию qsort (из <stdlib.h>) для сортировки. Её сигнатура:
void qsort(
void *base, // начало массива
size_t nitems, // число элементов
size_t size, // размер каждого элемента
int (*compar)(const void *, const void *)
);
base: указатель на первый элемент массива (в C это обычноarr).nitems: количество элементов (например,length).size: размер одного элемента в байтах (например,sizeof(double)).compar: указатель на функцию сравнения.
Как работает compar (функция сравнения)
Пример для сортировки по возрастанию (double):
int cmpAsc(const void *a, const void *b) {
// a и b — указатели на элементы массива типа (const void *).
// Нужно явно привести к (double *) и взять значение:
double x = *(const double *)a;
double y = *(const double *)b;
if (x < y) return -1; // x идёт раньше
else if (x > y) return 1;
else return 0;
}
Почему void *?
Язык C не поддерживает шаблоны (templates) напрямую, поэтому qsort работает с «генериком»: любой тип массива представляется просто как «указатель на память» (void *). Внутри compar мы уже знаем конкретный тип (например, double) и делаем приведение (double *), затем берём *(double *)a, чтобы получить реальное числовое значение.
return -1: элементaидёт раньшеb.return +1: элементaидёт послеb.return 0: элементы равны (по порядку не различаются).
Для убывающей сортировки меняем приоритет:
int cmpDesc(const void *a, const void *b) {
double x = *(const double *)a;
double y = *(const double *)b;
if (x > y) return -1; // теперь большее значение идёт "раньше"
else if (x < y) return 1;
return 0;
}
Вызывается так:
qsort(arr, length, sizeof(double), cmpAsc); // по возрастанию
// или
qsort(arr, length, sizeof(double), cmpDesc); // по убыванию
Частые Ошибки
1. Возврат локального массива
Нельзя:
double * wrongFunction() {
double temp[100];
// ...
return temp; // Массив пропадёт за пределами функции!
}
Правильно: использовать malloc внутри функции и возвращать динамический массив (или вернуть в структуре).
2. Игнорирование результатов fopen, fscanf, fprintf, fclose
Всегда проверяйте:
FILE *f = fopen("filename.txt", "r");
if (!f) return -1; // ошибка
if (fprintf(f, "Hello") < 1) {
// ошибка записи
}
if (fclose(f) != 0) {
// ошибка закрытия
}
3. Отсутствие проверок malloc / realloc
double * arr = malloc(n * sizeof(double));
if (!arr) return -1; // нет памяти
double * tmp = realloc(arr, newSize * sizeof(double));
if (!tmp) {
free(arr);
return -1;
}
arr = tmp;
4. Неправильное разделение логики
По условию задачи, ввод и обработка должны быть в разных функциях. Смешивание чтения массива, вычислений и записи ответа в одну большую функцию — плохая практика, усложняет тесты и увеличивает риск ошибок.
5. Возврат любого другого числа кроме 0 и -1 в main
Нельзя:
int main(void) {
// ...
return 1; // При верном ответе, так делать нельзя!
}
Правильно: Вернуть -1 - при ЛЮБОЙ ошибке, иначе 0.
Не нужно ничего выводить, писать об ошибке и тому подобном!
Итог: На Чём Сделать Акцент
-
Сигнатуры Ввода/Вывода:
- Чтение вещественных чисел с
"%lf". - Чтение целых чисел с
"%d". - Открытие для чтения
"r", для записи"w".
- Чтение вещественных чисел с
-
Работа с Памятью:
- Динамические массивы (
malloc,realloc,free), проверка наNULL. - Недопустимо возвращать указатель на локальный статический массив.
- Динамические массивы (
-
Обработка Всех Ошибок:
- При
fopen,fscanf,fprintf,fclose,malloc,realloc. - Если любой шаг проваливается —
return -1.
- При
-
Сортировка через
qsort:- Умеем писать функцию сравнения, понимаем, что такое
void *. - Знаем, как вызвать
qsort.
- Умеем писать функцию сравнения, понимаем, что такое
-
Общая Логика:
- Считываем массивы A и B (проверяем, что не пустые).
- Выполняем нужные преобразования.
- Выводим результат в
output.txt. - Любые накладки ⇒ завершаем с
-1, без вывода результата.
В завершение: Рекомендуем ознакомиться со страницей о Makefile. Правильно настроенный Makefile упрощает сборку проекта, автоматизирует проверку и экономит время при отладке.