Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Подбельский Фомин_Программирование на языке СИ_...doc
Скачиваний:
356
Добавлен:
10.08.2019
Размер:
53.81 Mб
Скачать

"Матрица" со строками разной длины.

"Матрица" со строками разной длины. Массив в языке Си должен иметь элементы одного типа и, естественно, одного размера. В ряде случаев возникает необходимость обрабатывать, подобно элементам массива, объекты разного размера. Например, попытка оформить в виде двумерного массива строки чисел с разным количеством числовых значений при обычном подходе потребует определить двумерный массив с максимально допустимыми размерами. Наличие более коротких строк не может уменьшить общих размеров массива - излишние требования к памяти налицо. Использование массивов указателей и средств динамического выделения памяти позволяет обойти указанные затруднения и более рационально распределить память. Для иллюстрации этих возможностей рассмотрим следующую задачу, очень схожую с задачей, рассмотренной ранее.

Необходимо ввести и распечатать в обратном порядке набор строк числовых значений. Количество строк в наборе вводится в начале работы программы, а длина каждой строки (т.е. количество чисел - элементов в ней) вводится перед каждой последовательностью числовых значений элементов строки.

Программа для решения задачи может быть такой:

Результаты выполнения программы (Free BSD UNIX):

Приведенным результатам выполнения программы соответствует рис. 4.6, где условно изображены все массивы, динамически формируемые в процессе выполнения программы.

В программе использованы:

line - указатель на массив указателей типа double *, каждый из которых, т.е. line[i], адресует динамически выделяемый участок памяти длиной в m[i] элементов типа double.

m - указатель на массив целых (int), значение каждого элемента равно длине массива, на который указывает line[i].

Рис. 4.6. Схема "матрицы" со строками разной длины для случая: число строк n = 5, количество элементов в строках: 4, 3,1,4, 2

Для иллюстрации разных функций выделения памяти в программе использованы calloc( ) и malloc( ). Различие между ними заключается в количестве и смысле параметров (см. табл. 4.1), а также в том, что функция calloc( ) обнуляет содержимое выделенного блока памяти.

При выходе из программы все блоки динамически выделяемой памяти рекомендуется явным образом освобождать. Для этих целей используется несколько вызовов функции free( ). В цикле по i после печати очередной строки функция free (line[i]) освобождает участок памяти, адресуемой указателем line[i]. После окончания цикла освобождаются блоки, выделенные для массива указателей free(line) и массива целых free(m).

4.3. Символьная информация и строки

Для представления текстовой информации в языке Си используются символы (константы), символьные переменные и строки (строковые константы), для которых в языке Си не введено отдельного типа в отличие от некоторых других языков программирования.

Символьные константы были рассмотрены в главе 1. Для символьных данных введен базовый тип char. Описание символьных переменных имеет вид:

char список_имен_переменных;

Например:

Ввод-вывод символьных данных.

Ввод-вывод символьных данных. Для ввода и вывода символьных значений в форматных строках библиотечных функций printf( ) и scanf( ) используется спецификация преобразования %с. Некоторые особенности работы с символьными данными уже рассматривались выше. Смотрите, например, разные способы "инвертирования" массива символов в §4.2. Продолжая эту тему, рассмотрим следующую задачу.

Ввести предложение, слова в котором разделены пробелами и в конце которого стоит точка Удалить повторяющиеся пробелы между отдельными словами (оставить по одному пробелу), вывести отредактированное предложение на экран.

Текст программы:

В программе две символьные переменные: z - для чтения очередного символа из - для хранения предыдущего. В заголовке цикла переменные z и s получают значения "пробел". Очередной символ вводится как значение переменной z, и пара z, s анализируется. Если хотя бы один из символов значений пары отличен от пробела, то значение z печатается. В заголовке цикла z сравнивается с символом "точка" и при несовпадении запоминается как значение s. Далее цикл повторяется до появления на входе точки, причем появление двух пробелов (z и s) приводит к пропуску оператора печати.

Пример работы программы:

Помимо scanf( ) и printf( ) для ввода и вывода символов в библиотеке предусмотрены специальные функции обмена:

getchar( ) - функция без параметров. Позволяет читать из входного потока (обычно с клавиатуры) по одному символу за обращение. Как и при использовании функции scanf( ), чтение вводимых данных начинается после нажатия клавиши <Enter>. Это дает возможность исправлять вводимую информацию (стирая последние введенные символы с помощью клавиши <Backspace>) до начала ее чтения программой;

putchar(X) - выводит символьное значение X в стандартный выходной поток (обычно на экран дисплея).

Проиллюстрируем применение этих функций на следующей задаче: "Ввести предложение, в конце которого стоит точка, и подсчитать общее количество символов, отличных от пробела (не считая точки)".

В заголовке цикла for выражение z=getchar( ) заключено в скобки, так как операция присваивания (см. табл. 1.4) имеет более низкий ранг, чем операции сравнения. Если скобки опустить, то последовательность операций будет такой: функция getchar( ) введет значение символа и выполнит его сравнение с символом '.'. Результат сравнения присвоится переменной z. По смыслу же необходимо введенный символ присвоить переменной z и сравнить его с точкой.

Результат выполнения программы: