- •«Алгоритмические языки и программирование»
- •Часть 1
- •Часть 1. «Язык программирования с» (опорний конспект лекций).
- •Содержание
- •6. Понятие о препроцессоре языка Си 25
- •7. Операторы языка Си и приемы программирования 26
- •1.Правила записи программы на языке Си
- •2.Идентификаторы языка Си
- •3.Понятие о типах данных.
- •3.1.Основные типы данных языка Си
- •3.2.Правила записи констант различных типов
- •3.3.Беззнаковый тип для целых данных
- •3.4.Символьные строки
- •4.Понятие функции
- •4.1.Стандартная функция printf
- •4.2.Стандартная функция scanf
- •5.Операции и выражения
- •5.1.Простейшие арифметические операции
- •5.2.Операция присваивания
- •5.3.Оператор присваивания
- •5.4.Использование в выражениях операндов разных типов
- •5.5.Операции преобразования типов
- •5.6.Стандартные математические функции
- •5.7.Простейшие функции, определяемые программистом
- •5.8.Дополнительные арифметические операции
- •5.9.Дополнительные операции присваивания
- •5.10.Операции отношения
- •5.11.Логические операции
- •5.12.Операция определения размера данных
- •5.13.Приоритеты операций
- •6.Понятие о препроцессоре языка Си
- •7.Операторы языка Си и приемы программирования
- •7.1.Оператор цикла while
- •7.2.Условный оператор и условная операция
- •7.3.Некоторые приемы программирования
- •7.4.Оператор прерывания цикла
- •7.5.Оператор продолжения цикла
- •7.6.Пример организации простейшего меню
- •7.7.Множественный выбор. Оператор переключения
- •7.8.Оператор цикла do-while.
- •7.9.Перечисления
- •7.10.Пример организации светового меню
- •8.Массивы. Адресная арифметика языка Си
- •8.1.Описание массива
- •8.2.Ввод-вывод массива
- •8.3.Инициализация массива
- •8.4.Программа вычисления длины строки символов
- •8.5.Двумерные массивы (массивы массивов)
- •8.6.Адресная арифметика языка Си
- •8.7.Указатели и одномерные массивы
- •8.8.Указатели и двумерные массивы
- •8.9.Указатели и функции
- •8.10.Оператор typedef
- •9.Дополнительные сведения о функциях
- •9.1.Области видимости и глобальные данные
- •9.2.Время жизни переменных и классы памяти языка Си
- •9.3.Передача аргументов в функцию
- •9.4.Возврат значений из функций
- •10.Работа с динамической памятью
- •10.1.Стандартные функции управления динамической памятью
- •10.2.Пример использования динамической памяти
- •10.3.Особенности работы с двумерными массивами
- •10.3.1.Пересчет индексов вручную
- •10.3.2.Массивы с постоянной длиной строки
- •10.3.3.Общий случай двумерного массива
- •10.4.Особенности работы с массивами большого размера
- •11.Модульное программирование в системе Turbo c
- •11.1.Обеспечение корректной стыковки модулей
- •11.2.Создание библиотек функций
- •12.Некоторые библиотечные функции языка Си
- •12.1.Функции консольного ввода/вывода (уникальны для tc)
- •12.2.Функции обработки строк.
- •12.3.Функции распознавания вида символа
- •12.4.Функции преобразования данных
10.4.Особенности работы с массивами большого размера
Массивами большого размера будем называть такие массивы, которые не помещаются в сегменте памяти.
Для больших двумерных массивов вариантом решения проблемы может служить предложенная в предыдущем разделе схема массива в виде вектора указателей на строки.
Если эта схема неприемлема или если массив одномерный, то можно воспользоваться специальным атрибутом указателя huge, который имеется у всех компиляторов, ориентированных на IBM PC.
Следует иметь в виду, что использование модели Large или указателей типа far недостаточно для корректной работы с большими массивами. Это происходит потому, что, во-первых, при выполнении действий над far указателями их сегментная часть не меняется, во-вторых, описанные выше функции выделения памяти не могут выделить память больше одного сегмента.
При работе с массивами большого размера, соответствующий указатель должен описываться с ключевым словом huge, даже в модели памяти Huge (указатели по умолчанию - far), например:
double huge *A;
при этом обеспечивается автоматическая нормализация указателя при переходе от сегмента к сегменту. Естественно, операция нормализации может отнимать довольно значительное время.
Для работы с большими блоками памяти используются специальные функции с префиксом far.
Функция выделения памяти:
void far *farmalloc(unsigned long size);
Выделение памяти с обнулением:
void far *farcalloc(unsigned long nitems, unsigned long size);
Изменение размера ранее выделенного блока памяти:
void far *farrealloc(void far *block, unsigned long nbytes);
Освобождение блока памяти:
void farfree(void far *block);
Получение информации о верхнем свободном блоке памяти:
unsigned long farcoreleft(void);
Работа вышеперечисленных функций совпадает с функциями рассмотренными ранее и не имеющими префикса far. В любых моделях памяти они оперируют четырехбайтовыми указателями и могут выделять блок памяти больше максимального размера сегмента. Но если требуется корректная индексация, то соответствующий указатель должен быть обязательно huge.
Следующая программа иллюстрирует использование массива размером большим максимального размера сегмента. Если в этой программе поменять атрибут huge на far, то вся адресация будет выполняться по модулю равному размеру сегмента и результат будет неверным.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <malloc.h>
void far FarMalloc( unsigned long size )
{
void far *p = farmalloc(size);
if( !p )
{ printf("Недостаточно памяти!\n"); exit(1); }
return p;
}
void main(void)
{
double huge *A;
unsigned long i, maxN;
/* Выделение максимального блока памяти */
A = (double huge *) FarMalloc( maxN = farcoreleft() );
maxN /= sizeof(double);
printf("Размер массива: %lu\n", maxN);
getch();
/* Заполняем массив */
for(i = 0; i < maxN; i++) A[i] = i;
/* Печатаем часть массива.*/
for(i = 0; i < 1000; i++)
{
printf("%10.3lf ", A[i]);
if( (i + 6) % 5 == 0 ) printf("\n");
if( (i + 121) % 120 == 0 ) { getch(); clrscr(); }
}
printf("\n");
/* Освобождение памяти */
farfree(A);
}
