- •Предисловие
- •Знакомство с языком C
- •Структура программы
- •Пример простой программы
- •Более сложный пример
- •Контрольные вопросы
- •Основные понятия, объявление переменных, типы данных
- •Объявление переменных
- •Примеры описаний переменных:
- •Основные типы данных
- •Производные типы.
- •Контрольные вопросы
- •Ввод/вывод с помощью функций printf() и scanf().
- •Модификаторы спецификаций преобразования используемые в функции printf()
- •Применение функции scanf()
- •Контрольные вопросы
- •Операции
- •Простейшие арифметические операции
- •Операция присваивания
- •Использование в выражениях операндов разных типов
- •Операции преобразования типов
- •Дополнительные арифметические операции
- •Дополнительные операции присваивания
- •Операции отношения
- •Логические операции
- •Приоритеты операций
- •Таблица 3. Таблица приоритетов рассмотренных выше операций
- •Контрольные вопросы
- •Операторы
- •Оператор-выражение
- •Ветвление
- •Условный оператор
- •Оператор switch
- •Оператор break
- •Циклы
- •Цикл while
- •Цикл do…while
- •Цикл for
- •Другие операторы
- •Оператор continue
- •Оператор goto
- •Оператор вызова функции
- •Контрольные вопросы
- •Обработка числовых последовательностей
- •Последовательная обработка
- •Обработка числовых последовательностей
- •Примеры
- •Контрольные вопросы
- •Последовательная обработка символьных данных
- •Символьные данные
- •Последовательная обработка символов
- •Функции getchar( ) и putchar( )
- •Контрольные вопросы
- •Обработка массивов
- •Массивы
- •Объявление массива
- •Использование и обработка массивов
- •Примеры
- •Контрольные вопросы
- •Указатели и динамические массивы
- •Указатели
- •Динамическое выделение памяти
- •Статические и динамические массивы
- •Контрольные вопросы
- •Подпрограммы
- •Описание подпрограмм
- •Параметры подпрограмм
- •Область действия переменных
- •Примеры
- •Контрольные вопросы
- •Рекурсивные функции
- •Понятие рекурсивной функции
- •Контрольные вопросы
- •Символьные строки и функции обработки строк
- •Посимвольная обработка строк
- •Пример программы
- •Контрольные вопросы
- •Структуры
- •Тип данных структура
- •Контрольные вопросы
- •Работа с файлами
- •Примеры
- •Контрольные вопросы
- •Массивы и функции как параметры
- •Указатели на функции
- •Массивы и указатели
- •Указатели и двумерные массивы
- •Пример
- •Технологии программирования
- •Структурное программирование
- •Модульное программирование
- •Объектно-ориентированное программирование
- •Компонентное программирование
- •Структурная декомпозиция задачи и разработка алгоритмов и программ методами сверху вниз и снизу вверх
- •Контрольные вопросы
- •Модульное программирование
- •Работа с графикой на языке C и модуль graphics.h
- •Типы видео мониторов и их режимы
- •Инициализация графики
- •Система координат
- •Основные графические функции
- •Функции рисования
- •Функции изменения параметров рисования
- •Шаблоны линий
- •Шаблоны закраски
- •Задание на расчетно-графическую работу
- •Порядок выполнения работы
- •Задание
- •Задание для вариантов 1-11
- •Задание для вариантов 12-20
- •Задание для вариантов 21-40
- •Пример исходных данных для вариантов 12-16
- •Задание для вариантов 41-60
- •Варианты индивидуальных заданий
- •Вариант 1
- •Вариант 2
- •Вариант 3
- •Вариант 4
- •Вариант 5
- •Вариант 6
- •Вариант 7
- •Вариант 8
- •Вариант 9
- •Вариант 10
- •Вариант 11
- •Вариант 12
- •Вариант 13
- •Вариант 14
- •Вариант 15
- •Вариант 16
- •Вариант 17
- •Вариант 18
- •Вариант 19
- •Вариант 20
- •Вариант 21
- •Вариант 22
- •Вариант 23
- •Вариант 24
- •Вариант 25
- •Вариант 26
- •Вариант 27
- •Вариант 28
- •Вариант 29
- •Вариант 30
- •Вариант 31
- •Вариант 32
- •Вариант33
- •Вариант 34
- •Вариант 35
- •Вариант 36
- •Вариант 37
- •Вариант 38
- •Вариант 39
- •Вариант 40
- •Вариант 41
- •Вариант 42
- •Вариант 43
- •Вариант 44
- •Вариант 45
- •Вариант 46
- •Вариант 47
- •Вариант 48
- •Вариант 49
- •Вариант 50
- •Вариант 51
- •Вариант 52
- •Вариант 53
- •Вариант 54
- •Вариант 55
- •Вариант 56
- •Вариант 57
- •Вариант 58
- •Вариант 59
- •Вариант 60
- •Задания на курсовую работу
- •Требования к курсовой работе
- •Этапы разработки программ
- •Содержание отчета по курсовой работе
- •Задания к курсовой работе
- •Литература
- •Функции консольного ввода/вывода
- •Функции обработки строк
- •Функции преобразования данных
Обработка массивов
Массивы
Массив - упорядоченная последовательность пронумерованных элементов одинакового типа.
Индекс - номер элемента массива. Индексы элементов массива начинаются с нуля. Элемент массива может иметь несколько индексов. Размерность массива - количество индексов каждого элемента.
Вектор - одномерный массив (один индекс).
Матрица – двумерный массив (первый индекс - номер строки, второй - номер столбца).
Объявление массива
Переменная типа массив в Turbo C описывается следующим образом:
<Имя базового типа> <Имя массива>[<Количество элементов>];
Доступ к элементам массива осуществляется с использованием имени массива и индекса элемента. Элементы массива индексируются начиная с 0, соответственно последний элемент массива имеет индекс равный <Количество элементов>-1.
Пример работы с массивом целых чисел из 3 элементов:
int A[3];
A[0]=1;
A[1]=A[0]+5;
A[2]=A[1]/2;
printf(“%d%d%d”,A[0],A[1],A[2]);
Язык Си не имеет встроенных средств для ввода-вывода массива целиком, поэтому массив вводят и выводят поэлементно с помощью циклов, как, например, в следующей программе:
#include <stdio.h> void main(void)
{
66
double a[100]; int n, i;
printf("Введите количество чисел n = "); scanf("%d", &n);
if( n>(sizeof a)/sizeof(double) )
{ printf("Слишком много элементов\n"); return; } for(i=0; i<n; i++)
{
printf("a[%d] = ", i); scanf("%lf", &a[i]);
}
/* Операторы, обрабатывающие массив */
}
Во многих случаях удобно возложить на программу подсчет числа элементов, вводимого массива, при этом ввод завершается при появлении во входном потоке признака конца данных. Таким признаком в следующей программе служит число большее 1.0e300
#include <stdio.h> void main(void)
{
double a[100], temp; int n, end;
for(end=n=0; n<(sizeof a)/sizeof(double); n++)
{
printf("a[%d] = ", n); scanf("%lf", &temp);
if( temp>=1.0e300 ) { end=1; break; } a[n] = temp;
}
if( end )
{
/* Операторы, обрабатывающие массив */
}
else
printf("Переполнение массива\n");
}
Вывод массива, содержащего большое количество элементов желательно производить в несколько строк с остановом после заполнения экрана.
Следующий фрагмент программы выводит массив строками по 5 элементов. После вывода 120 элементов программа останавливается для просмотра выдачи. Очередные 120 элементов выводятся после нажатия на любую клавишу.
for (i=0; i<n; i++)
{
printf("%10.3lf ", a[i]);
if( (i+6) % 5 == 0 ) printf("\n"); if ((i+121) % 120 == 0 )
67
{
getch();
clrscr();
}
}
Здесь стандартная функция clrscr() очищает экран.
Использование и обработка массивов
Если в условии задачи даны переменные с индексами, для них не обязательно использовать массив. Массив нужен для входных или выходных данных, если их элементы обрабатываются неоднократно или не в том порядке, в котором вводятся или выводятся. В этих случаях приходится одновременно хранить в памяти все элементы в виде массива.
В языке СИ определены только одномерные массивы, но поскольку элементом массива может быть массив, можно определить и многомерные массивы. Они формализуются списком константных выражений следующих за идентификатором массива, причем каждое константное выражение заключается в свои квадратные скобки.
Каждое константное выражение в квадратных скобках определяет число элементов по данному измерению массива, так что объявление двухмерного массива содержит два константных выражения, трехмерного - три и т.д. Отметим, что в языке СИ первый элемент массива имеет индекс равный 0.
Примеры:
int a[2][3]; /* |
представлено в виде матрицы |
|
|
||
|
|
a[0][0] |
a[0][1] a[0][2] |
*/ |
|
double b[10]; |
|
a[1][0] |
a[1][1] a[1][2] |
тип double */ |
|
/* вектор |
из 10 элементов имеющих |
||||
int w[3][3] = |
{ |
{ 2, 3, |
4 }, |
|
|
{3, 4, 8 },
{1, 0, 9 } };
Впоследнем примере объявлен массив w[3][3]. Списки, выделенные в
фигурные скобки, соответствуют строкам массива, в случае отсутствия скобок инициализация будет выполнена неправильно.
В языке СИ можно использовать сечения массива, как и в других языках высокого уровня (PL1 и т.п.), однако на использование сечений
68
накладывается ряд ограничений. Сечения формируются вследствие опускания одной или нескольких пар квадратных скобок. Пары квадратных скобок можно отбрасывать только справа налево и строго последовательно. Сечения массивов используются при организации вычислительного процесса в функциях языка СИ, разрабатываемых пользователем.
Примеры:
int s[2][3];
Если при обращении к некоторой функции написать s[0], то будет передаваться нулевая строка массива s.
int b[2][3][4];
При обращении к массиву b можно написать, например, b[1][2] и будет передаваться вектор из четырех элементов, а обращение b[1] даст двухмерный массив размером 3 на 4. Нельзя написать b[2][4], подразумевая, что передаваться будет вектор, потому что это не соответствует ограничению наложенному на использование сечений массива.
Пример объявления символьного массива.
char str[] = "объявление символьного массива";
Следует учитывать, что в символьном литерале находится на один элемент больше, так как последний из элементов является управляющей последовательностью '\0'.
Примеры
Пусть, например, в заданном массиве из 10 целых чисел надо изменить порядок следования его элементов на обратный без привлечения вспомогательного массива. Соответствующая программа приведена на примере.
Пример
/*обращение массива*/ #include <stdio.h> main()
{
int p,i=0;
static a[10]={10,11,12,13,14, 15,16,17,18,19};
while(i<10/2)
69
{
p=a[i]; a[i]=a[9-i]; a[9-i]=p; i++;
}
i=0;
while(i<10)
printf(" %d",a[i++]);
}
Следующая программа позволяет в целочисленном массиве найти разность максимального и минимального элемента. Обратите внимание, что функция fmax при первом обращении к ней дает максимальный элемент массива, а при повторном вызове - минимальный, так как предварительно мы изменили знаки элементов на противоположные. Это изменение знаков учитывается при вызове функции printf. В языке Си отсутствует возможность динамически распределять память под массивы: надо при описании массива задать точно его размер. Но если тот же массив описывается еще раз в другой программе, размеры можно не указывать, достаточно после имени сохранить пару квадратных скобок, например int x[]. Если при вызове функции в качестве аргумента ей передается имя массива, то, в отличие от простых переменных, берется фактически адрес начала этого массива. Поэтому записи fmax(a, 10) и fmax(&a[0], 10) равносильны.
Пример
/*в массиве найти разность мин. и макс. элементов */
int fmax(x,n) int x[],n;
{
int max, i=0; max=x[0]; while(i<n)
{
if(x[i]> max) max=x[i];
i++;
}
return(max);
}
#include <stdio.h> main()
{
static int a[10]=
70
{1,-2,3,-4,5,-6,7,-8,9,-13}; max=fmax(a,10);
i=0;
while(i<10)
{
a[i]=-a[i]; i++;
}
main=fmax(a,10); printf("макс-мин=%d\n",max+min);
}
В следующем пример массив описан как внешний. Функция main подсчитывает наибольшее число одинаковых идущих подряд элементов массива, определенного вне функции main.
Пример
/*макс одинаковых подряд*/ #include <stdio.h>
int a[]={5,6,6,6,4,3,3,3,3,3,8}; int n=10;
main()
{
int i,k,max; i=k=max=1; while(i<n)
{
if(a[i]==a[i-1]) k++;
else
{
if(k>max)max=k;
k=1;
}
i++;
}
printf("kmax=%d\n",(k>max)?k:max);
}
Если, как в данном примере, размер массива пропущен, то транслятор определит его длину, считая присваиваемые значения во время начальной инициализации. Условная операция (k>max)?k:max в операторе printf предусмотрена для того частного случая, когда весь массив состоит из одинаковых элементов. Приведем несколько примеров, в которых ведется обработка двумерных массивов. Но прежде одну полезную возможность языка Си. Речь идет о препроцессорном утверждении #define, позволяющем присваивать символические имена константам. В общем случае это
71
утверждение записывают так: #define строка1 строка2 (точка с запятой не ставится).
Прежде чем исходный текст программы будет передан компилятору, он обрабатывается препроцессором, который всюду в исходном тексте заменит вхождение "строка1" на "строка2". Например, строка #define max 80, записанная в начале программы, обеспечит всюду замену указанного имени max на соответствующую константу. Замена имени связана не только числами, но и текстами. А теперь вернемся к примерам. В следующей программе строится единичная матрица a[m][m], размер которой определяется с помощью конструкции #define m 5. Сам алгоритм вычисления элементов матрицы основан на возведении (i/j)*(j/i) равно единице тогда и только тогда, когда i равно j. В остальных случаях оно равно нулю.
Пример
#define M 5 #include <stdio.h> main()
{
int a[M][M]; int j,i=0; while(i<M)
{
j=1;
while(j<M)
{
a[i][j]=(i/j)*(j/i);
printf("%d",a[i][j]);
j++;
}
i++;printf("\n");
}
}
В программе определяется минимальный элемент каждой строки матрицы и выполняется обмен местами найденного и диагональю этой же строки.
Обращаем внимание на следующее обстоятельство. Если двумерный массив надо передать функции, то описание параметра в ней должно обязательно включать в себя размер строки массива, а размер столбцов
72