- •Часть 2
- •Содержание
- •1.37.18.5. Несовместимость фактического и формального параметров указателей функции……………………………33
- •1. Основы программирования на языке Си
- •1.30. Цикл, управляемый инструкцией while
- •1.31. Цикл, управляемый инструкцией do while
- •1.32. Цикл с выходом
- •1.35. Функция
- •1.33. Вложенные циклы
- •1.34. Перечисление
- •1.35.1. Назначение функции
- •1.35.2. Определение функции
- •1.35.3. Вызов функции.
- •1.35.4. Прототип функции
- •1.35.5. Способы передача параметров
- •1.35.6. Понятие о встраиваемых (inline) функциях
- •1.36. Организация модулей в языке Си
- •1.36.1. Пример организации модуля
- •1.36.2. Защита от повторного включения заголовочного файла
- •1.37. Массивы и указатели
- •1.37.1. Массивы. Общие сведения
- •1.37.1.1. Классификация массивов
- •1.37.1.2. Определение и инициализация массива
- •1.37.1.3. Операции с массивами
- •1.37.2. Указатели. Общие сведения
- •1.37.2.1. Области применения указателей
- •1.37.2.2. Классификация указателей
- •1.37.2.3. Понятие о нулевом указателе
- •1.37.2.4. Понятие о недействительном указателе
- •1.37.2.5. Определение переменной – указателя
- •1.37.2.6. Операции с указателями
- •1.37.2.6.1. Разыменование указателя. Модель переменной-указателя
- •1.37.2.6.3. Оператор присваивания
- •1.37.2.6.4. Инкремент и декремент указателя
- •1.37.2.6.5. Сложение и вычитание целого числа
- •1.37.2.6.6. Вычитание указателей
- •1.37.2.6.7. Индексирование указателей
- •1.37.2.6.8. Сравнение указателей
- •1.37.2.7. Указатели и динамическая память
- •Функция malloc
- •Функция calloc
- •Функция realloc
- •Функция free
- •1.37.3. Указатели и квалификатор const
- •1.37.4. Указатели и квалификатор restrict
- •1.37.5. Связь между указателями и массивами
- •1.37.6. Указатели – параметры функций
- •1.37.7. Массивы – параметры функций
- •1.37.8. Ошибки при работе с указателями
- •1.37.8.1. Ошибки при объявлении указателей
- •1.37.8.2. Использование неинициализированного указателя
- •1.37.8.3. Присваивание несовместимых указателей
- •1.37.8.4. Разыменование нулевого указателя
- •1.37.18.5. Несовместимость фактического и формального параметров указателей функции
- •1.37.8.6. Возврат из функции указателя на локальную переменную
- •1.37.8.7. Висячий указатель
- •1.37.8.8. Утечка памяти
- •1.37.9. Указатели на функцию
- •1.37.9.1. Выражение указатель на функцию
- •1.37.9.2. Определение указателя переменной на функцию
- •1.37.9.3. Инициализация переменной указатель на функцию
- •1.37.9.4. Операции с указателями на функцию
- •1.38.5.Строковые функции стандарта с11
- •1.38.6. Ввод и вывод строк
- •1.39. Работа со структурами
- •1.39.1. Объявление структур
- •1.39.2. Определение структуры в многомодульной программе
- •1.39.3. Инициализация структур
- •1.39.4. Обращение к полям структуры
- •1.39.5. Операции над структурами
- •1.39.6. Массивы структур
- •1.39.6.1. Объявление массивов структур
- •1.39.6.2. Идентификация элементов массива структур
- •1.40. Работа с внешними устройствами
- •1.40.1. Понятие потока
- •1.40.2. Файлы
- •1.40.2.1. Указатель файла
- •1.40.2.2 Функция fopen
- •1.40.2.9. Построковый ввод-вывод
- •1.40.3.Блоковый ввод-вывод
- •Примеры решенных задач
- •2.4. Итерационные циклы
- •2.5. Вложенные циклы
- •2.6. Работа с функциями
- •2.6.1. Преобразование программы в функцию пользователя
- •2.6.2. Функция как обобщенное решение ряда частных задач
- •2.6.3. Параметры функции или глобальные переменные
- •2.6.4. Указатели в качестве параметров функций
- •2.7. Обработка одномерных массивов
- •2.7.1. Массивы ─ входные и выходные параметры функции
- •2.7.2. Ввод массивов
- •2.7.3. Вывод нескольких массивов в виде таблицы
- •2.7.4. Создание нового массива копированием положительных элементов из исходного массива
- •2.7.5. Значения наибольшего и наименьшего элементов массивов
- •2.8. Обработка двумерных массивов
- •2.8.1. Интерфейс функций, работающих с двумерными массивами.
- •2.8.2. Создание и уничтожение двумерного динамического массива
- •2.8.3. Примеры обработки двумерных массивов
- •2.9.1. Пользовательские аналоги библиотечных функций
- •2.9.2. Копирование чисел, находящихся в строке, в числовой массив
- •2.9. Работа со строками
- •2.9.3. Подсчет количества лексем в строке
- •2.9.4. Массивы строк
- •2.10. Указатели на функцию
- •2.10.1. Использование функции qsort
- •2.10.2. Табулирование произвольной функции одного переменного. Новое решение задачи табулирования
- •2.11. Работа со структурами
- •2.11.1. Структуры, поля которых содержат указатели
- •2.11.2. Работа с массивом структур.
- •2.12. Работа с файлами
- •2.12.1. Работа с текстовыми файлами
- •2.12.2. Работа с двоичными файлами
- •2.12.2.1. Вычисление суммы чисел, содержащихся в двоичном файле.
- •2.12.2.2. Чтение числа из заданной позиции двоичного файла
- •2.12.2.3.Замена всех отрицательных чисел двоичного файла нулями
- •Литература
2.12.2. Работа с двоичными файлами
2.12.2.1. Вычисление суммы чисел, содержащихся в двоичном файле.
Постановка задачи. Дан двоичный файл, хранящий произвольное количество чисел типа double. Написать функцию, вычисляющую сумму чисел, хранящихся в файле.
Решение. Интерфейс функции. Имя функции sum_dbl_num_in_bin_file. Функция должна иметь один параметр – файловый указатель. Возвращаемое значение – вычисленная сумма. Прототип функции будет иметь вид:
double sum_dbl_num_in_bin_file(FILE* in_file);
Реализация функции. Удобно выбрать для чтения данных из файла функцию fread(), обеспечивающую чтение очередного блока чисел. Структура алгоритма − вложенные циклы. До входа во внешний цикл необходимо определить и инициализировать переменную sum, которая будет использоваться для вычисления искомой суммы. Внешний цикл должен обеспечивать чтение очередного блока чисел, а внутренний цикл − суммировать числа этого блока. В связи с тем, что размеры запрошенного и прочитанного блока могут не совпадать, следует контролировать число блоков, которое возвращает функция fread().Для этой цели в программе служит переменная n. Программный код разработанной функции приведен ниже.
#include<stdio.h> #define MSIZE 256 double sum_dbl_num_in_bin_file(FILE* in_file) { double sum = 0; double ar[MSIZE]; while(!feof(in_file)) { int n = fread(ar, sizeof(double), MSIZE, in_file); for(int i = 0; i < n; i++)
sum += ar[i]; } return sum; }
2.12.2.2. Чтение числа из заданной позиции двоичного файла
Постановка задачи. Имеется числовой двоичный файл, содержащий числа типа double. Прочитать число, находящееся в позиции num.
Решение. Интерфейс функции. Имя функции read_number_from_bin_file. Функция должна иметь два параметра: файловый указатель in и целочисленный параметр num. Возвращаемое значение – прочитанное число. Прототип функции будет иметь вид:
double read_number_from_bin_file(FILE* in, int num);
Реализация функции. В теле функции следует выполнить три действия. Вычислить индекс позиции, в которой находится число, подлежащее чтению, переместиться к этой позиции и прочитать число, которое там находится. Реализация функции приведена ниже.
double read_number_from_bin_file(FILE* in, int num) { //Вычислим начальную позицию n-го числа long pos =(long)(num – 1) * sizeof(double); //Переместимся к началу n-го числа fseek(in, pos, SEEK_SET); //Читаем n-ое число double value;
fread(&value, sizeof(double), 1, in); return value;
}
2.12.2.3.Замена всех отрицательных чисел двоичного файла нулями
Постановка задачи. Имеется числовой двоичный файл, содержащий числа типа double. Заменить все вхождения отрицательных чисел нулями. Решение задачи оформить в виде функции.
Интерфейс функции. Выберем для функции «говорящее» имя – replace_neg_num_with_zeros. Функция будет предназначена для модификации файла. Такая функция может не иметь возвращаемого значения. Функция должна иметь один формальный параметр − файловый указатель, в качестве имени которого выберем идентификатор in_out. В заключение разработки интерфейса приведем заголовок разрабатываемой функции:
void replace_neg_num_with_zeros(FILE* in_out)
Реализация функции. Особенностью данной функции является работа в режиме модификации (режим чтения-записи). Заметим, что при открытии файла в таком режиме в функции fopen() следует указывать во втором ее параметре знак + (b+). В этом случае поток можно использовать как для ввода, так и для вывода. Однако операции ввода и вывода не могут следовать непосредственно друг за другом. Они должны быть отделены вызовом одной из следующих функций: fsetpos(), fseek(), rewind или fflush() [7, стр. 377]. В реализации, приведенной ниже, для этой цели используется функция fseek(). В теле функции следует организовать итерационный цикл. Требуемые действия отражены в комментариях.
void replace_neg_num_with_zeros(FILE* in_out) { int n;//n – оличество прочитанных чисел double x; double zero = 0;//Для замены отрицательного числа нулем while(!feof(in_out)) { // Читаем очередное число n = fread(&x, sizeof(double), 1, in_out); if(0 == n) //Достигнут конец файла continue;//Передаем управление инструкции while if(x < 0)//Требуется ли замена очередного числа? { //Замена нужна. Вернемся к месту замены fseek(in_out, -(long)sizeof(double), SEEK_CUR); //Выполним замену fwrite(&zero, sizeof(double), 1, in_out); //Подготовимся к смене режима записи на режим чтения fseek(in_out, 0L, SEEK_CUR); } } }
