- •Часть 2
- •Содержание
- •1.37.18.5. Несовместимость фактического и формального параметров указателей функции……………………………33
- •1. Основы программирования на языке Си
- •1.30. Цикл, управляемый инструкцией while
- •1.31. Цикл, управляемый инструкцией do while
- •1.32. Цикл с выходом
- •1.33. Вложенные циклы
- •1.34. Перечисление
- •1.35. Функция
- •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. Работа со строками
- •2.9.1. Пользовательские аналоги библиотечных функций
- •2.9.2. Копирование чисел, находящихся в строке, в числовой массив
- •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.Замена всех отрицательных чисел двоичного файла нулями
- •Литература
1.38.5.Строковые функции стандарта с11
Функции, традиционно используемые в языке Си для работы со строками, не проверяют размер массива, в котором хранится строка. Это приводит к возникновению ошибок в работе программы и к понижению ее безопасности (к повышению опасности заражения компьютерным вирусом).
Приложение К стандарта С11 содержит описания альтернативных функций, которые обеспечивают более безопасное программирование. Эти функции проверяют достаточно ли велик выходной буфер для ожидаемого результата, и возвращают признак ошибки, если это не имеет места. Например, в этом приложении определены функции strcpy_s(), strcat_s(), strncat_s(), которые предназначены для замены функций strcpy(), strcat() и strncat().
1.38.6. Ввод и вывод строк
Наиболее просто организовать вывод строк. Для этого можно использовать функции puts() и printf().
Функция puts.
int puts(const char* str);
Функция puts() отображает на экране дисплея свой строковый аргумент, а затем переводит курсор на новую строку.
Функция printf.
Строки могут выводиться с помощью библиотечной функции printf(). Рекомендуется в целях обеспечения безопасности всегда использовать спецификацию преобразования типа s [8].
Примеры.
printf(“%s”, “Hello, world”);
printf(“%5s%10s%10s”, “НОМЕР”, “АРГУМЕНТ”, “ФУНКЦИЯ”);
Не рекомендуется выводить строки без указания спецификации преобразования. Например,
printf(“Hello, world”);
Перейдем к рассмотрению средств ввода строк.
Имеется ряд библиотечных функций, с помощью которых можно выполнять ввод строк:
• scanf(),
• gets(),
• fgets().
Начнем рассмотрение с функции scanf().
Особенность функции scanf() состоит в том, что с её помощью нельзя вводить строки, содержащие пробелы. Эта функция может использоваться только для ввода отдельных слов.
Пример.
#define MLEN 129 #include<stdio.h> int main(void) { char st[MLEN]; prinf(“%s”,“Enter a string: ”); scanf(“%s”, st); printf(“%s”, st); /* */ return 0; }
Протокол работы с программой, приведенной выше, будет иметь следующий вид:
Enter a string: Hello, world<Enter>
Hello,
Выше с помощью подчёркивания выделен ввод пользователя. Из протокола видно, что введенным оказалось только первое слово (Hello,).
Другой особенностью функции scanf() является возможность ограничения количества вводимых символов. Для этого в спецификации преобразования функции следует использовать дополнительный целочисленный параметр, как это показано на примере ниже:
#define MLEN 129 #include<stdio.h> int main(void) { char st[MLEN]; prinf(“Enter a string: ”); scanf(“%5s”, st); printf(“%s”, st); /* */ return 0; }
Протокол работы с программой имеет следующий вид:
Enter a string: 1234567890<Enter>
12345
В этом примере спецификация преобразования содержит дополнительный параметр в виде числового литерала (5). В рассматриваемом случае воспринимается не более 5 вводимых символов.
Функция gets.
Прототип этой функции имеет следующий вид:
char* gets(char* s);
Функция читает символы, вводимые с клавиатуры, в символьный массив s. Чтение заканчивается, когда встретится либо символ “новая строка” (\n), либо конец файла. После записи последнего прочитанного символа в массив s добавляется нуль-символ. Если встречается символ “новая строка”, он отбрасывается. При успешном завершении функция возвращает указатель s. При достижении конца файла, когда не прочитан еще ни один символ, функция вернет значение NULL, а содержимое массива, на который установлен указатель s, останется без изменения. При обнаружении ошибки чтения функция вернет NULL, а содержимое массива считается не определенным.
Приведем пример применения функции gets().
#include<stdio.h>
#include<string.h> #define MAX 81 int main(void) {
char name[MAX]; char out[MAX] = “Привет, Вам ”; puts(“Введите Ваше имя”); gets(name); printf(“Привет Вам, %s”, name); puts(out);
return 0;
} Протокол работы с программой.
Введите Ваше имя Иван Привет Вам, Иван
Существенным недостатком функции gets() является возможность переполнения массива, на который установлен указатель s. Поэтому функцию gets() не следует использовать в коммерческих приложениях. Для этих целей можно воспользоваться функцией fgets(). В разделе 1.40.2.8 приводится один из возможных вариантов организации пользовательской функции для ввода с клавиатуры с использованием функции fgets() (см. раздел 1.40.2.8).
