- •Язык программирования Си
- •7. Понятие о препроцессоре языка Си 29
- •8. Операторы языка Си и приемы программирования 30
- •9. Массивы. Адресная арифметика языка Си 51
- •Правила записи программы на языке Си
- •Правила формального описания синтаксиса языка программирования
- •Идентификаторы языка Си
- •Понятие о типах данных.
- •Системы счисления. Представление данных в эвм.
- •Основные типы данных языка Си
- •Правила записи констант различных типов
- •Беззнаковый тип для целых данных
- •Символьные строки
- •Понятие функции
- •Стандартная функция printf
- •Стандартная функция scanf
- •Операции и выражения
- •Простейшие арифметические операции
- •Операция присваивания
- •Оператор-выражение
- •Использование в выражениях операндов разных типов
- •Операции преобразования типов
- •Стандартные математические функции
- •Простейшие функции, определяемые программистом
- •Дополнительные арифметические операции
- •Дополнительные операции присваивания
- •Битовые операции
- •Операции отношения
- •Логические операции
- •Операция определения размера данных
- •Приоритеты операций
- •Понятие о препроцессоре языка Си
- •Операторы языка Си и приемы программирования
- •Оператор цикла while
- •Условный оператор и условная операция
- •1) Короткие операторы:
- •2) Группы коротких операторов:
- •3) Длинные группы операторов:
- •Запись алгоритмов с помощью диаграмм Несси - Шнейдермана (структограмм )
- •Некоторые приемы программирования
- •Оператор прерывания цикла
- •Оператор продолжения цикла
- •Пример организации простейшего меню
- •Множественный выбор. Оператор переключения
- •Оператор цикла do-while.
- •Перечисления. Работа с клавиатурой ibm pc
- •Пример организации светового меню
- •Массивы. Адресная арифметика языка Си
- •Описание массива
- •Ввод-вывод массива
- •Инициализация массива
- •Программа вычисления длины строки символов
- •Двумерные массивы (массивы массивов)
- •Адресная арифметика языка Си
- •Указатели и одномерные массивы
- •Указатели и двумерные массивы
- •Указатели и функции
- •Оператор typedef
- •Дополнительные описания указателей для ibm pc
- •Непосредственная работа с экранной памятью
- •Дополнительные сведения о функциях
- •Области видимости и глобальные данные
- •Время жизни переменных и классы памяти языка Си
- •Передача аргументов в функцию
- •Возврат значений из функций
- •Работа с динамической памятью
- •Стандартные функции управления динамической памятью
- •Пример использования динамической памяти
- •Особенности работы с двумерными массивами
- •Пересчет индексов вручную
- •Массивы с постоянной длиной строки
- •Общий случай двумерного массива
- •Особенности работы с массивами большого размера
- •Модульное программирование в системе Turbo c
- •Обеспечение корректной стыковки модулей
- •Создание библиотек функций
- •Некоторые библиотечные функции языка Си
- •Функции консольного ввода/вывода (уникальны для tc)
- •Функции обработки строк.
- •Функции распознавания вида символа
- •Функции преобразования данных
- •Структуры языка c.
- •Описание структуры
- •1 Способ
- •2 Способ
- •Трактовка имени структуры.
- •Доступ к элементу структуры.
- •Инициализация структур.
- •Структуры и функции.
- •Поля бит в структурах.
- •Объединения.
- •Дополнительные сведения о препроцессоре языка c.
- •Условное выражение.
- •Приоритеты и направления операций.
- •Динамические данные.
- •Линейные списки.
- •Организация данных в виде стека.
- •Организация данных в виде очереди.
- •Организация данных в виде деревьев.
- •Библиотека ввода-вывода языка c.
- •Открытие потока.
- •Закрытие потока.
- •Предопределенные указатели потоков.
- •Функции ввода-вывода.
Особенности работы с массивами большого размера
Массивами большого размера будем называть такие массивы, которые не помещаются в сегменте памяти.
Для больших двумерных массивов вариантом решения проблемы может служить предложенная в предыдущем разделе схема массива в виде вектора указателей на строки.
Если эта схема неприемлема или если массив одномерный, то можно воспользоваться специальным атрибутом указателя 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.
Следующая программа иллюстрирует использование массива размером большим максимального размера сегмента:
#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);
}
Если в этой программе поменять атрибут huge на far, то вся адресация будет выполняться по модулю равному размеру сегмента и результат будет неверным.