
- •Федеральное агентство по образованию
- •Краткая история языка с
- •Особенности и основные понятия языка Си
- •Структура программы
- •Типы данных
- •Классификация типов данных
- •Вещественные
- •Логический
- •Диапазоны представления данных
- •Объявление переменных
- •Константы в языке Си
- •Операции языка Си. Приоритет операций
- •Операция присваивания
- •Арифметические операции
- •Операции отношения
- •Логические операции
- •Поразрядные операции
- •Операцияsizeof
- •Операция выбора по условию
- •Операция запятая
- •Приведение типов Неявное преобразование типов
- •Явное преобразование типов
- •Основные средства ввода-вывода на Си Понятие потока
- •Стандартные потоки
- •Функции потокового ввода-вывода
- •Функции ввода
- •Ввод символов
- •Ввод строк
- •Форматированный ввод
- •Операторы языка Си
- •Оператор if
- •Оператор switch
- •Оператор while
- •Оператор do while
- •Оператор for
- •Оператор break
- •Оператор continue
- •Функции вывода на экран
- •Вывод символов
- •Функция вывода строк puts()
- •Форматированный вывод
- •Указатели в языке Си
- •Адресная арифметика
- •Массивы
- •Функции в языке с
- •Прототипы функций
- •Указатели типа void
- •Функции, возвращающие указатели
- •Встраиваемые функции
- •Рекурсивные функции
- •Функции с переменным числом аргументов
- •Аргументы функции main()
- •Область действия и область видимости
- •Локальные переменные
- •Локальные переменные в функции Main()
- •Глобальные переменные
- •Классы памяти
- •Указатели на указатели
- •Указатели и многомерные массивы
- •Массивы указателей
- •Указатели на функции
- •Операции над строками символов Определение длины строки
- •Копирование строк
- •Поиск в строках
- •Преобразования символов в строках
- •Другие функции для работы со строками
- •Преобразования строк в числа
- •Преобразования чисел в строки
- •Функции анализа символов
- •Распределение памяти
- •Манипулирование блоками памяти
- •Типы, определяемые пользователем
- •Перечислимый тип
- •Структуры
- •Сложные структуры
- •Битовые поля в структурах
- •Объединения
- •Работа с файлами Связь между потоками и файлами
- •Типы дисковых файлов
- •Открытие файла
- •Запись и чтение данных
- •Форматированный ввод-вывод Форматированный вывод
- •Int fprintf (file *fp, char *fmt, ...);
- •Форматированный ввод
- •Символьный ввод
- •Символьный вывод
- •Блочный ввод-вывод
- •Закрытие файла
- •Директивы препроцессора
- •Директива #include
- •Директива #define
- •Директивы условной компиляции
- •Директива #undef
- •Предопределенные макросы
- •69 Лекции по курсу «Языки программирования» Часть III
Функции анализа символов
Заголовочный файл ctype.h содержит прототипы ряда функций, которые анализируют символы и возвращают TRUE или FALSE в зависимости от того, удовлетворяют ли те определенным условиям. Например, с их помощью можно узнать, является ли символ буквой, цифрой и т.п. Эти функции с именами типа isxxxx() на самом деде представляют собой макросы, определенные в файле ctype.h.
Макросы isxxxx() имеют идентичные прототипы: int isxxxx(int ch);
В этом прототипе аргумент ch представляет собой анализируемый символ. Каждый макрос возвращает значение TRUE (не ноль), если его условие удовлетворяется, и FALSE (ноль, если оно не удовлетворяется. В таблице приведен полный список макросов isxxxx().
Макрос |
Выполняемая операция |
isalnum() |
Возвращает TRUE, если ch — буква или цифра |
isalpha() |
Возвращает TRUE, если ch — буква |
isblank() |
Возвращает TRUE, если ch — пустой символ |
iscntrl() |
Возвращает TRUE, если ch — управляющий символ |
isdigit() |
Возвращает TRUE, если ch — цифра |
isgraph() |
Возвращает TRUE, если ch — отображаемый символ (не пробел) |
islower{) |
Возвращает TRUE, если ch — буква в нижнем регистре |
isprint() |
Возвращает TRUE, если ch — отображаемый символ (в том числе пробел) |
ispunct() |
Возвращает TRUE, если ch — знак препинания |
isspace() |
Возвращает TRUE, если ch— символ свободного пространства (пробел, табуляция, вертикальная табуляция, перевод строки, прогон страницы, возврат каретки) |
isupper() |
Возвращает TRUE, если ch — буква в верхнем регистре |
isxdigit() |
Возвращает TRUE, если ch — шестнадцатеричная цифра (0-9, a-f, A-F) |
Не используйте функций, не принадлежащих к стандарту ANSI, если собираетесь переносить программу на другие платформы.
Изменение регистра символов по стандарту ANSI
Хотя функции strlwr() и strupr() прекрасно справляются с изменением регистра символов в строках на нижний или верхний, они не определены в стандарте ANSI. Все же и этот стандарт предусматривает два макроса для преобразования символов в верхний или нижний регистр. Наряду с макросами isxxxx() существуют еще два стандартных изменения регистра символов: toupper() и tolower().
Пример
char buf[80];
int ctr;
gets(buf );
for ( ctr = 0; ctr< strlen(buf); ctr++)
{printf("%c", tolower(buf[ctr])); }
printf("\n");
Распределение памяти
Библиотека Си содержит функции для распределения памяти непосредственно в ходе выполнения программы. Этот процесс называется динамическим распределением памяти. Нередко именно этот способ оказывается более выигрышным по сравнению с явным распределением памяти в коде программы путем объявления переменных, структур и массивов - называемым также статическим распределением памяти. Для статического распределения памяти необходимо знать, сколько памяти потребуется для ее объектов, еще при написании программы. А вот динамическое распределение позволяет программе оперативно реагировать на запросы к памяти в ходе ее выполнения. Для работы всех функций динамического распределения памяти необходимо подключить заголовочный файл stdlib.h. Некоторые компиляторы требуют также файла malloc.h. Все функции распределения памяти возвращают указатель типа void. А следовательно указатель типа void необходимо сначала привести к определенному типу, а потом уже использовать его для обращения по адресу.
Распределение памяти с помощью функции malloc()
Синтаксис:
#include <stdlib.h> void *malloc(size_t размер); |
Тип аргумента size_t определен в заголовочном файле stdlib.h как unsigned. Функция malloc () выделяет в памяти блок из размер байт и возвращает указатель на его первый байт Функция возвращает NULL (нулевой указатель), если запрашиваемый объем памяти выделить.
При любой попытке распределения памяти всегда следует проверять возвращаемое значение, даже если запрашиваемый объем достаточно мал.
Пример 1
#include <stdlib.h>
#include <stdio.h>
main()
{
/* выделение памяти для 100-символьной строки */
char *str;
str = (char *) malloc(100);
if (str == NULL)
{
printf( "Нет памяти\n" );
exit(l);
}
printf( "Память вывелена\n" );
}
Пример 2 /* выделение памяти для массива из 50 целых чисел */ int *masint; masint = (int *) malloc(50 * sizeof (int)); |
Пример 3 /* выделение памяти для массива 10 вещественных чисел */ float *masfloat; masfloat = (float *) malloc(10 *sizeof(float)); |
Работа с функцией malloc()
Функцию malloc() можно использовать для размещения в памяти одиночного символа (char). Вначале следует объявить указатель на char:
char *ptr;
Затем нужно вызвать функцию malloc() и передать в нее размер требуемого блока памяти. Переменная типа char занимает один байт памяти — именно такой блок нам и нужен. Возвращаемое функцией malloc() значение следует присвоить объявленному указателю:
ptr = malloc(l);
Этот оператор выделяет блок памяти размером один байт и присваивает его адрес указателю ptr. В отличие от переменных, объявленных в программе, этот байт не имеет имени. К нему можно обратиться только через указатель. Например, для занесения в него символа ' x' используется следующий оператор:
*ptr = 'х';
Память для строки с помощью функции malloc() выделяется почти так же, как и для отдельной переменной типа char. Основное различие состоит в том, что необходимо знать длину строки. Эта длина зависит от нужд программы. Пусть необходимо выделить место в памяти для строки из 99 символов плюс завершающий 1 нулевой символ — всего 100. Для этого вначале объявляется указатель на char, а затем вызывается malloc ():
char *ptr;
ptr = malloc(100); или ptr = malloc(100 * sizeof(char));
Теперь ptr указывает на выделенный блок длиной 100 байт, который можно использовать для хранения строки и всевозможных операций с ней. Этот блок обладает точно такими же свойствами, как и непосредственно объявленный в тексте программы массив:
char ptr[100];
Статическое выделение памяти:
*message = "Строка символов";
При выполнении этого оператора строка "Строка символов" вместе с ее завершающим нулевым символом помещается в память, и указатель message инициализируется таким образом, чтобы указывать на первый символ этой строки. В этом случае выделением памяти «озабочен» компилятор. После такого объявления message становится указателем на строку,- и с ним можно работать.
Предыдущее объявление с инициализацией эквивалентно следующему:
char message[] = "Строка символов";
В данном случае обе записи *message и message [] взаимозаменяемы и означают одной и же: "указатель на...".
Этот способ распределения памяти для строк хорош, если длина строки известна заранее при написании программы. Если строка message окажется длинее, то результат работы программы будет непредсказуем.
Пример выделения памяти для текстовых строк с помощью функции malloc()
#include <stdio.h>
#include <stdlib.h>
char count, *ptr, *p;
int main( void )
{
/* Выделение блока из 35 байт. Проверка правильности. */
/* Библиотечная функция exit() завершает программу. */
ptr = malloc(35 * sizeol(char));
if (ptr == NULL)
{
puts("Ошибка: недостаточно памяти");
return 1;
}
/* Заполнение строки значениями от 65 до 90, */
/* т.е. кодами ASCII для букв A-Z. */
/* р - указатель для прохождения строки. */
/* Перед началом цикла ptr указывает на начало строки. */
р = ptr;
for (count =65; count < 91 ; count++)
*p++ = count;
/* Добавление завершающего нулевого символа. */
*р = '\0';
/* Отображение строки на экране. */
puts(ptr);
free(ptr);
return 0;
}
Примечание: Функция free() в высвобождает ранее выделенный блок памяти, на который указывает ptr, и возвращает его в распоряжение системы.
Распределение памяти с помощью функции calloc()
Функция calloc() также предназначена для распределения памяти. Однако вместо того, чтобы выделять группы байт для размещения данных, как это делает malloc(), функция calloc() размещает в памяти группу объектов. Эта функция имеет следующий прототип:
void *calloc(size_t num, size_t size);
Тип size_t — синоним типа unsigned.
Аргумент num равен количеству объектов для размещения в памяти, a
size — это размер каждого объекта в байтах.
Если размещение прошло успешно, вся выделенная память очищается ( заполняется нулями), и функция возвращает указатель на первый байт. Если num или size равны 0 или же распределение памяти потерпело неудачу, функция возвращает NULL.
Пример.
Демонстрация функции calloc(). */
#include <stdlib.h>
#include <stdio.h>
main( void )
{
unsigned long num;
int *ptr;
printf("Количество объектов : ");
scanf("%ld", &num);
ptr = (int*)calloc(num, sizeof(long long));
if (ptr != NULL)
puts("Память выделена");
else
puts("Ошибка");}
Распределение дополнительной памяти с помощью функции realloc()
Функция realloc() изменяет размер блока памяти, ранее созданного с использованием функции malloc() или calloc(). Функция имеет следующий прототип:
void *realloc(void *ptr, size_t size);
Аргумент ptr указывает на исходный блок памяти. Новый размер в байтах указывается параметром size. При вызове realloc() возможен один из следующих исходов.
Если для расширения блока, находящегося по адресу ptr, имеется достаточно памяти, то производится ее выделение в нужном количестве, и функция возвращает ptr.
Если памяти недостаточно для того, чтобы расширить существующий блок по его текущему адресу, то создается новый блок размером size, и имеющиеся данные копируются из старого блока в начало нового. Старый блок освобождается, и функция возвращает указатель на новый блок памяти.
Если аргумент ptr равен NULL, то функция действует точно так же, как malloc(), выделяя блок памяти размером size байт и возвращая указатель на него.
Если аргумент size равен 0, блок памяти по адресу ptr освобождается, и функция возвращает NULL.
Если для перераспределения недостаточно памяти (т.е. нельзя ни расширить старый блок, ни разместить новый), функция возвращает NULL, и исходный блок остается неизменным.