SlideShare a Scribd company logo
1 of 174
ОСНОВЫ ПРОГРАММИРОВАНИЯ НА
ЯЗЫКЕ C
(Программирование на языке
высокого уровня, часть 2)
Комплексное учебное пособие
Пример простой программы
/* Сложение двух целых чисел */
#include <stdio.h>
main ()
{ int a, b;
/* объявление целочисленных переменных а и b */
printf ("Задайте два числа: "); /* вывод сообщения
*/
scanf ("%d %d", &a, &b); /* ввод значений а и b
*/
printf ("%d + %d = %dn", a, b, a+b); /* вывод результата
*/
return 0;
}
Более сложный пример
#include <stdio.h>
#include <stdlib.h>
#define PROMPT ':'
main()
{
float a,b,rez;
char oper;
while(putch(PROMPT),scanf("%f%c%f",&a,&oper,&b)!=EOF)
{
switch (oper)
{
case '+': rez=a+b; break;
case '-': rez=a-b; break;
case '*': rez=a*b; break;
case '/': rez=a/b; break;
default:
printf("Ошибка!n");
exit(1);
}
printf("Результат:%fn",rez)
}
}
Объявление переменных и
основные типы данных
Имя (идентификатор) - это
последовательность латинских букв и
цифр, начинающаяся с буквы. Можно
использовать в имени символы
подчеркивания вместо пробелов, когда
имя состоит из нескольких слов.
Примеры описаний
переменных:
float
x,y,z;
*/
double
x1,x2;
точности*/
char
simv;
int
i,j;
long
summa;
short
k1,k2;
unsigned count;
число */

/* вещественные числа
/* вещ. числа двойной
/*
/*
/*
/*
/*

символ */
целые числа */
длинное целое */
короткие целые */
беззнаковое целое
(неотрицательное)
Ввод/вывод с помощью функций
printf() и scanf().
Формат

Тип вводимой информации

%d

Десятичное целое число

%c

Один символ

%s

Строка символов

%e

Число с плавающей точкой, экспоненциальная
запись

%f

Число с плавающей точкой, десятичная запись

%g

Используется вместо записей %f или %e,если он
короче

%u

Десятичное целое без знака

%o

Восьмеричное целое без знака

%x

Шестнадцатиричное целое число без знака
Пример
pi=3.14159;
e=2.718282;
printf(“число pi=%f ; число e=
%f;n”,pi,e);
/*результат следующий */
число pi=3.14159; число e=2.71828;
или
printf(“число p=%f; число e=%f; число
pi+e=%f! n”,pi,e,pi+e);
/*результат */
число pi=3.14159; число e=2.71828 ; число
pi+e=5.85987!
Модификаторы спецификаций
преобразования используемые в
функции printf()
К модификаторам относятся:
1)Знак минус - при этом аргумент будет печататься с
левой позиции поля заданной ширины. Обычно печать
аргумента оканчивается в самой правой позиции поля.
Пример %-10в.
2)Строка цифр – задает минимальную ширину поля.
При этом, если информация не помещается в
указанную ширину поля, то ширина поля увеличивается
до необходимых размеров.
3)Строка цифр – определяет точность: для типов
данных с плавающей точкой – число печатаемых цифр
справа от десятичной точки; для символьных строк –
максимальное число печатаемых символов. Пример
%4.2f – две десятичные цифры для поля шириной в
четыре символа.
Влияние модификаторов преобразования
на печать целого числа:
main()
{
printf(“/%d/n”,625);
printf(“/%2d/n”,625);
printf(“/%10d/n”,625);
printf(“/%-10d/n”,625);
}
Печать будет следующей:
/625/
/625/
/
625/
/625
/
Для чисел с плавающей точкой:
main()
{
printf(“/%f/n”,1234.56);
printf(“/e/n”,1234.56);
printf(“/4.2f/n”,1234.56);
printf(“/%3.1f/n”,1234.56);
printf(“/%10.3f/n”,1234.56);
printf(“/%10.3e/n”,1234.56);
}
Результат будет следующим:
/1234.560059/
/1.234560Е+03/
/1234.56/
/1234.6/
/ 1234.560/
/ 1.234Е+03/
Рассмотрим варианты строк:
# define const “КГТУ – пуп земли!”
/*здесь 15 символов, включая пробелы*/
main()
{
printf(“/%2s/n”,const);
printf(“/%17.s/n”,const);
printf(“%20.4s/n”,const);
printf(“%-20.4/n”,const);
}
/КГТУ – пуп земли!/
/ КГТУ – пуп земли!/
/
КГТУ/
/КГТУ
/
Функцию printf() можно использовать для
преобразования данных.
Пример
printf(“%dn”,625);
printf(“%on”,625);
printf(“%xn”,625);
printf(“%dn”,-625);
printf(“%un”,-625);
54911(=65536-625)

625
1161
271
-625
Применение функции scanf()
Рассмотрим пример:
main()
{
int vozrast;
float rost;
char sobaka[20];
printf(“Укажите ваш возраст, рост в метрах и
любимую породу собак”);
scanf(“%d%f”, &vozrast,&rost);
scanf(“%s”,sobaka); /*отсутствует &*/
printf(“%d %4.2f %sn”,vosrast,rost,sobaka);
}
Ввод
25 1.72
/*Можно вводить в каждой строке, т.е.25*/
ризеншнауцер
/*
1.72*/
/*
ризеншнауцер*/
Печать
25 1.72 ризеншнауцер
Операции
Под операцией понимают некоторое действие,
которое может быть выполнено над одним или
несколькими операндами для получения
результата. Операции и операнды могут
объединяться в выражение. Каждое
выражение вычисляется с учетом особенностей
составляющих его операций и их
приоритетов. В результате вычисляется
значение выражения.
Простейшие арифметические
операции
Примеры выражений с арифметическими
операциями:
a + b%c
(a + b)/3*5
Операция присваивания
Пример:
ab = ( c = d+5 ) * 6
Оператор-выражение
Пример:
ab = ( c = d + 5 ) * 6;

/* это оператор */
Использование в выражениях
операндов разных типов
Пример:
int a, c;
float d, e;
e = d*(c+e);
преобразовано в
a = 'A' + 20;
преобразовано в

/* c будет
float */
/* 'A' будет
int */
Операции преобразования типов
В некоторых случаях правила преобразования
типов не позволяют получить верный
результат, например:
int a, b;
float c;
a = 7; b = 14;
c = a/b;
/* результат 0 */
Для получения правильного результата можно
поступить так
c = a; c = c/b;
Явное преобразование типов:
(<имя_типа>) <выражение>
имя_типа - название любого типа, в том
числе и заданного программистом.
Для нашего примера применение
операции преобразования типа будет
выглядеть так:
c = (float)a / (float)b;
Дополнительные арифметические
операции
a = a + 1; эквивалентно a++; или ++a;
a = 4;
b = ( a++ ) * 5; /* здесь b = 20 */
a = 4;
b = ( ++ a ) * 5; /* здесь b = 25 */
Дополнительные операции
присваивания
a = a + b;
a = a - b;
a = a * b;
a = a / b;
Дополнительные операторы присваивания:
a += b;
a -= b;
a *= b;
a /= b;
a %= b;
Операции отношения
>
больше,
<
меньше,
>= больше или равно,
<= меньше или равно,
== равно,
!=
не равно.
Например:
int a,b;
a = 5;
b = ( a + 5 <= 4 ); /* b = 0 */
Логические операции
!
логическое отрицание
(одноместная),
&& логическое "и"
(двуместная),
||
логическое "или"
(двуместная).
Результаты логических операций
op1

op2

!op1

op1 && op2

op1 || op2

0

0

не 0 (1)

0

0

0

не 0 (1)

не 0 (1)

0

не 0 (1)

не 0
(1
)

0

0

0

не 0 (1)

не 0
(1
)

не 0 (1)

0

не 0 (1)

не 0 (1)
→
←

Таблица приоритетов рассмотренных
выше операций
Операции одного приоритета
!

~

++

*

/

%

+

-

<<
<

--

(тип)

Направление выполнения
операции.

←
→
→

>>
<=

→
>

>=

→
←

Таблица приоритетов рассмотренных
выше операций
Операции одного приоритета
==

!=

&
^
|

Направление выполнения операции.

→
→
→
→

&&

→

||

→

= *= /= %= += -= <<=
>>= &= ^= |=

←
Операторы
Условный оператор
Ветвление в простейшем случае описывается в языке
Си с помощью условного оператора, имеющего вид:
if ( выражение )
оператор_1;
else
оператор_2;
где часть else может и отсутствовать. Сначала
вычисляется "выражение" в скобках; если оно истинно
то выполняется оператор_1. Если "выражение" ложно
(равно нулю - NULL), то оператор_1 пропускается, а
выполняется оператор_2. Если на месте условно
выполняемых операторов должна располагаться группа
из нескольких операторов языка, то они заключаются в
фигурные скобки - { }. Часто "выражение" в скобках
представляет условие, заданное с помощью операций
отношений и логических операций.
Пример 1
#include <stdio.h>
main()
{

/* главная функция*/
int x, y, z, max ;

/* описание

переменных*/
printf(" Введите три числа :n ");
scanf(" %d %d %d ", &x, &y, &z); /*ввод трех
чисел*/
if( x > y)
/*операции сравнивания*/
max=x;
else
max=y;
if ( z>max)
max=z;
printf(" Максимальное из (%d, %d, %d)= %d n",x, y,
z, max);
}
Пример 2
/*РЕШЕНИЕ УРАВНЕНИЯ AX=B*/
#include <stdio.h>
main()
{
float A,B,X;
printf("ВВЕДИ А, Вn");
scanf("%f %f",&A, &B);
if(A!=0)
printf("РЕШЕНИЕ:%fn", B/A);
else
if(B==0)
printf("X-ЛЮБОЕ ЧИСЛОn");
else
printf("РЕШЕНИЙ НЕТn");
}
Пример 3
/* Програииа определяет поведение ракеты,
стартующей на экваторе, в зависимости
от ее начальной скорости*/
#include <stdio.h>
main()
{
float V;
printf("ВВЕДИ Vn");
scanf("%f",&V);
if(V<7.9)
printf("РАКЕТА УПАДЕТ НА ЗЕМЛЮn");
if(V<11.2)
printf("РАКЕТА СТАНЕТ СПУТНИКОМ ЗЕМЛИn ");
if(V<16.4)
printf("РАКЕТА СТАНЕТ СПУТНИКОМ СОЛНЦАn");
else
printf("РАКЕТА ПОКИНЕТ СОЛНЕЧНУЮ СИСТЕМУn");
}
Оператор switch
Оператор switch предназначен для
организации выбора из множества
различных вариантов. Формат оператора
следующий:
switch ( выражение )
{
[объявление]
:
[ case константное-выражение1]: [ списокоператоров1]
[ case константноевыражение2]: [ список-операторов2]
:
:
[ default:
[ список операторов ]]

}
Для того, чтобы выполнить одни и те же действия для
различных значений выражения, можно пометить один
и тот же оператор несколькими ключевыми словами
case.
Пример:
int i=2;
switch (i)
{
case 1: i += 2;
case 2: i *= 3;
case 0: i /= 2;
case 4: i -= 5;
default:
;
}
Рассмотрим ранее приведенный пример, в котором
иллюстрировалось использование вложенных
операторов if, переписанной теперь с использованием
оператора switch.
char ZNAC;
int x,y,z;
switch (ZNAC)
{
case '+': x
break;
case '-': x
break;
case '*': x
break;
case '/': x
break;
default : ;
}

= y + z;
= y - z;
= y * z;
= u / z;
Оператор break
Оператор break обеспечивает
прекращение выполнения самого
внутреннего из объединяющих его
операторов switch, do, for, while. После
выполнения оператора break управление
передается оператору, следующему за
прерванным.
Циклы
Для выполнения повторяющихся
операций в языке Си предусмотрены три
вида циклов: while, do…while и for.
Цикл while называют циклом с
предусловием и записывают следующим
образом:
while (<выражение>)
<оператор>;
Пример программы, которая выводит на
экран таблицу функций sin(x) и cos(x):
#include <math.h>
#include <stdio.h>
void main( void )
{
double x = 0;
while( x < 3.0 )
{
printf( "%6.3lf
%9.6lf
%9.6lfn",x, sin(x), cos(x) );
x += 0.2;
}
}
Цикл do…while называют циклом с
постусловием и записывают следующим
образом:
do
<оператор>;
while (<выражение>);
Пример оператора do while:
/* вычисление суммы n вещественных
чисел */
s = 0; i = 1;
do
{
scanf(“%f”, &x);
s = s + x ;
i++;
}
while (i <= n) ;
При использовании цикла for инициализация
переменных и их изменение указывается в самом
цикле. Записывается это следующим образом:
for ([<выражение1>];[<выражение2>];
[<выражение3>])
<оператор>;
Здесь <выражение1> – необязательная часть
оператора, которая обычно используется для задания
начальных значений переменным цикла;
<выражение2> – необязательная часть оператора,
которая задаёт условие выполнения цикла;
<выражение3> – необязательная часть оператора,
которая обычно используется для изменения значений
переменных цикла.
Оператор continue
Оператор continue, как и оператор
break, используется только внутри
операторов цикла, но в отличие от него
выполнение программы продолжается не
с оператора, следующего за прерванным
оператором, а с начала прерванного
оператора. Формат оператора
следующий:
continue;
Пример
int main()
{
int a,b;
for (a=1,b=0; a<100; b+=a,a++)
{ if (b%2) continue;
...
/* обработка четных сумм
}
return 0;
}

*/
Оператор goto
Использование оператора безусловного
перехода goto в практике
программирования на языке СИ
настоятельно не рекомендуется, так как
он затрудняет понимание программ и
возможность их модификаций.
Формат этого оператора следующий:
goto имя-метки;
...
имя-метки: оператор;
Оператор вызова функции
Оператор вызова функции имеет вид:
имя_функции (аргумент1, ... , аргументN);
Обработка числовых
последовательностей
На языке С процесс обработки можно записать с помощью
оператора цикла while или лучше оператора цикла for:
а) scanf ("%d", &n); i=1;
while (i<=n)
{
scanf ("%f", &a);
/* обработка a */
...
i++;
}

б) scanf ("%d", &n);
for (i=1; i<=n; i++)
{
scanf ("%f", &a);
/* обработка a */
...
}
а) scanf ("%f", &a);
do
{ /* обработка a */
...
scanf ("%f", &a);
}
while (a!=W);

б) scanf ("%f", &a);
while (a!=W)
{ /* обработка a */
...
scanf ("%f", &a);
}
Пример1
• #include <stdio.h>
•
#include <math.h>
•
main()
•
{
•
int n;
/* количество чисел */
•
int a,
/* очередное число
*/
•
s=0,
/* сумма
*/
•
i;
/* порядковый номер числа в
последовательностити */
•
printf ("nВведите количество чисел: ");
•
scanf ("%d", &n);
•
printf ("Введите числовую последовательность:n");
•
for (i=1; i<=n; i++)
•
{
•
scanf ("%d", &a);
•
if (abs(a) < i*i) s=s+a;
•
}
•
printf ("сумма=%dn", s);
•
return 0;
•
}
Результаты тестирования программы
в примере1:
• Введите количество чисел: 6
•
Введите числовую
последовательность:
•
1 -2
3
16
-5
40
•
сумма=-4
•
Введите количество чисел: 4
•
Введите числовую
последовательность:
•
-1
5
10
-20
•
сумма=0
Пример2
•#include <stdio.h>
•#define
W
0
/* признак конца последовательности
*/
•main( )
•{
•float
a,
/* текущее число
*/
•
s = 0;
/* сумма
чисел
*/
•int
n = 0;
/* количество чисел
*/
•printf("n Введите последовательность чисел, заканчивающуюся
нулемn");
•scanf ("%f", &a);
•while (a != W)
•{ s += a;
•
n++;
•
scanf("%f", &a);
•}
•if (n != 0)
•{ printf ("Сумма = %.2fn", s);
•
printf ("Среднее арифметическое = %.2fn ", s/n);
•}
•else printf ("Пустая последовательность");
•
return 0;
•}
Результаты тестирования программы
в примере2:
•Введите последовательность чисел,
заканчивающуюся нулем
•2
3.5
1.5
5
0
•Сумма = 12.00
•Среднее арифметическое = 3.00
•Введите последовательность чисел,
заканчивающуюся нулем
•0
•Пустая последовательность
Пример3
•/* Определение максимального элемента
*/
•/* числовой последовательности
*/
•#include <stdio.h>
•main( )
•{
float a, max;
/* Текущее число, текущий
максимум
*/
•
int k;
/* Количество введенных чисел
*/
•printf ("nВведите последовательность чиселn");
•k = scanf("%f", &max);
/* ввод 1-го числа
*/
•if (k < 1) printf ("nВходная последовательность
пустаn");
•else
•{ while (scanf("%f", &x) != EOF )
•
if (x > max)
max = x;
•
printf ("nМаксимум= %fn", max);
•}
•
return 0;
•}
Пример4
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•

#include <stdio.h>
main( )
{
float apred, a;
*/
int flag = 1;
*/

/* предыдущее и текущее
/*

числа

признак знакочередования
/* flag=1- знаки чередуются,

0 – нет
*/
printf ("nВведите последовательность чиселn");
scanf("%f", &apred);
while( scanf("%f", &a)>0)
{ if (apred * a >= 0) flag = 0;
apred = a;
}
if (flag)
printf ("Знаки чередуются.");
else
printf ("Знаки не чередуются.");
return 0;
}
Последовательная обработка
символьных данных
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•

Примеры символьных констант:
‘*’
‘a’
‘5’
‘n’
Специальные (управляющие) символьные константы:
'n'
новая строка (new line),
't' 'v'
табуляция горизонтальная,
вертикальная,
'b'
возврат на шаг (backspace),
''
-  (обратный слэш)
''' ' (апостроф)
'"'
- "
(кавычка),
'0'
нуль-символ (байт с нулевым кодом).
Кодировка цифровых символов (символ и его числовой код):
'0' =
48
'1' = '0' + 1 = 49
'2' = '0' + 2 = 50
. . .
'9' = '0' + 9 = 57
Отсюда соотношения:
Код цифры = '0' + Значение цифры
Значение цифры = Код цифры - '0'
Последовательная обработка символов
•

Пример Вывести коды введенных с клавиатуры символов. Последовательность
символов завершается нажатием клавиши Enter.

•
•
•
•
•
•
•
•
•
•

/*
Коды символов
*/
#include <stdio.h>
#include <conio.h>
main()
{
char sim;
/* очередной символ */
printf("n Введите строку символовn");
while((sim=getchar()) != 'n')
printf("%c = %d, ", sim, sim);
printf("nНажмите любую клавишу");
getch();
/* чтение кода нажатой клавиши без отображения
символа
•
на экране*/
•
return 0;
•

Оператор while в программе можно записать иначе – с использованием функции
putchar():

• while((sim=getchar()) != 'n')
•
{ putchar(sim);
•
printf(" = %d, ", sim);
•
}
•
Пример Дан текст произвольной длины,
оканчивающийся точкой. Проверить, есть ли в
тексте сочетания "ВА".
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•

#include
main()
{
char
char
short

<stdio.h>

/* текущий символ текста */
/* предыдущий символ
*/
/* признак, имеется ли "ВА" в тексте */
/* net=1, если "ВА" нет
*/
/* net=0, если "ВА" есть
*/
printf ("nВведите текст.n");
s=getchar();
/* чтение первого символа */
if (s!='.')
{ do
{
prs=s; s=getchar();
if (prs=='В' && s=='А')
net=0;
}
while (s!='.');
}
if (net) printf ("В тексте нет 'ВА'.n");
else printf ("В тексте есть 'ВА'.n");
return 0;

}

s;
prs;
net=1;
Обработка массивов
Массивы
• Массив - упорядоченная последовательность
пронумерованных элементов одинакового
типа.
• Индекс - номер элемента массива. Индексы
элементов массива начинаются с нуля.
Элемент массива может иметь несколько
индексов. Размерность массива - количество
индексов каждого элемента.
• Вектор - одномерный массив (один индекс).
• Матрица – двумерный массив (первый
индекс - номер строки, второй - номер
столбца).
Язык Си не имеет встроенных средств для вводавывода массива целиком, поэтому массив вводят и
выводят поэлементно с помощью циклов, как,
например, в следующей программе:
•
•
•
•
•
•
•
•
•
•
•
•
•
•

#include <stdio.h>
void main(void)
{
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");
}
Использование и обработка
массивов
• Примеры:
•
int a[2][3]; /* представлено в виде матрицы
•
a[0][0] a[0][1] a[0][2]
•
a[1][0] a[1][1] a[1][2]
*/
•
double b[10]; /* вектор из 10 элементов имеющих
тип double */
•
int w[3][3] = { { 2, 3, 4 },
•
{ 3, 4, 8 },
•
{ 1, 0, 9 } };
• В последнем примере объявлен массив w[3][3]. Списки,
выделенные в фигурные скобки, соответствуют строкам
массива, в случае отсутствия скобок инициализация будет
выполнена неправильно.
• Примеры:
• int s[2][3];
• Если при обращении к некоторой
функции написать s[0], то будет
передаваться нулевая строка массива
s.
• int b[2][3][4];
• Пример объявления символьного
массива.
• char str[] = "объявление символьного массива";
Пример1

• /*обращение массива*/
#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)
{
p=a[i];
a[i]=a[9-i];
a[9-i]=p;
i++;
}
i=0;
while(i<10)
printf(" %d",a[i++]);
}
Пример2
• /*в массиве найти разность
мин. и макс. элементов */
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);
}
Пример2
• #include <stdio.h>
main()
{
static int a[10]=
{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("макс-мин=%dn",max+min);
}
Пример3
•

/*макс одинаковых подряд*/
#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=%dn",(k>max)?k:max);
}
Пример4
•

#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");
}
}
Пример5
• /*обмен мин с диагональю*/
#include <stdio.h>
#define M 4
main()
{
static a[M][M]={
{ 3,4,1,5),
{-1,6,7,0},
{ 1,8,7,-1},
{ 4,9,7,-1}};
int i, j, jmin, amin;
i=0;
Пример5
• while(i<M)
{
amin=a[i][0];
jmin=0;j=1;
while(j<m)
{
if(a[i][j]<amin)
{
amin=a[i][j];
jmin=j;
}
j++;
}
Пример5
• a[i][jmin]=a[i][i];
a[i][i]=amin;
i++;
}
i=0
while(i<M)
{
j=0;
while(j<M)
printf("%3d",a[i][j++]);
printf("n");
i++;
}
}
Указатели
•Язык Си имеет средства работы
непосредственно с областями
оперативной памяти ЭВМ, задаваемыми
их адресами (указателями). В языке C
указатели строго типизированы, т. е.
различают указатели (адреса)
символьных, целых, вещественных
величин, а также типов данных,
создаваемых программистом.
Для указателей одного и того же типа допустимой
является операция присваивания, кроме того
указателю типа void может быть присвоено значение
адреса данного любого типа, но не наоборот, например

•int *a, *b;
•double *d;
•void *v;
•...
•a = b; /* Правильно */
•v = a; /* Правильно */
•v = d; /* Правильно */
•b = v; /* Неправильно */
•d = a; /* Неправильно */
Для поддержки адресной арифметики в языке Си
имеются две специальные операции - операция взятия
адреса & и операция получения значения по заданному
адресу * (операция разадресации).
•Рассмотрим работу вышеописанных операций на следующем
примере
•int *p, a,
•double d;
•void *pd;
•p = &a;
•*p = 12;
•p = &b;
•*p = 20;
•/* Здесь a
•pd = &d;
•*( (double
•/* Здесь d

b;

содержит число 12, b - число 20 */
*) pd ) = a;
содержит число 12.0 */
Состояние ячеек до первого присваивания
P, адрес
1000

a, адрес
2000

b, адрес 4000

мусор

мусор

мусор

Состояние ячеек после присваивания p = &a
p, адрес 1000 a, адрес 2000 b, адрес 4000

2000

мусор

мусор
Состояние ячеек после присваивания *p = 12
p, адрес
1000

a, адрес
2000

b, адрес 4000

2000

12

мусор

Состояние ячеек после присваивания p = &b
p, адрес 1000 a, адрес 2000 b, адрес 4000

4000

12

мусор
Состояние ячеек после присваивания *p = 20

p, адрес 1000

a, адрес 2000

b, адрес 4000

4000

12

20
Следует также опасаться случая, когда указатель содержит адрес
объекта программы, завершившего свое существование. Например,
результат работы следующей программы неверен и непредсказуем:
•#include <stdio.h>
•#include <math.h>
•double * Cube(double x)
•{
• double cube_val;
• cube_val = x*x*x;
• return &cube_val;
•}
•void main(void)
•{
• double *py;
• py = Cube(5);
• printf("y1 = %lfn", *py);
• sin(0.7);
• printf("y1 = %lfn", *py);
•}
Динамическое выделение памяти
• Данные, которые создаются,
инициализируются и уничтожаются по
требованию программиста называются
динамическими. Для управления такими
данными используются специальные
стандартные функции, прототипы которых
описаны в заголовочном файле <malloc.h>
(для некоторых компиляторов <alloc.h>).
• Для запроса динамической памяти служит
функция malloc(), которая имеет следующий
прототип:
• void * malloc(size_t size);
Статические и динамические
массивы
• int n;
• int *m;
/*
указатель (ссылка)
*/
• scanf(“%d”, &n);
• m = (int *) malloc ( n * sizeof(int));/* выделение
памяти */
• if (m == NULL) { printf( “No memory”); return
1;}/* ошибка
*/
• for (int i = 0; i < n; i++)
•
scanf(“%d”, &m[i]);
• …
• free (m);
/* освобождение памяти
*/
• return 0;
/* успешное завершение
*/
Типичная последовательность действий при
работе с динамической памятью:
•double *A; int n;
• ...
• n = 200;
• ...
• A = (double *) malloc( n *
sizeof(double) );
• ...
• /* Работа с массивом A */
• ...
• free(A);
Подпрограммы
• Подпрограмма - это программа,
которая выполняется в составе одной
или нескольких программ. В сложных
программах в виде подпрограммы чаще
всего определяют функционально
самостоятельный фрагмент алгоритма,
который возможно используется
неоднократно.
• Вызов подпрограммы (команда «выполнить
подпрограмму») записывается аналогично
использованию математической функции:
• f(a1, a2, ... , an)
• где f - имя подпрограммы (аналогично имени
функции P), a1, a2, ... , an - аргументы
вызова (фактические параметры), конкретные
величины, подставляемые вместо формальных
параметров при выполнении подпрограммы (как
аргумент 10 при вычислении значения функции P).
• Формальный параметр – это входная или выходная
переменная подпрограммы, указанная в заголовке ее
определения (как x в левой части определения
функции P(x)).
• Определение функции имеет вид:
• <Заголовок_ функции>
• {
<Объявление переменных функции>
// тело
•
<Операторы функции>
// функции
• }
• Заголовок функции имеет вид:
• <тип значения> <имя функции> ([<тип>
<имя>[,<тип> <имя>] …])
• Если функция не обладает значением, в
качестве типа значения пишется ключевое
слово void. Тип значения функции
разрешается не указывать. В этом случае (по
умолчанию) подразумевается тип int.
• Выполнение подпрограммы завершается при
выполнении оператора возврата или достижении
конца тела функции.
• Оператор возврата имеет вид:
• return [<выражение>];
• В теле функции, обладающей значением,
обязательно должен быть оператор возврата, где тип
вычисленного выражения должен соответствовать
типу значения функции. Значение выражения
становится значением функции: оно передается в
вызывающую программу и подставляется вместо
вызова функции. Оператор возврата вида return;
(без выражения) осуществляет возврат в
вызывающую программу в точку, следующую за
вызовом подпрограммы. Если функция не
возвращает значение, оператор возврата может
отсутствовать.
• Вызов подпрограммы, т.е. команда для
выполнения подпрограммы имеет вид:
• <имя функции> ([<имя> [,<имя>] …])

• При вызове подпрограммы (в скобках)
определяются имена фактических
параметров (аргументы вызова). Фактические
параметры подставляются вместо формальных
параметров при выполнении подпрограммы.
• Вызов функции, обладающей значением
(возвращающей значение), в операторе
присваивания:
• <имя переменной> =
…]);

<имя функции> ([<имя> [, <имя>]
• Пример описания функции:
• /* функция определения наибольшего из двух чисел
*/
• float max ( float x, float y )
• { if (x>y) return x;
•
else return y;
• }
• Пример вызова функции:
• f = max(a,b) - max(a+b,c);
• содержит два вызова приведенной выше функции
max. При первом обращении функции max
передаются значения переменных a и b, она
возвращает наибольшее из этих чисел, которое
подставляется вместо указателя функции max(a,b).
При втором вызове функции max формальным
параметрам x и y присваиваются соответственно
значения фактических параметров a+b и c.
Оператор return возвращает наибольшее из этих
Параметры подпрограмм
• При вызове подпрограммы происходит согласование
параметров:
• - порядок и типы формальных параметров в
объявлении и определении подпрограммы должны
совпадать с порядком и типами фактических
параметров при вызове подпрограммы.
• После вызова подпрограммы выполняются ее
операторы, где фактические параметры
подставляются вместо формальных параметров.
• Передача параметров и согласование формальных
и фактических параметров может осуществляться
• по значению;
• по ссылке (по адресу).
Передача параметров по
значению
• При передаче параметра по значению фактический
параметр может быть выражением, в частном случае
переменной или константой. Формальному
параметру присваивается значение выражения, тип
которого должен совпадать с типом формального
параметра. В подпрограмме используется только
значение фактического параметра, любые изменения
параметра в подпрограмме не влияют на его
значение в вызывающей программе. Таким способом
можно передавать только входные параметры, т.е.
можно передать данные от вызывающей программы
к подпрограмме.
Передача параметров по
ссылке.
• При передаче параметра по ссылке фактический
параметр может быть только переменной, тип
которой должен совпадать с типом формального
параметра. Передается не значение фактического
параметра, а его адрес. При выполнении
подпрограммы фактический параметр заменяет
формальный параметр, действия выполняются над
фактическим параметром. Изменения параметра в
подпрограмме меняют его значение в вызывающей
программе. Таким способом можно передавать и
входные, и выходные параметры, т.е. можно
передать данные от вызывающей программы к
подпрограмме и в обратном направлении.
Область действия переменных
• Локальные переменные. Переменные,
объявленные в теле функции, являются
локальными переменными этой функции.
Формальные параметры подпрограммы,
также считаются локальными для этой
подпрограммы. Областью действия
локальной переменной является блок, в
котором эта переменная объявлена.
• Глобальные переменные. Глобальные
переменные объявляются до всех функций
или между определениями функций.
Областью действия глобальной переменной
является вся программа.
Пример
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•

/* Вариант Б. Вычисление c=n!/(m!*(m-n)!)
*/
/* с помощью функции, возвращающей значение
*/
#include <stdio.h>
long fakt (int k);
/* прототип функции
*/
/*
Вычисление c = n! / (m! * (n-m)!)
*/
void main(void)
{ int n, m, c;
/* исходные данные и результат
*/
printf("nВведите два исходных целых числа ");
scanf("%d %d", &n, &m);
c = fakt(n) / (fakt (m) * fakt (n-m));
printf ("n c = %d", c);
}
/*
Функция k!
*/
long fakt (int k)
{ long f;
/* k!
*/
int j;
/* текущий множитель
*/
f=1;
for (j=2; j<=k; j++)
f = f * j;
return f;
/* значение функции
*/
}
Пример
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•

#include <stdio.h>
int KolLatBukv (char s[])
{
int i,
/* индекс очередного символа строки s */
k=0;/* количество лат. букв */
for ( i = 0; s[i] != '0'; i++ )
if(s[i]>='a'&&s[i]<='z'||s[i]>='A'&&s[i]<='Z') k++;
return k;
}
void main()
{
char s1[81], s2[81];
/* заданные строки */
printf ("nВведите две строки символовn");
gets (s1);
gets (s2);
printf ("В 1-й строке %d лат. буквn", KolLatBukv (s1));
printf ("Во 2-й строке %d лат. буквn", KolLatBukv (s2));
}
Пример результата
выполнения программы:
• Введите две строки символов
•
AaBbcd 123 Zz
•
t = x + y * z / 10 ;
• В 1-й строке 8 лат. букв
• Во 2-й строке 4 лат. букв
Пример
•
•
•
•
•
•
•
•
•
•
•
•
•

#include <stdio.h>
void SumPos (float m[], int n, float *s, int *k)
/* Вх. параметры:
m – указатель на заданный массив,
n – число элементов массива.
Вых. параметры:
*s – сумма положительных элементов массива,
*k – количество положительных элементов
*/
{
int i;
for (i=0, *s=0, *k=0; i<n; i++)
if (m[i] > 0) (*s) += m[i], (*k)++;
}
Пример
• void main()
• {
• float a[6],
/* массив */
• s;
/* сумма положительных элементов */
• int k,
/* количество положительных эл-тов
*/
• i;
/* индекс элемента массива*/
• printf ("nВведите 6 чиселn");
• for ( i=0; i < 6; i++) scanf ("%d ", &a[i] );
• SumPos (a, 6, &s, &k); /* вызов функции */
• printf ("Сумма положительных чисел = %fn", s);
• printf ("Количество положительных чисел: %dn", k);
• }
Рекурсивные функции
•Рекурсивная функция – это функция, в
определении которой есть обращение к себе
самой.
•Пример. Допустим, нужно вычислить n!
(факториал числа n). Значение n! можно
представить как произведение n на
факториал (n-1) :
•n! = n*(n-1)!
•(n-1)! = (n-1)*(n-2)!
•…
Пример
• /* Рекурсивная функция вычисления n! */
•float fact (int n)
•{ if (n<0)
•
{
puts (“Недопустимый аргумент
функции fact”);
•
exit (1); /* завершение выполнения
программы */
•
}
•
if (n==1 || n==0) return 1;
•
return
n*fact(n-1);
•}
Пример вызова этой функции:
•int k;
•scanf (“%d”, &k);
•printf (“%d! = %.0f”, k,
fact(k));
Выполнение функции при k=4.
Символьные строки и функции
обработки строк
• Символьная строка представляет собой
последовательность символов, заканчивающуюся
нуль-символом (‘0’ c кодом 0).
• Строковые константы заключаются в кавычки. При
компиляции программы они автоматически
дополняются нуль-символом. Строковые
переменные объявляются как массивы символов,
например:
• char
str[81];
• char
error[] = “Ошибка”;
•
/* массив из 7 символов, включая ‘0’ */
• Для ввода с клавиатуры строки
символов служит библиотечная
функция gets(), а для вывода –
функция puts().
• Пример:
•
char s1[81], s2[81];
•
•
•
•
•

char
puts
puts
gets
gets

*s3 = “Привет!”;
(s3);
(“Введите две строки”);
(s1);
(s2);
• В библиотеках Turbo C, Borland C++
имеется ряд функций обработки строк:
• - определения длины строки (strlen),
• - сравнения строк (strcmp, strncmp),
• - копирования строк (strcpy, strncpy),
• - сцепления строк (strcat, strncat),
• - поиска символа в строке (strchr, strrchr,
strpbrk),
• - поиска подстроки в строке (strstr).
• При их использовании в программу
необходимо включить заголовочный файл
string.h, содержащий объявления этих
функций.
•
•
•
•
•
•
•
•
•
•
•
•
•
•

Рассмотрим одну из библиотечных функций - функцию
сцепления двух заданных строк strcat(). Определение функции:
char *strcat (char *s1, char *s2);
Функция копирует строку s2 (на которую ссылается указатель
s2) в конец строки s1 и возвращает значение s1 - ссылку на
сцепленную строку.
Работу функции можно описать так:
char *strcat (char *s1, char *s2)
{ char *rs; /* ссылка на результирующую строку
*/
rs=s1;
/* запоминание адреса начала строки
s1 */
while (*s1!='0')
s1++; /* поиск конца
строки s1 */
/* копирование строки s2 в конец s1 */
while (*s2!='0')
{ *s1=*s2; s1++; s2++; }
*s1='0';
return rs;
}
• А теперь посмотрите на более компактную
(но менее понятную) запись этой функции:
• char *strcat (char *s1, char *s2)
• { char *rs;
•
rs=s1; /* запоминание адреса
начала строки s1 */
•
while (*s1!='0') s1+
+;
/* поиск конца строки s1
*/
•
while ((*s1++ = *s2++) !
='0'); /* копирование s2 в конец
s1,
•
включая нуль-символ */
•
return rs;
•}
• С символьными строками можно работать как с
массивами: обращаться к отдельным символам
строки с помощью индекса. Ту же функцию
сцепления строк можно написать иначе:
• char *strcat (char *s1, char *s2)
• {
•
int i=0, j=0; /* индексы символов
строк s1 * и s2 */
•
while (s1[i]) i++;
/* поиск
конца строки s1 */
•
while ((s1[i++] = s2[j++])); /*
копирование строки s2
•
в конец s1, включая
нуль-символ */
•
return s1;
• }
Пример драйвера для функции
сцепления строк strcat():
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•

#include <stdio.h>
#include <conio.h>
void main()
{ char str1[81],str2[81];
puts ("Введите две строки");
gets (str1);
gets (str2);
if (strlen(str1)+strlen(str2) < 81)
{ puts ("Результат:");
puts (strcat(str1,str2));
printf ("Строки после вызова функции сцепления:n
%sn%sn",
str1,str2);
}
else puts ("Не хватает памяти для результирующей
строки");
getch();
}
Посимвольная обработка строк
• Для представления строк могут использоваться
массивы символов. Примеры описания такого
массива:
• char text[10];
*/

/* массив из 10 символов

• Для ввода символьных строк можно
использовать библиотечную функцию gets():
• char s[81];
•
gets(s);

• Вывод символьных строк можно выполнить
либо с помощью библиотечной функции puts():
•

сhar str[]= “Привет”;
• puts(str);
/* или

printf(“%sn”, str); */
Структуры
•Структура – это структура данных,
состоящая из фиксированного числа
компонентов, называемых полями
структуры. В отличие от массива,
компоненты (поля) записи могут быт
различного типа. Чтобы можно было
ссылаться на тот или иной компонент
записи, поля именуются. Структура
является аналогом типа данных запись
из языка Паскаль.
Переменные типа структура
объявляются следующим образом:
•struct <имя типа>
•{
•<список полей>
•} <имя переменной>;
•Здесь <имя типа>, <имя переменной> –
правильный идентификатор;
•struct – зарезервированное слово;
•<список полей> – список полей; представляет
собой последовательность разделов структуры,
между которыми ставится точка с запятой.
Массив структур можно описать
следующим образом:
•struct Stud
•{
• char fam[15], name [15];
• int group;
• Birthday bd;
• float rating;
•} PMI[100];
•
•
•
•
•
•
•
•
•
•

Например:
struct ANKETA a1;
struct BOOK b1,b2;
struct BOOK mb[100]; /* массив из 100
структур типа BOOK*/
struct ANKETA *p1;
/* указатель на
структуру типа ANKETA */
struct BOOK *p2 = &b2;
/* указатель на
структуру типа BOOK,
ссылающийся на переменную b2 */
При объявлении структурных переменных на языке
C++ ключевое слово struct обычно опускается,
например:
ANKETA
a1;
BOOK
b1,b2;
• Пример
• /* ввод значения структурной переменной b2 типа
BOOK*/
• gets(b2.author);
• gets (b2.name);
• scanf(“%d%d”, &b2.year, &b2.pages);
• Пример
• struct ANKETA a2;
• strcpy(a2.fio, “Иванов А.В.”);
• а2.gr = 1980;
• strcpy(a2.adr, “ул.Пушкина, д.10, кв.5”);
• Пример
• struct BOOK *p3 = &b3;
• printf (“%s, %s, %d г., %d с.n”, p3->author, p3>name,
•
p3->year, p3->pages);
• Результат на экране:
• Толстой Л.Н., Война и мир, 1995 г., 1650 с.
• Если структурные переменные используются
только в одной функции программы, то можно
совместить описание переменных с
описанием типа. При этом имя типа можно не
задавать, например:
• struct
• { char fio[20];
•
int
gr;
•
char adr[40];
• } a1, a2, *p1;
Работа с файлами
•Файл – это поименованная область на
диске, содержащая какую-либо
информацию, например, текст
программы, данные для программы,
документ.
•Файлы бывают текстовые и двоичные
(бинарные).
Работа с файлами
•Текстовые файлы – это файлы, которые
создаются или которые можно
просмотреть с помощью текстовых
редакторов. В операционной системе MS
DOS текстовые файлы представляют
собой последовательность символьных
строк. Каждый символ занимает один
байт. Строка заканчивается двумя
символами: «возврат каретки» (с кодом
13) и «перевод строки» (с кодом 10).
Работа с файлами
•Двоичные файлы содержат информацию
во внутреннем представлении. Примером
двоичного файла является exe-файл,
содержащий программу в машинных
командах. Прикладная программа тоже
может создать двоичный файл, записав в
него данные в том виде, в каком они
хранятся в памяти (к примеру, типа int).
Для чтения информации из
файла служат функции:
•
•
•
•
•
•
•
•
•

fscanf() – форматированный ввод,
fgets() – чтение одной строки,
fgetc() – чтение одного символа,
fread() – ввод заданного числа байтов (символов).
Для записи информации в файл используются
функции:
fprintf() – форматированный вывод,
fputs() – вывод строки,
fputc() – вывод одного символа,
fwrite() – вывод заданного числа байтов (символов).
Некоторые функции доступа к
файлам
•fopen – открытие файла.
•Прототип функции:
•FILE * fopen (char * fname, char * mode);
•Первый параметр fname задает имя открываемого
файла, второй – режим открытия файла или вид его
обработки. Параметр mode может задаваться в виде:
•“r” – чтение файла,
•“w” – запись в файл (если файл существует, он
стирается),
•“a” – добавление информации в конец файла,
•“r+” – чтение и запись.
Пример
•FILE *fout, *fmod;
• /* указатели на выходной и модифицируемый файлы
*/
•char fname[13];
/* имя модифиц. файла */
•fout = fopen (“f1.txt”, “w”);
•puts(“Введите имя модифицируемого файла”);
•gets (fname);
•if ((fmod = fopen(fname, “r+”) ==NULL)
•{ puts (“Файл в текущем каталоге не найден”);
•
exit (1);
•}
• Задача. Входной файл st.txt содержит
сведения о сдаче студентами группы
экзаменационной сессии. Каждая
запись файла содержит фамилию и
инициалы студента (15 символов) и
пять оценок (5 символов) и
завершается символом ”перевод
строки”. Напечатать список студентов с
указанием среднего балла каждого
студента.
•
•
•
•
•
•
•
•
•
•
•
•

Программа:
/*-----------------------------------------*/
/* Печать среднего балла каждого студента */
/*-----------------------------------------*/
#include <stdio.h>
#include <conio.h>
struct STUDENT
{ char fio[15];
/* фамилия и.о. */
char oc[7];
/* 5 оценок + 'n' + '0' */
};
void main()
{ FILE *f;
/* указатель на входной файл
*/
•
struct STUDENT tz; /* текущая запись файла
*/
•
int i,
•
s;
/* сумма оценок */
• if ((f= fopen("st.txt","r")) == NULL)
•
{ puts ("Файл st.txt не найден");
•
return;
•
}
•
puts ("nФамилия и.о.
Ср.балл");
•
puts ("------------------------------");
•
while (fgets((char *)&tz, sizeof(struct
STUDENT), f) != NULL)
•
{ for (i=0,s=0; i<5; i++)
•
s+=tz.oc[i]-'0';
•
tz.fio[14]='0';
•
printf("%s %.1fn", tz.fio, (float)s/5);
•
}
•
fclose(f);
•
getch();
• }
Массивы и функции как параметры
• Указатели на функции
• Функции, как и другие объекты программы,
располагаются в памяти ЭВМ. Любая область
памяти имеет адрес, в том числе и та, в
которой находится функция. Имя функции без
круглых скобок за ним представляет собой
константный адрес этой области памяти.
Таким образом, имея функции со
следующими прототипами:
• double sin(double x);
• double cos(double x);
• double tan(double x);
• Можно описать и указатель на
функцию. Например, для функции с
аргументом типа double,
возвращающей значение типа double,
описание такого указателя будет
выглядеть следующим образом:
• double (*fn)(double x);
• После того, как описан указатель на функцию,
становятся возможными следующие операции:
•
•
•
•

fn = sin; /* Настройка указателя на функцию sin
a = fn(x); /* Вызов функции sin через указатель
fn = cos; /* Настройка указателя на функцию cos
b = fn(x); /* Вызов функции cos через указатель

• Можно описать массив указателей на функцию и
проинициализировать его:
• double (*fnArray[3])(double x) = { sin, cos,
tan };

• Теперь становится возможным следующий цикл:
• for(i=0; i<3; i++)
• printf( "F(x) = %lfn", fnArray[i](x) );

*/
*/
*/
*/
• Можно описать функцию возвращающую значение
указателя на функцию:
• double (*fnFunc(int i)) (double x)
• {
•
switch(i)
•
{
•
case 0 : return sin;
•
case 1 : return cos;
•
case 2 : return tan;
•
}
• }

• После описания функции fnFunc становится
возможным следующий цикл:
• for(i=0; i<3; i++)
• printf( "F(x) = %lfn", fnFunc(i)(x) );
Массивы и указатели
• В языке C понятие массива тесно связано с
понятием указателя. Действительно, как
было описано выше, имя массива
представляет собой адрес области памяти,
распределенной под этот массив, или иными
словами адрес первого элемента массива.
Пусть описаны следующие данные:
• int a[100], *pa;
• и осуществлено присваивание:
• pa = a;
• Два существенных отличия массива от
указателя:
• массиву при описании выделяется
память для хранения всех его
элементов, а указателю только для
хранения адреса;
• адрес массива навсегда закреплен за
именем, то есть имя массива является
адресной константой и выражение вида
a = pa недопустимо.
Пример
• double A[100], *pA, *pA100;
• int i;
• /* Заполняем массив A. Работаем
с массивом */
• for (i=0; i<100; i++) A[i]=0;
• /* Заполняем массив A. Работаем
с указателями */
• for (pA=A, pA100=pA+100;
pA<pA100; pA++) *pA=11.9;
Указатели и двумерные массивы
• Пусть имеются следующие определения
массивов и указателей:
• int A[4][2], B[2];
• int *p, (*pA)[4][2], (*pAstr)[2];
• Здесь A представляет собой двумерный
массив из четырех строк и двух столбцов, B одномерный массив из двух элементов. Для
каждого из этих массивов будет выделено
соответствующее количество памяти,
достаточное для хранения всех их
элементов.
• Указатель p представляет собой указатель на
величину int, указатель pA - указатель на
двумерный массив из четырех строк и двух
столбцов, pAstr - указатель на одномерный
массив из двух элементов.
• Для вышеописанных указателей допустимы
следующие операции присваивания, поскольку слева
и справа от операции присваивания находятся
указатели на один и тот же тип данных:
• p = B;
• p = &B[1];
• p = &A[0][0];
• p = A[2];
• Следующее присваивание:
• p = A; /* неверно */
• является неверным, так как слева от операции
присваивания находится указатель на тип int, а
справа - указатель на первый элемент массива A,
который (элемент) представляет собой массив из
двух элементов типа int. В таких случаях
компиляторы выдают предупреждающее сообщение
о подозрительном преобразовании указателя.
• Следующие присваивания корректны
• pA = &A; /* Указатель на двумерный массив
*/
• pAstr = &B; /* Указатель на одномерный
массив */
• и устанавливают следующее соответствие
элементов:
• (*pA)[i][j] эквивалентно A[i][j]
• (*pAstr)[i] эквивалентно B[i]
• Массивы указателей удобны для хранения
символьных строк:
• char *str[] = {
• "Строка 1",
• "Строка 2",
• "Длинная строка 3"
• };
Пример
•
•
•
•
•
•
•
•
•
•
•
•

#include <stdio.h>
#define N 3
void p1(int *m,int k)
{ int i;
for(i=0;i<k;printf("%d",m[i++]));
puts("n");
}
void p3(int *m,int k)
{ int i;
for(i=k-1;i>=0;printf("%d",m[i--]));
puts("n");
}
Пример
•
•
•
•
•
•
•
•
•
•
•

void p2(void p(int *,int), int *mm,int nn)
{
p(mm,nn);
}
void main()
{
int mas[N],i;
for(i=0;i<N;mas[i++]=i);
p2(p1,mas,N);
p2(p3,mas,N);
}
Технологии программирования
•В проектировании и
программировании активно
применяются следующие технологии:
•Структурное программирование.
•Модульное программирование.
•Объектно-ориентированное
программирование.
•Компонентное программирование.
Структурное
программирование…
• Э. Дэйкстра (60-е годы):
• Для любой простой программы можно
построить функционально эквивалентную ей
структурную программу, т.е. программу,
сформированную на основе фиксированного базисного
множества, включающего:
•структуру последовательного действия,
•структуру выбора одного из двух действий
•структуру
цикла,
то
есть
многократного
повторения некоторого действия с проверкой условия
остановки повторения.
Структурное
программирование…
•Простая программа – ровно один
вход и один выход.
•Базисные конструкции:
Структурное программирование
• Стандартизация и линейность программы –
снижение сложности.
•
•
•
•
•

Некоторые соображения:
Алгоритм должен иметь 1 вход и 1 выход.
Никаких goto.
Нет зависимости от языка программирования.
Ясен набор операторов, который необходим в языках
программирования.
Модульное программирование...
• Основная идея: разбиваем сложную
задачу на подзадачи, каждую из них
при необходимости разбиваем снова и
т.д.
• Получаем простые задачи, их решаем,
объединяем.
Модульное программирование
• Структурное программирование – универсальный
базис алгоритмических конструкций.
• Модульное программирование – специфичный для
задачи базис из модулей.
– Более высокий уровень абстракции.
– Настройка на конкретную задачу.
– Возможности повторного использования.
– Возможности коллективной разработки –
разделение труда.
Объектно-ориентированное
программирование...
• Дальнейшая борьба со сложностью.
• Технология работает с этапа анализа.
• Анализ – Проектирование –
Программирование.
• В основе – объектная модель и
объектная декомпозиция.
Объектно-ориентированное
программирование
• Основные принципы объектной модели:
– абстракция;
– инкапсуляция;
– иерархия (наследование, агрегация);
– полиморфизм;
– модульность.
• Объектная декомпозиция (в отличие от
алгоритмической): элементы проекта –
классы и объекты (а не алгоритмы).
И только потом данные и алгоритмы.
Компонентное
программирование...
• Компонентное программирование –
развитие объектно-ориентированной
идеологии.
• Введен следующий уровень абстракции –
классы объединяются в компоненты.
• Основной принцип компонентного
программирования: сборка приложения
из готовых компонент, в общем случае
написанных на разных языках.
Компонентное программирование
• Компонент:
– программный код в виде самостоятельного
модуля
– м.б. использован в неизменном виде
– может допускать настройку
– обладает поведением (функциональностью).
• Компонент изолирован от внешнего мира своим
интерфейсом – набором методов (их
сигнатурами).
• Компонентная программа – набор независимых
компонент, связанных друг с другом посредством
интерфейсов.
Структурная декомпозиция и
нисходящее программирование
• Задача
•
Дано целое n и вещественные x1,
x2, ..., xn. Составить программу
печати заданных вещественных чисел
в порядке возрастания (не убывания).
Вход:
• Введите количество чисел:
5
• Введите числа: 12.5 6 14 -3 10
•
Выход:
• Упорядоченные числа:-3.0 6.0 10.0
12.5 14.0
Функциональная структура
программы
•
main

Vvod

Sort
1 этап.
• Разработка алгоритма функции
main().
Алгоритм :

• 1. n = Vvod(x); /* Ввод n и
массива x */
• 2. Sort (x,n);
/* Сортировка
массива x по
возрастанию*/
• 3. Вывод сортированного по
возрастанию массива x
2 этап
• Алгоритм функции ввода данных
Алгоритм функции ввода данных
• int Vvod (float x[])
• {
•
Ввод n;
•
for (i=0; i<n; i++)
•
Ввод x[i];
•
Возврат n;
• }
Вывод массива x
• Вывод заголовка "Упорядоченные
числа:";
• for (i=0; i<n; i++)
•
Вывод x[i];
Метод последовательного
нахождения максимума
• 2.5 6 14
элементов
• 2.5 6 10
•
• 2.5 6 10
• 2.5 6 -3
•
• 2.5 6 -3
элементов
• 2.5 -3 6
• 2.5 - 6
• -3 2.5

-3 10

// рассматривается n

-3 14
-3
10

// рассматривается n-1 элементов

// рассматривается n-2

// рассматривается n-3 элементов
Алгоритм функции сортировки
массива x по возрастанию
• void Sort (float x[], int n)
• { for (k=n-1; k>0; k--)
•
{ Определение максимума среди
•
элементов x[0], ... , x[k] и его
•
индекса
imax.
•
• }

Обмен: x[imax] <--> x[k];
3 этап
• Определение максимума среди
элементов x[0], ... , x[k] и его индекса
imax.
Фрагмент программы:
• imax =0;
• for (i =1; i <= k; i++)
•
if (x[i] > x[imax]) imax = i;
Программа:
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•

#include <stdio.h>
#define NMAX 100
/* Макс-е количество входных чисел */
/* Функция ввода данных * /
int Vvod (float x[])
{
int n;
/* Количество чисел
*/
int i;
/* Индекс текущего числа */
printf ("nВведите количество чиселn");
scanf ("%d", &n);
printf ("Введите числаn");
for (i=0; i<n; ++i)
scanf("%f", &x[i]);
return n;
}
• /*Функция сортировки массива по
возрастанию*/
• void
Sort (float x[], int n) {
•
int
k; /* Максимальный индекс
просмотра*/
•
float r;
/* Для обмена
*/
•
int imax; /* Индекс максимального
элемента */
•
int
i; /* Индекс текущего числа
*/
•
for (k=n-1; k>0; k--)
•
{ imax =0;
•
for (i =1; i <= k; i++)
•
if (x[i] > x[imax])
imax = i;
•
/* Обмен
x[imax] и x[k] */
•
r = x[imax];
•
x[imax] = x[k];
•
x[k] = r;
• /* Главная функция */
• void main (void)
• { float x[NMAX]; /* Обрабатываемые числа*/
•
int n; /* Количество чисел
*/
•
int i; /* Индекс текущего числа
*/
•
/* 1. Ввод массива x */
•
n = Vvod(x);
•
/* 2. Сортировка массива x по возрастанию */
•
Sort(x,n);
•
/* 3. Вывод массива x */
•
printf("Упорядоченные числа:n");
•
for (i=0; i<n; ++i)
•
printf (" %4.1f", x[i]);
• }
Модульное программирование
• Технология модульного программирования
предполагает разбиение программы на
отдельные части – модули. Модуль может
содержать одну или несколько
взаимосвязанных функций и общие для
функций данные. Каждый модуль
помещается в отдельный файл (с
расширением .c или .cpp) и компилируется
автономно. Получившиеся в результате
компиляции объектные модули
объединяются в единый исполняемый
модуль (exe-файл) с помощью компоновщика
(Linker).
• При разработке многомодульных программ
нужно создавать проект (файл с
расширением .prj). В проекте указывают, из
каких файлов состоит программа. Это могут
быть исходные файлы с расширением .c
или .cpp, или объектные файлы с
расширением .obj (полученные в результате
компиляции исходных модулей), или
библиотеки объектных модулей (файлы с
расширением .lib). Заголовочные файлы (с
расширением .h) в проекте не указывают,
они должны быть в том же каталоге, в
котором содержатся модули программы.
Окно диалога “Open Project File”
Окно диалога “Add to Project List”
Пример создания многомодульной
программы
•
•
•
•
•
•
•
•
•
•
•
•
•
•

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#define MAXDL
9
/* макс. длина идентификатора (с признаком
конца '0' ) */
struct
EL_SP
/* тип элемента списка
{ char id [MAXDL];/* идентификатор
*/
struct EL_SP *sled;
/* ссылка на следующий элемент */
};
void Vkl ( struct EL_SP **p, char t_id[] );
void PechSp ( struct EL_SP *p );

*/
Файл “Vkl.c”:
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•

#include "spisok.h"
/*-------------------------------------------------*/
/* функция включения очередного идентиф. в список */
/*-------------------------------------------------*/
void Vkl ( struct EL_SP **p, char t_id[] )
/* Вх. данные: *p
- указатель списка
идентификаторов в лексикографическом порядке,
t_id - включаемый в список (текущий) ид-р */
/* Вых. данные: *p
*/
{

struct EL_SP *pt,/* указатель включаемого эл-та */
*k,*j;
/* указатели очередного и предыдущего
элементов списка
*/
/* выделение памяти для нового эл-та списка */
pt = (struct EL_SP *) malloc(sizeof(struct EL_SP));
strcpy(pt->id, t_id);
Файл “Vkl.c”:
• if (*p==NULL || strcmp(pt->id,(*p)->id) < 0)
•
{
/* включение ид-ра в начало списка */
•
pt->sled=*p; *p=pt;
•
}
•
else
•
{
/* поиск элемента списка, после которого нужно
•
включить идентификатор */
•
k=*p;
•
while (k!=NULL && strcmp(pt->id,k->id)>=0)
•
{ j=k; k=k->sled;
•
}
•
/* включение эл-та *pt после элемента *j */
•
j->sled=pt; pt->sled=k;
•
}
• }
Файл “PechSp.c”:
• #include "spisok.h"
• /
*-------------------------------------------------*/
• /*
функция печати списка
*/
• /
*-------------------------------------------------*/
• void PechSp ( struct EL_SP *p )
• /* Вх. данные: p - указатель начала списка
*/
• { struct EL_SP *i;
•
/* указатель текущего элемента списка */
•
printf ("nРезультат:n");
•
for ( i=p; i!=NULL; i=i->sled )
•
puts (i->id);
• }
Файл “main.c”:
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•

#include "spisok.h"
/*---------------------------------------------*/
/*
О С Н О В Н А Я
П Р О Г Р А М М А
*/
/*---------------------------------------------*/
main()
{ struct EL_SP *p; /* указатель начала списка
*/
unsigned n ;
/* количество идентификаторов */
unsigned i ;
/* параметр цикла
*/
char t_id[MAXDL]; /* текущий идентификатор
*/
printf ("nВведите число идентификаторовn n=");
scanf ("%u",&n);
getchar();
/* пропуск символа "перевод строки" */
p=NULL;
/* список пока пуст */
printf("Введите идентификаторы ");
printf("после каждого нажимайте клавишу <Enter>n");
for ( i=1; i<=n; i++ )
{
gets (t_id);
Vkl (&p,t_id); /* включение ид-ра в список */
}
PechSp (p);
/* печать списка */
printf ("nДля завершения нажмите любую клавишуn");
getch();
}
Работа с графикой на языке C и
модуль graphics.h
• Монитор ПК может работать в двух
режимах текстовый и графический. В
этих режимах по разному
представляется видео память. Переход
из режима в режим очищает экран. В
графическом режиме необходимо
пользоваться функциями из
графической библиотеки graphics.h.
Типы видео мониторов и их
режимы
•

Существует много типов мониторов, на каждом из которых
доступны кроме своего режима, и все более низкие режимы.
Под режимом понимается разрешающая способность
количество цветов. Кроме того мониторы делятся по
аппаратной реализации: ЦИФРОВЫЕ и АНАЛОГОВЫЕ.
Инициализация графики
• Функции:
• initgraph(int *GrDr,int *GrMod,char *Path)
;
• i=graphresult() ;
• closegraph() ;
• Функция initgraph(...) инициализирует
графический режим. В параметрах ей передается:
• GrDr - Тип графического монитора, или DETECT Определить максимально возможный. Тип
установленного оборудования возвращается в этих
же переменных (поэтому они и передаются
указателем).
• GrMod - Режим.
• Path - Путь до файлов *.bgi - драйверов графических
режимов. Если указанно " " - то в текущем каталоге.
Пример:
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
int main(void)
{
int GrDr,GrMod,rez ;
GrDr=DETECT ;
initgraph(&GrDr,&GrMod," ") ;
rez=graphresult() ;
if(rez != grOk)
{
printf("n Ошибка инициализации графики") ;
return(1) ;
} /* Кон. if */
line(0,0,100,100) ;
getch() ;
closegraph() ;
return(0) ;
} /* Кон. main() */
Система координат

Основные графические функции
Ниже используются обозначения:
x,y,x1,y1,x2,y2 – координаты;
*St – строка символов;
rx,ry,r – радиусы;
h – толщина изображения;
Alfa1,Alfa2 – углы в градусах;
DX,DY – размеры символа;
Color – цвета.
Функции рисования
Функция

Описание

line(int x1,int y1,int x2,int y2)

Линия

rectangle(int x1,int y1,int x2,int y2)

Прямоугольник

bar(int x1,int y1,int x2,int y2)

Закрашенный прямоугольник

bar3d(int x1,int y1,int x2,int y2,int h)

Закр. прям. с оттененением

ellipse(int x,int y,int rx,int ry)

Эллипс

fillellipse(int x,int y,int rx,int ry)

Закрашенный эллипс

arc(int x,int y,int Alfa1,int Alf2,int r)

Дуга (круг)
Функции рисования
Функция

Описание

outtextxy(int x,int y,char *St)

Вывод строки текста

putpixel(int x,int y,char Color)

Поставить точку

Color=getpixel(int x,int y)

Получить цвет точки

floodfill(int x,int y,char Color)

Залить
цвета

cleardevice()

Очистить экран

clearviewport()

Очистить порт вывода

setviewport(int x1,int int y1)

Установить порт вывода

int x2,int y2,char flg)

flg-вывод за пред. окна

до

границы

указанного
Функции изменения параметров
рисования
Функция

Описание

setcolor(char Color)

Установить цвет рисования

setbkcolor(char Color)

Установить цвет фона

setfillstyle(<Шаблон>,cahr Color)

Установить цвет и стиль закраски
фигур

setlinestyle(<Шаблон>,int Bit,char h) Установить
линий.

стиль

и

толщину
Шаблоны линий
Шаблон

Ном

Изображение

SOLID_LINE

0

Сплошная линия

DOTTED_LINE

1

Линия из точек

CENTER_LINE

2

Centered line

DASHED_LINE

3

Dashed line
Шаблоны закраски
Шаблон

Ном.

Изображение

EMPTY_FILL

0

Цветом фона

SOLID_FILL

1

Выбранным цветом

LINE_FILL

2

---

LTSLASH_FILL

3

///

SLASH_FILL

4

///

BKSLASH_FILL

5



LTBKSLASH_FILL

6



HATCH_FILL

7

Light hatch

XHATCH_FILL

8

Heavy crosshatch

INTERLEAVE_FILL

9

Interleaving line

WIDE_DOT_FILL

10

Точками

CLOSE_DOT_FILL

11

Частыми точками

More Related Content

What's hot

Lession 4-aplikasi-rangkaian-diodarevvv-for-mhs
Lession 4-aplikasi-rangkaian-diodarevvv-for-mhsLession 4-aplikasi-rangkaian-diodarevvv-for-mhs
Lession 4-aplikasi-rangkaian-diodarevvv-for-mhsMarina Natsir
 
2. rpp dan penilaian kd 3.3 fluida statis tekanan hidrostatis
2. rpp dan penilaian kd 3.3  fluida statis tekanan hidrostatis2. rpp dan penilaian kd 3.3  fluida statis tekanan hidrostatis
2. rpp dan penilaian kd 3.3 fluida statis tekanan hidrostatisika kusmiyati
 
magnetostatika.ppt
magnetostatika.pptmagnetostatika.ppt
magnetostatika.pptmuliani7
 
17. sma kelas xii rpp kd 3.10;4.10 inti atom dan radioaktivitas (karlina 1308...
17. sma kelas xii rpp kd 3.10;4.10 inti atom dan radioaktivitas (karlina 1308...17. sma kelas xii rpp kd 3.10;4.10 inti atom dan radioaktivitas (karlina 1308...
17. sma kelas xii rpp kd 3.10;4.10 inti atom dan radioaktivitas (karlina 1308...eli priyatna laidan
 
Materi M5KB2 - Nihon Jijou
Materi M5KB2 - Nihon JijouMateri M5KB2 - Nihon Jijou
Materi M5KB2 - Nihon JijouPPGHybrid1
 
Fisika Kelas XII SMA - Medan Magnet dan Sifat Kemagnetan Bahan
Fisika Kelas XII SMA - Medan Magnet dan Sifat Kemagnetan BahanFisika Kelas XII SMA - Medan Magnet dan Sifat Kemagnetan Bahan
Fisika Kelas XII SMA - Medan Magnet dan Sifat Kemagnetan BahanWa Ode Aisyah Aisyah
 
Ngữ âm tiếng Việt, Đoàn Thiện Thuật, 2016.pdf
Ngữ âm tiếng Việt, Đoàn Thiện Thuật, 2016.pdfNgữ âm tiếng Việt, Đoàn Thiện Thuật, 2016.pdf
Ngữ âm tiếng Việt, Đoàn Thiện Thuật, 2016.pdfMan_Ebook
 
Rumus Fisika Kelas 8
 Rumus Fisika Kelas 8 Rumus Fisika Kelas 8
Rumus Fisika Kelas 8fitria rusadi
 
RPP HUKUM NEWTON
RPP HUKUM NEWTONRPP HUKUM NEWTON
RPP HUKUM NEWTONMAFIA '11
 
Karakteristik Transistor
Karakteristik TransistorKarakteristik Transistor
Karakteristik TransistorRyan Aryoko
 
9. sma kelas x rpp kd 3.6 dan 4.6 elastisitas dan hukum hooke (karlina 130823...
9. sma kelas x rpp kd 3.6 dan 4.6 elastisitas dan hukum hooke (karlina 130823...9. sma kelas x rpp kd 3.6 dan 4.6 elastisitas dan hukum hooke (karlina 130823...
9. sma kelas x rpp kd 3.6 dan 4.6 elastisitas dan hukum hooke (karlina 130823...eli priyatna laidan
 
Termodinamika
TermodinamikaTermodinamika
TermodinamikaStudent
 
Teknologi bahan elektrik
Teknologi bahan elektrikTeknologi bahan elektrik
Teknologi bahan elektrikBanu Yuditya
 

What's hot (20)

Rpp fluida statis
Rpp fluida statisRpp fluida statis
Rpp fluida statis
 
Lession 4-aplikasi-rangkaian-diodarevvv-for-mhs
Lession 4-aplikasi-rangkaian-diodarevvv-for-mhsLession 4-aplikasi-rangkaian-diodarevvv-for-mhs
Lession 4-aplikasi-rangkaian-diodarevvv-for-mhs
 
ppt KWH meter
ppt KWH meterppt KWH meter
ppt KWH meter
 
2. rpp dan penilaian kd 3.3 fluida statis tekanan hidrostatis
2. rpp dan penilaian kd 3.3  fluida statis tekanan hidrostatis2. rpp dan penilaian kd 3.3  fluida statis tekanan hidrostatis
2. rpp dan penilaian kd 3.3 fluida statis tekanan hidrostatis
 
magnetostatika.ppt
magnetostatika.pptmagnetostatika.ppt
magnetostatika.ppt
 
17. sma kelas xii rpp kd 3.10;4.10 inti atom dan radioaktivitas (karlina 1308...
17. sma kelas xii rpp kd 3.10;4.10 inti atom dan radioaktivitas (karlina 1308...17. sma kelas xii rpp kd 3.10;4.10 inti atom dan radioaktivitas (karlina 1308...
17. sma kelas xii rpp kd 3.10;4.10 inti atom dan radioaktivitas (karlina 1308...
 
Materi M5KB2 - Nihon Jijou
Materi M5KB2 - Nihon JijouMateri M5KB2 - Nihon Jijou
Materi M5KB2 - Nihon Jijou
 
Fisika Kelas XII SMA - Medan Magnet dan Sifat Kemagnetan Bahan
Fisika Kelas XII SMA - Medan Magnet dan Sifat Kemagnetan BahanFisika Kelas XII SMA - Medan Magnet dan Sifat Kemagnetan Bahan
Fisika Kelas XII SMA - Medan Magnet dan Sifat Kemagnetan Bahan
 
Ngữ âm tiếng Việt, Đoàn Thiện Thuật, 2016.pdf
Ngữ âm tiếng Việt, Đoàn Thiện Thuật, 2016.pdfNgữ âm tiếng Việt, Đoàn Thiện Thuật, 2016.pdf
Ngữ âm tiếng Việt, Đoàn Thiện Thuật, 2016.pdf
 
3. dioda semikonduktor
3. dioda semikonduktor3. dioda semikonduktor
3. dioda semikonduktor
 
Hukum Archimedes
Hukum ArchimedesHukum Archimedes
Hukum Archimedes
 
Rumus Fisika Kelas 8
 Rumus Fisika Kelas 8 Rumus Fisika Kelas 8
Rumus Fisika Kelas 8
 
Transistor pnp
Transistor pnpTransistor pnp
Transistor pnp
 
RPP HUKUM NEWTON
RPP HUKUM NEWTONRPP HUKUM NEWTON
RPP HUKUM NEWTON
 
Karakteristik Transistor
Karakteristik TransistorKarakteristik Transistor
Karakteristik Transistor
 
9. sma kelas x rpp kd 3.6 dan 4.6 elastisitas dan hukum hooke (karlina 130823...
9. sma kelas x rpp kd 3.6 dan 4.6 elastisitas dan hukum hooke (karlina 130823...9. sma kelas x rpp kd 3.6 dan 4.6 elastisitas dan hukum hooke (karlina 130823...
9. sma kelas x rpp kd 3.6 dan 4.6 elastisitas dan hukum hooke (karlina 130823...
 
Gaya Pegas
Gaya PegasGaya Pegas
Gaya Pegas
 
Termodinamika
TermodinamikaTermodinamika
Termodinamika
 
Teknologi bahan elektrik
Teknologi bahan elektrikTeknologi bahan elektrik
Teknologi bahan elektrik
 
Vektor potensial
Vektor potensialVektor potensial
Vektor potensial
 

Viewers also liked

презентация
презентацияпрезентация
презентацияstudent_kai
 
лекция№34
лекция№34лекция№34
лекция№34student_kai
 
лекция№33
лекция№33лекция№33
лекция№33student_kai
 
лекция №10
лекция №10лекция №10
лекция №10student_kai
 
лекция№32
лекция№32лекция№32
лекция№32student_kai
 
лекция№29
лекция№29лекция№29
лекция№29student_kai
 
слайды кур раб планетар тмм
слайды кур раб планетар тммслайды кур раб планетар тмм
слайды кур раб планетар тммstudent_kai
 
презентации продолжение банкета
презентации продолжение банкетапрезентации продолжение банкета
презентации продолжение банкетаstudent_kai
 
презентация курсовой работы
презентация курсовой работыпрезентация курсовой работы
презентация курсовой работыstudent_kai
 
лекция№31
лекция№31лекция№31
лекция№31student_kai
 
лекция №3и
лекция №3илекция №3и
лекция №3иstudent_kai
 
босс референт (аменицкий)
босс референт (аменицкий)босс референт (аменицкий)
босс референт (аменицкий)student_kai
 
лекция№22
лекция№22лекция№22
лекция№22student_kai
 
презентация 12
презентация 12презентация 12
презентация 12student_kai
 

Viewers also liked (20)

презентация
презентацияпрезентация
презентация
 
лекция 1
лекция 1лекция 1
лекция 1
 
лекция№34
лекция№34лекция№34
лекция№34
 
лекция№33
лекция№33лекция№33
лекция№33
 
L10 sld
L10 sldL10 sld
L10 sld
 
лекция №10
лекция №10лекция №10
лекция №10
 
лекция№32
лекция№32лекция№32
лекция№32
 
лекция№29
лекция№29лекция№29
лекция№29
 
л 15 sld1
л 15  sld1л 15  sld1
л 15 sld1
 
слайды кур раб планетар тмм
слайды кур раб планетар тммслайды кур раб планетар тмм
слайды кур раб планетар тмм
 
презентации продолжение банкета
презентации продолжение банкетапрезентации продолжение банкета
презентации продолжение банкета
 
л 12 sld
л 12  sldл 12  sld
л 12 sld
 
л 14 sld
л 14  sldл 14  sld
л 14 sld
 
презентация курсовой работы
презентация курсовой работыпрезентация курсовой работы
презентация курсовой работы
 
лекция№31
лекция№31лекция№31
лекция№31
 
лекция 4
лекция 4лекция 4
лекция 4
 
лекция №3и
лекция №3илекция №3и
лекция №3и
 
босс референт (аменицкий)
босс референт (аменицкий)босс референт (аменицкий)
босс референт (аменицкий)
 
лекция№22
лекция№22лекция№22
лекция№22
 
презентация 12
презентация 12презентация 12
презентация 12
 

Similar to основы программирования на языке C

Groovy On Grails
Groovy On GrailsGroovy On Grails
Groovy On Grailsguest32215a
 
Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)Mikhail Kurnosov
 
PetrKerzum (Yandex) @ CodeCamp2011
PetrKerzum (Yandex) @ CodeCamp2011PetrKerzum (Yandex) @ CodeCamp2011
PetrKerzum (Yandex) @ CodeCamp2011CodeCamp
 
лабораторная работа №2
лабораторная работа №2лабораторная работа №2
лабораторная работа №2Zhanna Kazakova
 
лабораторная работа №3
лабораторная работа №3лабораторная работа №3
лабораторная работа №3Zhanna Kazakova
 
Программирование Linux
Программирование LinuxПрограммирование Linux
Программирование LinuxAnthony Shoumikhin
 
Программирование Linux
Программирование LinuxПрограммирование Linux
Программирование LinuxAnthony Shoumikhin
 
Программирование Linux
Программирование LinuxПрограммирование Linux
Программирование LinuxAnthony Shoumikhin
 
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияAlexey Paznikov
 
DSLs in Lisp and Clojure
DSLs in Lisp and ClojureDSLs in Lisp and Clojure
DSLs in Lisp and ClojureVasil Remeniuk
 
C language lect_06_introduction
C language lect_06_introductionC language lect_06_introduction
C language lect_06_introductionRoman Brovko
 
5.1 Перегрузка операторов
5.1 Перегрузка операторов5.1 Перегрузка операторов
5.1 Перегрузка операторовDEVTYPE
 
Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Mikhail Kurnosov
 
Михаил Трошев — CSS: Систематизация базовых знаний
Михаил Трошев — CSS: Систематизация базовых знанийМихаил Трошев — CSS: Систематизация базовых знаний
Михаил Трошев — CSS: Систематизация базовых знанийYandex
 
Макс Ширшин — Регулярные выражения
Макс Ширшин — Регулярные выраженияМакс Ширшин — Регулярные выражения
Макс Ширшин — Регулярные выраженияYandex
 

Similar to основы программирования на языке C (20)

лекция 2
лекция 2лекция 2
лекция 2
 
лекция 1
лекция 1лекция 1
лекция 1
 
Groovy On Grails
Groovy On GrailsGroovy On Grails
Groovy On Grails
 
Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)Семинар 4. Многопоточное программирование на OpenMP (часть 4)
Семинар 4. Многопоточное программирование на OpenMP (часть 4)
 
Step cpp022
Step cpp022Step cpp022
Step cpp022
 
PetrKerzum (Yandex) @ CodeCamp2011
PetrKerzum (Yandex) @ CodeCamp2011PetrKerzum (Yandex) @ CodeCamp2011
PetrKerzum (Yandex) @ CodeCamp2011
 
лабораторная работа №2
лабораторная работа №2лабораторная работа №2
лабораторная работа №2
 
лабораторная работа №3
лабораторная работа №3лабораторная работа №3
лабораторная работа №3
 
Lecture 1
Lecture 1Lecture 1
Lecture 1
 
Программирование Linux
Программирование LinuxПрограммирование Linux
Программирование Linux
 
Программирование Linux
Программирование LinuxПрограммирование Linux
Программирование Linux
 
Программирование Linux
Программирование LinuxПрограммирование Linux
Программирование Linux
 
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программированияПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
ПВТ - весна 2015 - Лекция 4. Шаблоны многопоточного программирования
 
DSLs in Lisp and Clojure
DSLs in Lisp and ClojureDSLs in Lisp and Clojure
DSLs in Lisp and Clojure
 
C language lect_06_introduction
C language lect_06_introductionC language lect_06_introduction
C language lect_06_introduction
 
5.1 Перегрузка операторов
5.1 Перегрузка операторов5.1 Перегрузка операторов
5.1 Перегрузка операторов
 
Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)
 
Programming c++ (begin-if-else)
Programming c++ (begin-if-else)Programming c++ (begin-if-else)
Programming c++ (begin-if-else)
 
Михаил Трошев — CSS: Систематизация базовых знаний
Михаил Трошев — CSS: Систематизация базовых знанийМихаил Трошев — CSS: Систематизация базовых знаний
Михаил Трошев — CSS: Систематизация базовых знаний
 
Макс Ширшин — Регулярные выражения
Макс Ширшин — Регулярные выраженияМакс Ширшин — Регулярные выражения
Макс Ширшин — Регулярные выражения
 

More from student_kai

лекция№30
лекция№30лекция№30
лекция№30student_kai
 
лекция№28
лекция№28лекция№28
лекция№28student_kai
 
лекция№27
лекция№27лекция№27
лекция№27student_kai
 
лекция№26
лекция№26лекция№26
лекция№26student_kai
 
лекция№25
лекция№25лекция№25
лекция№25student_kai
 
лекция№25
лекция№25лекция№25
лекция№25student_kai
 
лекция№24
лекция№24лекция№24
лекция№24student_kai
 
лекция№23
лекция№23лекция№23
лекция№23student_kai
 
лекция№21
лекция№21лекция№21
лекция№21student_kai
 
лекция№20
лекция№20лекция№20
лекция№20student_kai
 
лекция№19
лекция№19лекция№19
лекция№19student_kai
 
лекция№18
лекция№18лекция№18
лекция№18student_kai
 
лекция№17
лекция№17лекция№17
лекция№17student_kai
 
лекция№16
лекция№16лекция№16
лекция№16student_kai
 
лекция№15
лекция№15лекция№15
лекция№15student_kai
 
лекция№14
лекция№14лекция№14
лекция№14student_kai
 
лекция№13
лекция№13лекция№13
лекция№13student_kai
 
лекция№11
лекция№11лекция№11
лекция№11student_kai
 
лекция№10
лекция№10лекция№10
лекция№10student_kai
 
лекция№9
лекция№9лекция№9
лекция№9student_kai
 

More from student_kai (20)

лекция№30
лекция№30лекция№30
лекция№30
 
лекция№28
лекция№28лекция№28
лекция№28
 
лекция№27
лекция№27лекция№27
лекция№27
 
лекция№26
лекция№26лекция№26
лекция№26
 
лекция№25
лекция№25лекция№25
лекция№25
 
лекция№25
лекция№25лекция№25
лекция№25
 
лекция№24
лекция№24лекция№24
лекция№24
 
лекция№23
лекция№23лекция№23
лекция№23
 
лекция№21
лекция№21лекция№21
лекция№21
 
лекция№20
лекция№20лекция№20
лекция№20
 
лекция№19
лекция№19лекция№19
лекция№19
 
лекция№18
лекция№18лекция№18
лекция№18
 
лекция№17
лекция№17лекция№17
лекция№17
 
лекция№16
лекция№16лекция№16
лекция№16
 
лекция№15
лекция№15лекция№15
лекция№15
 
лекция№14
лекция№14лекция№14
лекция№14
 
лекция№13
лекция№13лекция№13
лекция№13
 
лекция№11
лекция№11лекция№11
лекция№11
 
лекция№10
лекция№10лекция№10
лекция№10
 
лекция№9
лекция№9лекция№9
лекция№9
 

основы программирования на языке C

  • 1. ОСНОВЫ ПРОГРАММИРОВАНИЯ НА ЯЗЫКЕ C (Программирование на языке высокого уровня, часть 2) Комплексное учебное пособие
  • 2. Пример простой программы /* Сложение двух целых чисел */ #include <stdio.h> main () { int a, b; /* объявление целочисленных переменных а и b */ printf ("Задайте два числа: "); /* вывод сообщения */ scanf ("%d %d", &a, &b); /* ввод значений а и b */ printf ("%d + %d = %dn", a, b, a+b); /* вывод результата */ return 0; }
  • 3. Более сложный пример #include <stdio.h> #include <stdlib.h> #define PROMPT ':' main() { float a,b,rez; char oper; while(putch(PROMPT),scanf("%f%c%f",&a,&oper,&b)!=EOF) { switch (oper) { case '+': rez=a+b; break; case '-': rez=a-b; break; case '*': rez=a*b; break; case '/': rez=a/b; break; default: printf("Ошибка!n"); exit(1); } printf("Результат:%fn",rez) } }
  • 4. Объявление переменных и основные типы данных Имя (идентификатор) - это последовательность латинских букв и цифр, начинающаяся с буквы. Можно использовать в имени символы подчеркивания вместо пробелов, когда имя состоит из нескольких слов.
  • 5. Примеры описаний переменных: float x,y,z; */ double x1,x2; точности*/ char simv; int i,j; long summa; short k1,k2; unsigned count; число */ /* вещественные числа /* вещ. числа двойной /* /* /* /* /* символ */ целые числа */ длинное целое */ короткие целые */ беззнаковое целое (неотрицательное)
  • 6. Ввод/вывод с помощью функций printf() и scanf(). Формат Тип вводимой информации %d Десятичное целое число %c Один символ %s Строка символов %e Число с плавающей точкой, экспоненциальная запись %f Число с плавающей точкой, десятичная запись %g Используется вместо записей %f или %e,если он короче %u Десятичное целое без знака %o Восьмеричное целое без знака %x Шестнадцатиричное целое число без знака
  • 7. Пример pi=3.14159; e=2.718282; printf(“число pi=%f ; число e= %f;n”,pi,e); /*результат следующий */ число pi=3.14159; число e=2.71828; или printf(“число p=%f; число e=%f; число pi+e=%f! n”,pi,e,pi+e); /*результат */ число pi=3.14159; число e=2.71828 ; число pi+e=5.85987!
  • 8. Модификаторы спецификаций преобразования используемые в функции printf() К модификаторам относятся: 1)Знак минус - при этом аргумент будет печататься с левой позиции поля заданной ширины. Обычно печать аргумента оканчивается в самой правой позиции поля. Пример %-10в. 2)Строка цифр – задает минимальную ширину поля. При этом, если информация не помещается в указанную ширину поля, то ширина поля увеличивается до необходимых размеров. 3)Строка цифр – определяет точность: для типов данных с плавающей точкой – число печатаемых цифр справа от десятичной точки; для символьных строк – максимальное число печатаемых символов. Пример %4.2f – две десятичные цифры для поля шириной в четыре символа.
  • 9. Влияние модификаторов преобразования на печать целого числа: main() { printf(“/%d/n”,625); printf(“/%2d/n”,625); printf(“/%10d/n”,625); printf(“/%-10d/n”,625); } Печать будет следующей: /625/ /625/ / 625/ /625 /
  • 10. Для чисел с плавающей точкой: main() { printf(“/%f/n”,1234.56); printf(“/e/n”,1234.56); printf(“/4.2f/n”,1234.56); printf(“/%3.1f/n”,1234.56); printf(“/%10.3f/n”,1234.56); printf(“/%10.3e/n”,1234.56); } Результат будет следующим: /1234.560059/ /1.234560Е+03/ /1234.56/ /1234.6/ / 1234.560/ / 1.234Е+03/
  • 11. Рассмотрим варианты строк: # define const “КГТУ – пуп земли!” /*здесь 15 символов, включая пробелы*/ main() { printf(“/%2s/n”,const); printf(“/%17.s/n”,const); printf(“%20.4s/n”,const); printf(“%-20.4/n”,const); } /КГТУ – пуп земли!/ / КГТУ – пуп земли!/ / КГТУ/ /КГТУ /
  • 12. Функцию printf() можно использовать для преобразования данных. Пример printf(“%dn”,625); printf(“%on”,625); printf(“%xn”,625); printf(“%dn”,-625); printf(“%un”,-625); 54911(=65536-625) 625 1161 271 -625
  • 13. Применение функции scanf() Рассмотрим пример: main() { int vozrast; float rost; char sobaka[20]; printf(“Укажите ваш возраст, рост в метрах и любимую породу собак”); scanf(“%d%f”, &vozrast,&rost); scanf(“%s”,sobaka); /*отсутствует &*/ printf(“%d %4.2f %sn”,vosrast,rost,sobaka); } Ввод 25 1.72 /*Можно вводить в каждой строке, т.е.25*/ ризеншнауцер /* 1.72*/ /* ризеншнауцер*/ Печать 25 1.72 ризеншнауцер
  • 14. Операции Под операцией понимают некоторое действие, которое может быть выполнено над одним или несколькими операндами для получения результата. Операции и операнды могут объединяться в выражение. Каждое выражение вычисляется с учетом особенностей составляющих его операций и их приоритетов. В результате вычисляется значение выражения.
  • 15. Простейшие арифметические операции Примеры выражений с арифметическими операциями: a + b%c (a + b)/3*5 Операция присваивания Пример: ab = ( c = d+5 ) * 6 Оператор-выражение Пример: ab = ( c = d + 5 ) * 6; /* это оператор */
  • 16. Использование в выражениях операндов разных типов Пример: int a, c; float d, e; e = d*(c+e); преобразовано в a = 'A' + 20; преобразовано в /* c будет float */ /* 'A' будет int */
  • 17. Операции преобразования типов В некоторых случаях правила преобразования типов не позволяют получить верный результат, например: int a, b; float c; a = 7; b = 14; c = a/b; /* результат 0 */ Для получения правильного результата можно поступить так c = a; c = c/b;
  • 18. Явное преобразование типов: (<имя_типа>) <выражение> имя_типа - название любого типа, в том числе и заданного программистом. Для нашего примера применение операции преобразования типа будет выглядеть так: c = (float)a / (float)b;
  • 19. Дополнительные арифметические операции a = a + 1; эквивалентно a++; или ++a; a = 4; b = ( a++ ) * 5; /* здесь b = 20 */ a = 4; b = ( ++ a ) * 5; /* здесь b = 25 */
  • 20. Дополнительные операции присваивания a = a + b; a = a - b; a = a * b; a = a / b; Дополнительные операторы присваивания: a += b; a -= b; a *= b; a /= b; a %= b;
  • 21. Операции отношения > больше, < меньше, >= больше или равно, <= меньше или равно, == равно, != не равно. Например: int a,b; a = 5; b = ( a + 5 <= 4 ); /* b = 0 */
  • 22. Логические операции ! логическое отрицание (одноместная), && логическое "и" (двуместная), || логическое "или" (двуместная).
  • 23. Результаты логических операций op1 op2 !op1 op1 && op2 op1 || op2 0 0 не 0 (1) 0 0 0 не 0 (1) не 0 (1) 0 не 0 (1) не 0 (1 ) 0 0 0 не 0 (1) не 0 (1 ) не 0 (1) 0 не 0 (1) не 0 (1)
  • 24. → ← Таблица приоритетов рассмотренных выше операций Операции одного приоритета ! ~ ++ * / % + - << < -- (тип) Направление выполнения операции. ← → → >> <= → > >= →
  • 25. ← Таблица приоритетов рассмотренных выше операций Операции одного приоритета == != & ^ | Направление выполнения операции. → → → → && → || → = *= /= %= += -= <<= >>= &= ^= |= ←
  • 26. Операторы Условный оператор Ветвление в простейшем случае описывается в языке Си с помощью условного оператора, имеющего вид: if ( выражение ) оператор_1; else оператор_2; где часть else может и отсутствовать. Сначала вычисляется "выражение" в скобках; если оно истинно то выполняется оператор_1. Если "выражение" ложно (равно нулю - NULL), то оператор_1 пропускается, а выполняется оператор_2. Если на месте условно выполняемых операторов должна располагаться группа из нескольких операторов языка, то они заключаются в фигурные скобки - { }. Часто "выражение" в скобках представляет условие, заданное с помощью операций отношений и логических операций.
  • 27. Пример 1 #include <stdio.h> main() { /* главная функция*/ int x, y, z, max ; /* описание переменных*/ printf(" Введите три числа :n "); scanf(" %d %d %d ", &x, &y, &z); /*ввод трех чисел*/ if( x > y) /*операции сравнивания*/ max=x; else max=y; if ( z>max) max=z; printf(" Максимальное из (%d, %d, %d)= %d n",x, y, z, max); }
  • 28. Пример 2 /*РЕШЕНИЕ УРАВНЕНИЯ AX=B*/ #include <stdio.h> main() { float A,B,X; printf("ВВЕДИ А, Вn"); scanf("%f %f",&A, &B); if(A!=0) printf("РЕШЕНИЕ:%fn", B/A); else if(B==0) printf("X-ЛЮБОЕ ЧИСЛОn"); else printf("РЕШЕНИЙ НЕТn"); }
  • 29. Пример 3 /* Програииа определяет поведение ракеты, стартующей на экваторе, в зависимости от ее начальной скорости*/ #include <stdio.h> main() { float V; printf("ВВЕДИ Vn"); scanf("%f",&V); if(V<7.9) printf("РАКЕТА УПАДЕТ НА ЗЕМЛЮn"); if(V<11.2) printf("РАКЕТА СТАНЕТ СПУТНИКОМ ЗЕМЛИn "); if(V<16.4) printf("РАКЕТА СТАНЕТ СПУТНИКОМ СОЛНЦАn"); else printf("РАКЕТА ПОКИНЕТ СОЛНЕЧНУЮ СИСТЕМУn"); }
  • 30. Оператор switch Оператор switch предназначен для организации выбора из множества различных вариантов. Формат оператора следующий: switch ( выражение ) { [объявление] : [ case константное-выражение1]: [ списокоператоров1] [ case константноевыражение2]: [ список-операторов2] : : [ default: [ список операторов ]] }
  • 31. Для того, чтобы выполнить одни и те же действия для различных значений выражения, можно пометить один и тот же оператор несколькими ключевыми словами case. Пример: int i=2; switch (i) { case 1: i += 2; case 2: i *= 3; case 0: i /= 2; case 4: i -= 5; default: ; }
  • 32. Рассмотрим ранее приведенный пример, в котором иллюстрировалось использование вложенных операторов if, переписанной теперь с использованием оператора switch. char ZNAC; int x,y,z; switch (ZNAC) { case '+': x break; case '-': x break; case '*': x break; case '/': x break; default : ; } = y + z; = y - z; = y * z; = u / z;
  • 33. Оператор break Оператор break обеспечивает прекращение выполнения самого внутреннего из объединяющих его операторов switch, do, for, while. После выполнения оператора break управление передается оператору, следующему за прерванным.
  • 34. Циклы Для выполнения повторяющихся операций в языке Си предусмотрены три вида циклов: while, do…while и for. Цикл while называют циклом с предусловием и записывают следующим образом: while (<выражение>) <оператор>;
  • 35. Пример программы, которая выводит на экран таблицу функций sin(x) и cos(x): #include <math.h> #include <stdio.h> void main( void ) { double x = 0; while( x < 3.0 ) { printf( "%6.3lf %9.6lf %9.6lfn",x, sin(x), cos(x) ); x += 0.2; } }
  • 36. Цикл do…while называют циклом с постусловием и записывают следующим образом: do <оператор>; while (<выражение>);
  • 37. Пример оператора do while: /* вычисление суммы n вещественных чисел */ s = 0; i = 1; do { scanf(“%f”, &x); s = s + x ; i++; } while (i <= n) ;
  • 38. При использовании цикла for инициализация переменных и их изменение указывается в самом цикле. Записывается это следующим образом: for ([<выражение1>];[<выражение2>]; [<выражение3>]) <оператор>; Здесь <выражение1> – необязательная часть оператора, которая обычно используется для задания начальных значений переменным цикла; <выражение2> – необязательная часть оператора, которая задаёт условие выполнения цикла; <выражение3> – необязательная часть оператора, которая обычно используется для изменения значений переменных цикла.
  • 39. Оператор continue Оператор continue, как и оператор break, используется только внутри операторов цикла, но в отличие от него выполнение программы продолжается не с оператора, следующего за прерванным оператором, а с начала прерванного оператора. Формат оператора следующий: continue;
  • 40. Пример int main() { int a,b; for (a=1,b=0; a<100; b+=a,a++) { if (b%2) continue; ... /* обработка четных сумм } return 0; } */
  • 41. Оператор goto Использование оператора безусловного перехода goto в практике программирования на языке СИ настоятельно не рекомендуется, так как он затрудняет понимание программ и возможность их модификаций. Формат этого оператора следующий: goto имя-метки; ... имя-метки: оператор;
  • 42. Оператор вызова функции Оператор вызова функции имеет вид: имя_функции (аргумент1, ... , аргументN);
  • 43. Обработка числовых последовательностей На языке С процесс обработки можно записать с помощью оператора цикла while или лучше оператора цикла for: а) scanf ("%d", &n); i=1; while (i<=n) { scanf ("%f", &a); /* обработка a */ ... i++; } б) scanf ("%d", &n); for (i=1; i<=n; i++) { scanf ("%f", &a); /* обработка a */ ... }
  • 44. а) scanf ("%f", &a); do { /* обработка a */ ... scanf ("%f", &a); } while (a!=W); б) scanf ("%f", &a); while (a!=W) { /* обработка a */ ... scanf ("%f", &a); }
  • 45. Пример1 • #include <stdio.h> • #include <math.h> • main() • { • int n; /* количество чисел */ • int a, /* очередное число */ • s=0, /* сумма */ • i; /* порядковый номер числа в последовательностити */ • printf ("nВведите количество чисел: "); • scanf ("%d", &n); • printf ("Введите числовую последовательность:n"); • for (i=1; i<=n; i++) • { • scanf ("%d", &a); • if (abs(a) < i*i) s=s+a; • } • printf ("сумма=%dn", s); • return 0; • }
  • 46. Результаты тестирования программы в примере1: • Введите количество чисел: 6 • Введите числовую последовательность: • 1 -2 3 16 -5 40 • сумма=-4 • Введите количество чисел: 4 • Введите числовую последовательность: • -1 5 10 -20 • сумма=0
  • 47. Пример2 •#include <stdio.h> •#define W 0 /* признак конца последовательности */ •main( ) •{ •float a, /* текущее число */ • s = 0; /* сумма чисел */ •int n = 0; /* количество чисел */ •printf("n Введите последовательность чисел, заканчивающуюся нулемn"); •scanf ("%f", &a); •while (a != W) •{ s += a; • n++; • scanf("%f", &a); •} •if (n != 0) •{ printf ("Сумма = %.2fn", s); • printf ("Среднее арифметическое = %.2fn ", s/n); •} •else printf ("Пустая последовательность"); • return 0; •}
  • 48. Результаты тестирования программы в примере2: •Введите последовательность чисел, заканчивающуюся нулем •2 3.5 1.5 5 0 •Сумма = 12.00 •Среднее арифметическое = 3.00 •Введите последовательность чисел, заканчивающуюся нулем •0 •Пустая последовательность
  • 49. Пример3 •/* Определение максимального элемента */ •/* числовой последовательности */ •#include <stdio.h> •main( ) •{ float a, max; /* Текущее число, текущий максимум */ • int k; /* Количество введенных чисел */ •printf ("nВведите последовательность чиселn"); •k = scanf("%f", &max); /* ввод 1-го числа */ •if (k < 1) printf ("nВходная последовательность пустаn"); •else •{ while (scanf("%f", &x) != EOF ) • if (x > max) max = x; • printf ("nМаксимум= %fn", max); •} • return 0; •}
  • 50. Пример4 • • • • • • • • • • • • • • • #include <stdio.h> main( ) { float apred, a; */ int flag = 1; */ /* предыдущее и текущее /* числа признак знакочередования /* flag=1- знаки чередуются, 0 – нет */ printf ("nВведите последовательность чиселn"); scanf("%f", &apred); while( scanf("%f", &a)>0) { if (apred * a >= 0) flag = 0; apred = a; } if (flag) printf ("Знаки чередуются."); else printf ("Знаки не чередуются."); return 0; }
  • 51. Последовательная обработка символьных данных • • • • • • • • • • • • • • • • • • • Примеры символьных констант: ‘*’ ‘a’ ‘5’ ‘n’ Специальные (управляющие) символьные константы: 'n' новая строка (new line), 't' 'v' табуляция горизонтальная, вертикальная, 'b' возврат на шаг (backspace), '' - (обратный слэш) ''' ' (апостроф) '"' - " (кавычка), '0' нуль-символ (байт с нулевым кодом). Кодировка цифровых символов (символ и его числовой код): '0' = 48 '1' = '0' + 1 = 49 '2' = '0' + 2 = 50 . . . '9' = '0' + 9 = 57 Отсюда соотношения: Код цифры = '0' + Значение цифры Значение цифры = Код цифры - '0'
  • 52. Последовательная обработка символов • Пример Вывести коды введенных с клавиатуры символов. Последовательность символов завершается нажатием клавиши Enter. • • • • • • • • • • /* Коды символов */ #include <stdio.h> #include <conio.h> main() { char sim; /* очередной символ */ printf("n Введите строку символовn"); while((sim=getchar()) != 'n') printf("%c = %d, ", sim, sim); printf("nНажмите любую клавишу"); getch(); /* чтение кода нажатой клавиши без отображения символа • на экране*/ • return 0; • Оператор while в программе можно записать иначе – с использованием функции putchar(): • while((sim=getchar()) != 'n') • { putchar(sim); • printf(" = %d, ", sim); • } •
  • 53. Пример Дан текст произвольной длины, оканчивающийся точкой. Проверить, есть ли в тексте сочетания "ВА". • • • • • • • • • • • • • • • • • • • • • #include main() { char char short <stdio.h> /* текущий символ текста */ /* предыдущий символ */ /* признак, имеется ли "ВА" в тексте */ /* net=1, если "ВА" нет */ /* net=0, если "ВА" есть */ printf ("nВведите текст.n"); s=getchar(); /* чтение первого символа */ if (s!='.') { do { prs=s; s=getchar(); if (prs=='В' && s=='А') net=0; } while (s!='.'); } if (net) printf ("В тексте нет 'ВА'.n"); else printf ("В тексте есть 'ВА'.n"); return 0; } s; prs; net=1;
  • 54. Обработка массивов Массивы • Массив - упорядоченная последовательность пронумерованных элементов одинакового типа. • Индекс - номер элемента массива. Индексы элементов массива начинаются с нуля. Элемент массива может иметь несколько индексов. Размерность массива - количество индексов каждого элемента. • Вектор - одномерный массив (один индекс). • Матрица – двумерный массив (первый индекс - номер строки, второй - номер столбца).
  • 55. Язык Си не имеет встроенных средств для вводавывода массива целиком, поэтому массив вводят и выводят поэлементно с помощью циклов, как, например, в следующей программе: • • • • • • • • • • • • • • #include <stdio.h> void main(void) { 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]); } /* Операторы, обрабатывающие массив */ }
  • 56. Подсчет числа элементов, вводимого массива, при этом ввод завершается при появлении во входном потоке признака конца данных. Таким признаком в следующей программе служит число большее 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"); }
  • 57. Использование и обработка массивов • Примеры: • int a[2][3]; /* представлено в виде матрицы • a[0][0] a[0][1] a[0][2] • a[1][0] a[1][1] a[1][2] */ • double b[10]; /* вектор из 10 элементов имеющих тип double */ • int w[3][3] = { { 2, 3, 4 }, • { 3, 4, 8 }, • { 1, 0, 9 } }; • В последнем примере объявлен массив w[3][3]. Списки, выделенные в фигурные скобки, соответствуют строкам массива, в случае отсутствия скобок инициализация будет выполнена неправильно.
  • 58. • Примеры: • int s[2][3]; • Если при обращении к некоторой функции написать s[0], то будет передаваться нулевая строка массива s. • int b[2][3][4]; • Пример объявления символьного массива. • char str[] = "объявление символьного массива";
  • 59. Пример1 • /*обращение массива*/ #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) { p=a[i]; a[i]=a[9-i]; a[9-i]=p; i++; } i=0; while(i<10) printf(" %d",a[i++]); }
  • 60. Пример2 • /*в массиве найти разность мин. и макс. элементов */ 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); }
  • 61. Пример2 • #include <stdio.h> main() { static int a[10]= {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("макс-мин=%dn",max+min); }
  • 62. Пример3 • /*макс одинаковых подряд*/ #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=%dn",(k>max)?k:max); }
  • 63. Пример4 • #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"); } }
  • 64. Пример5 • /*обмен мин с диагональю*/ #include <stdio.h> #define M 4 main() { static a[M][M]={ { 3,4,1,5), {-1,6,7,0}, { 1,8,7,-1}, { 4,9,7,-1}}; int i, j, jmin, amin; i=0;
  • 67. Указатели •Язык Си имеет средства работы непосредственно с областями оперативной памяти ЭВМ, задаваемыми их адресами (указателями). В языке C указатели строго типизированы, т. е. различают указатели (адреса) символьных, целых, вещественных величин, а также типов данных, создаваемых программистом.
  • 68. Для указателей одного и того же типа допустимой является операция присваивания, кроме того указателю типа void может быть присвоено значение адреса данного любого типа, но не наоборот, например •int *a, *b; •double *d; •void *v; •... •a = b; /* Правильно */ •v = a; /* Правильно */ •v = d; /* Правильно */ •b = v; /* Неправильно */ •d = a; /* Неправильно */
  • 69. Для поддержки адресной арифметики в языке Си имеются две специальные операции - операция взятия адреса & и операция получения значения по заданному адресу * (операция разадресации). •Рассмотрим работу вышеописанных операций на следующем примере •int *p, a, •double d; •void *pd; •p = &a; •*p = 12; •p = &b; •*p = 20; •/* Здесь a •pd = &d; •*( (double •/* Здесь d b; содержит число 12, b - число 20 */ *) pd ) = a; содержит число 12.0 */
  • 70. Состояние ячеек до первого присваивания P, адрес 1000 a, адрес 2000 b, адрес 4000 мусор мусор мусор Состояние ячеек после присваивания p = &a p, адрес 1000 a, адрес 2000 b, адрес 4000 2000 мусор мусор
  • 71. Состояние ячеек после присваивания *p = 12 p, адрес 1000 a, адрес 2000 b, адрес 4000 2000 12 мусор Состояние ячеек после присваивания p = &b p, адрес 1000 a, адрес 2000 b, адрес 4000 4000 12 мусор
  • 72. Состояние ячеек после присваивания *p = 20 p, адрес 1000 a, адрес 2000 b, адрес 4000 4000 12 20
  • 73. Следует также опасаться случая, когда указатель содержит адрес объекта программы, завершившего свое существование. Например, результат работы следующей программы неверен и непредсказуем: •#include <stdio.h> •#include <math.h> •double * Cube(double x) •{ • double cube_val; • cube_val = x*x*x; • return &cube_val; •} •void main(void) •{ • double *py; • py = Cube(5); • printf("y1 = %lfn", *py); • sin(0.7); • printf("y1 = %lfn", *py); •}
  • 74. Динамическое выделение памяти • Данные, которые создаются, инициализируются и уничтожаются по требованию программиста называются динамическими. Для управления такими данными используются специальные стандартные функции, прототипы которых описаны в заголовочном файле <malloc.h> (для некоторых компиляторов <alloc.h>). • Для запроса динамической памяти служит функция malloc(), которая имеет следующий прототип: • void * malloc(size_t size);
  • 75. Статические и динамические массивы • int n; • int *m; /* указатель (ссылка) */ • scanf(“%d”, &n); • m = (int *) malloc ( n * sizeof(int));/* выделение памяти */ • if (m == NULL) { printf( “No memory”); return 1;}/* ошибка */ • for (int i = 0; i < n; i++) • scanf(“%d”, &m[i]); • … • free (m); /* освобождение памяти */ • return 0; /* успешное завершение */
  • 76. Типичная последовательность действий при работе с динамической памятью: •double *A; int n; • ... • n = 200; • ... • A = (double *) malloc( n * sizeof(double) ); • ... • /* Работа с массивом A */ • ... • free(A);
  • 77. Подпрограммы • Подпрограмма - это программа, которая выполняется в составе одной или нескольких программ. В сложных программах в виде подпрограммы чаще всего определяют функционально самостоятельный фрагмент алгоритма, который возможно используется неоднократно.
  • 78. • Вызов подпрограммы (команда «выполнить подпрограмму») записывается аналогично использованию математической функции: • f(a1, a2, ... , an) • где f - имя подпрограммы (аналогично имени функции P), a1, a2, ... , an - аргументы вызова (фактические параметры), конкретные величины, подставляемые вместо формальных параметров при выполнении подпрограммы (как аргумент 10 при вычислении значения функции P). • Формальный параметр – это входная или выходная переменная подпрограммы, указанная в заголовке ее определения (как x в левой части определения функции P(x)).
  • 79. • Определение функции имеет вид: • <Заголовок_ функции> • { <Объявление переменных функции> // тело • <Операторы функции> // функции • } • Заголовок функции имеет вид: • <тип значения> <имя функции> ([<тип> <имя>[,<тип> <имя>] …]) • Если функция не обладает значением, в качестве типа значения пишется ключевое слово void. Тип значения функции разрешается не указывать. В этом случае (по умолчанию) подразумевается тип int.
  • 80. • Выполнение подпрограммы завершается при выполнении оператора возврата или достижении конца тела функции. • Оператор возврата имеет вид: • return [<выражение>]; • В теле функции, обладающей значением, обязательно должен быть оператор возврата, где тип вычисленного выражения должен соответствовать типу значения функции. Значение выражения становится значением функции: оно передается в вызывающую программу и подставляется вместо вызова функции. Оператор возврата вида return; (без выражения) осуществляет возврат в вызывающую программу в точку, следующую за вызовом подпрограммы. Если функция не возвращает значение, оператор возврата может отсутствовать.
  • 81. • Вызов подпрограммы, т.е. команда для выполнения подпрограммы имеет вид: • <имя функции> ([<имя> [,<имя>] …]) • При вызове подпрограммы (в скобках) определяются имена фактических параметров (аргументы вызова). Фактические параметры подставляются вместо формальных параметров при выполнении подпрограммы. • Вызов функции, обладающей значением (возвращающей значение), в операторе присваивания: • <имя переменной> = …]); <имя функции> ([<имя> [, <имя>]
  • 82. • Пример описания функции: • /* функция определения наибольшего из двух чисел */ • float max ( float x, float y ) • { if (x>y) return x; • else return y; • } • Пример вызова функции: • f = max(a,b) - max(a+b,c); • содержит два вызова приведенной выше функции max. При первом обращении функции max передаются значения переменных a и b, она возвращает наибольшее из этих чисел, которое подставляется вместо указателя функции max(a,b). При втором вызове функции max формальным параметрам x и y присваиваются соответственно значения фактических параметров a+b и c. Оператор return возвращает наибольшее из этих
  • 83. Параметры подпрограмм • При вызове подпрограммы происходит согласование параметров: • - порядок и типы формальных параметров в объявлении и определении подпрограммы должны совпадать с порядком и типами фактических параметров при вызове подпрограммы. • После вызова подпрограммы выполняются ее операторы, где фактические параметры подставляются вместо формальных параметров. • Передача параметров и согласование формальных и фактических параметров может осуществляться • по значению; • по ссылке (по адресу).
  • 84. Передача параметров по значению • При передаче параметра по значению фактический параметр может быть выражением, в частном случае переменной или константой. Формальному параметру присваивается значение выражения, тип которого должен совпадать с типом формального параметра. В подпрограмме используется только значение фактического параметра, любые изменения параметра в подпрограмме не влияют на его значение в вызывающей программе. Таким способом можно передавать только входные параметры, т.е. можно передать данные от вызывающей программы к подпрограмме.
  • 85. Передача параметров по ссылке. • При передаче параметра по ссылке фактический параметр может быть только переменной, тип которой должен совпадать с типом формального параметра. Передается не значение фактического параметра, а его адрес. При выполнении подпрограммы фактический параметр заменяет формальный параметр, действия выполняются над фактическим параметром. Изменения параметра в подпрограмме меняют его значение в вызывающей программе. Таким способом можно передавать и входные, и выходные параметры, т.е. можно передать данные от вызывающей программы к подпрограмме и в обратном направлении.
  • 86. Область действия переменных • Локальные переменные. Переменные, объявленные в теле функции, являются локальными переменными этой функции. Формальные параметры подпрограммы, также считаются локальными для этой подпрограммы. Областью действия локальной переменной является блок, в котором эта переменная объявлена. • Глобальные переменные. Глобальные переменные объявляются до всех функций или между определениями функций. Областью действия глобальной переменной является вся программа.
  • 87. Пример • • • • • • • • • • • • • • • • • • • • • /* Вариант Б. Вычисление c=n!/(m!*(m-n)!) */ /* с помощью функции, возвращающей значение */ #include <stdio.h> long fakt (int k); /* прототип функции */ /* Вычисление c = n! / (m! * (n-m)!) */ void main(void) { int n, m, c; /* исходные данные и результат */ printf("nВведите два исходных целых числа "); scanf("%d %d", &n, &m); c = fakt(n) / (fakt (m) * fakt (n-m)); printf ("n c = %d", c); } /* Функция k! */ long fakt (int k) { long f; /* k! */ int j; /* текущий множитель */ f=1; for (j=2; j<=k; j++) f = f * j; return f; /* значение функции */ }
  • 88. Пример • • • • • • • • • • • • • • • • • • #include <stdio.h> int KolLatBukv (char s[]) { int i, /* индекс очередного символа строки s */ k=0;/* количество лат. букв */ for ( i = 0; s[i] != '0'; i++ ) if(s[i]>='a'&&s[i]<='z'||s[i]>='A'&&s[i]<='Z') k++; return k; } void main() { char s1[81], s2[81]; /* заданные строки */ printf ("nВведите две строки символовn"); gets (s1); gets (s2); printf ("В 1-й строке %d лат. буквn", KolLatBukv (s1)); printf ("Во 2-й строке %d лат. буквn", KolLatBukv (s2)); }
  • 89. Пример результата выполнения программы: • Введите две строки символов • AaBbcd 123 Zz • t = x + y * z / 10 ; • В 1-й строке 8 лат. букв • Во 2-й строке 4 лат. букв
  • 90. Пример • • • • • • • • • • • • • #include <stdio.h> void SumPos (float m[], int n, float *s, int *k) /* Вх. параметры: m – указатель на заданный массив, n – число элементов массива. Вых. параметры: *s – сумма положительных элементов массива, *k – количество положительных элементов */ { int i; for (i=0, *s=0, *k=0; i<n; i++) if (m[i] > 0) (*s) += m[i], (*k)++; }
  • 91. Пример • void main() • { • float a[6], /* массив */ • s; /* сумма положительных элементов */ • int k, /* количество положительных эл-тов */ • i; /* индекс элемента массива*/ • printf ("nВведите 6 чиселn"); • for ( i=0; i < 6; i++) scanf ("%d ", &a[i] ); • SumPos (a, 6, &s, &k); /* вызов функции */ • printf ("Сумма положительных чисел = %fn", s); • printf ("Количество положительных чисел: %dn", k); • }
  • 92. Рекурсивные функции •Рекурсивная функция – это функция, в определении которой есть обращение к себе самой. •Пример. Допустим, нужно вычислить n! (факториал числа n). Значение n! можно представить как произведение n на факториал (n-1) : •n! = n*(n-1)! •(n-1)! = (n-1)*(n-2)! •…
  • 93. Пример • /* Рекурсивная функция вычисления n! */ •float fact (int n) •{ if (n<0) • { puts (“Недопустимый аргумент функции fact”); • exit (1); /* завершение выполнения программы */ • } • if (n==1 || n==0) return 1; • return n*fact(n-1); •}
  • 94. Пример вызова этой функции: •int k; •scanf (“%d”, &k); •printf (“%d! = %.0f”, k, fact(k));
  • 96. Символьные строки и функции обработки строк • Символьная строка представляет собой последовательность символов, заканчивающуюся нуль-символом (‘0’ c кодом 0). • Строковые константы заключаются в кавычки. При компиляции программы они автоматически дополняются нуль-символом. Строковые переменные объявляются как массивы символов, например: • char str[81]; • char error[] = “Ошибка”; • /* массив из 7 символов, включая ‘0’ */
  • 97. • Для ввода с клавиатуры строки символов служит библиотечная функция gets(), а для вывода – функция puts(). • Пример: • char s1[81], s2[81]; • • • • • char puts puts gets gets *s3 = “Привет!”; (s3); (“Введите две строки”); (s1); (s2);
  • 98. • В библиотеках Turbo C, Borland C++ имеется ряд функций обработки строк: • - определения длины строки (strlen), • - сравнения строк (strcmp, strncmp), • - копирования строк (strcpy, strncpy), • - сцепления строк (strcat, strncat), • - поиска символа в строке (strchr, strrchr, strpbrk), • - поиска подстроки в строке (strstr). • При их использовании в программу необходимо включить заголовочный файл string.h, содержащий объявления этих функций.
  • 99. • • • • • • • • • • • • • • Рассмотрим одну из библиотечных функций - функцию сцепления двух заданных строк strcat(). Определение функции: char *strcat (char *s1, char *s2); Функция копирует строку s2 (на которую ссылается указатель s2) в конец строки s1 и возвращает значение s1 - ссылку на сцепленную строку. Работу функции можно описать так: char *strcat (char *s1, char *s2) { char *rs; /* ссылка на результирующую строку */ rs=s1; /* запоминание адреса начала строки s1 */ while (*s1!='0') s1++; /* поиск конца строки s1 */ /* копирование строки s2 в конец s1 */ while (*s2!='0') { *s1=*s2; s1++; s2++; } *s1='0'; return rs; }
  • 100. • А теперь посмотрите на более компактную (но менее понятную) запись этой функции: • char *strcat (char *s1, char *s2) • { char *rs; • rs=s1; /* запоминание адреса начала строки s1 */ • while (*s1!='0') s1+ +; /* поиск конца строки s1 */ • while ((*s1++ = *s2++) ! ='0'); /* копирование s2 в конец s1, • включая нуль-символ */ • return rs; •}
  • 101. • С символьными строками можно работать как с массивами: обращаться к отдельным символам строки с помощью индекса. Ту же функцию сцепления строк можно написать иначе: • char *strcat (char *s1, char *s2) • { • int i=0, j=0; /* индексы символов строк s1 * и s2 */ • while (s1[i]) i++; /* поиск конца строки s1 */ • while ((s1[i++] = s2[j++])); /* копирование строки s2 • в конец s1, включая нуль-символ */ • return s1; • }
  • 102. Пример драйвера для функции сцепления строк strcat(): • • • • • • • • • • • • • • • • #include <stdio.h> #include <conio.h> void main() { char str1[81],str2[81]; puts ("Введите две строки"); gets (str1); gets (str2); if (strlen(str1)+strlen(str2) < 81) { puts ("Результат:"); puts (strcat(str1,str2)); printf ("Строки после вызова функции сцепления:n %sn%sn", str1,str2); } else puts ("Не хватает памяти для результирующей строки"); getch(); }
  • 103. Посимвольная обработка строк • Для представления строк могут использоваться массивы символов. Примеры описания такого массива: • char text[10]; */ /* массив из 10 символов • Для ввода символьных строк можно использовать библиотечную функцию gets(): • char s[81]; • gets(s); • Вывод символьных строк можно выполнить либо с помощью библиотечной функции puts(): • сhar str[]= “Привет”; • puts(str); /* или printf(“%sn”, str); */
  • 104. Структуры •Структура – это структура данных, состоящая из фиксированного числа компонентов, называемых полями структуры. В отличие от массива, компоненты (поля) записи могут быт различного типа. Чтобы можно было ссылаться на тот или иной компонент записи, поля именуются. Структура является аналогом типа данных запись из языка Паскаль.
  • 105. Переменные типа структура объявляются следующим образом: •struct <имя типа> •{ •<список полей> •} <имя переменной>; •Здесь <имя типа>, <имя переменной> – правильный идентификатор; •struct – зарезервированное слово; •<список полей> – список полей; представляет собой последовательность разделов структуры, между которыми ставится точка с запятой.
  • 106. Массив структур можно описать следующим образом: •struct Stud •{ • char fam[15], name [15]; • int group; • Birthday bd; • float rating; •} PMI[100];
  • 107. • • • • • • • • • • Например: struct ANKETA a1; struct BOOK b1,b2; struct BOOK mb[100]; /* массив из 100 структур типа BOOK*/ struct ANKETA *p1; /* указатель на структуру типа ANKETA */ struct BOOK *p2 = &b2; /* указатель на структуру типа BOOK, ссылающийся на переменную b2 */ При объявлении структурных переменных на языке C++ ключевое слово struct обычно опускается, например: ANKETA a1; BOOK b1,b2;
  • 108. • Пример • /* ввод значения структурной переменной b2 типа BOOK*/ • gets(b2.author); • gets (b2.name); • scanf(“%d%d”, &b2.year, &b2.pages); • Пример • struct ANKETA a2; • strcpy(a2.fio, “Иванов А.В.”); • а2.gr = 1980; • strcpy(a2.adr, “ул.Пушкина, д.10, кв.5”); • Пример • struct BOOK *p3 = &b3; • printf (“%s, %s, %d г., %d с.n”, p3->author, p3>name, • p3->year, p3->pages); • Результат на экране: • Толстой Л.Н., Война и мир, 1995 г., 1650 с.
  • 109. • Если структурные переменные используются только в одной функции программы, то можно совместить описание переменных с описанием типа. При этом имя типа можно не задавать, например: • struct • { char fio[20]; • int gr; • char adr[40]; • } a1, a2, *p1;
  • 110. Работа с файлами •Файл – это поименованная область на диске, содержащая какую-либо информацию, например, текст программы, данные для программы, документ. •Файлы бывают текстовые и двоичные (бинарные).
  • 111. Работа с файлами •Текстовые файлы – это файлы, которые создаются или которые можно просмотреть с помощью текстовых редакторов. В операционной системе MS DOS текстовые файлы представляют собой последовательность символьных строк. Каждый символ занимает один байт. Строка заканчивается двумя символами: «возврат каретки» (с кодом 13) и «перевод строки» (с кодом 10).
  • 112. Работа с файлами •Двоичные файлы содержат информацию во внутреннем представлении. Примером двоичного файла является exe-файл, содержащий программу в машинных командах. Прикладная программа тоже может создать двоичный файл, записав в него данные в том виде, в каком они хранятся в памяти (к примеру, типа int).
  • 113. Для чтения информации из файла служат функции: • • • • • • • • • fscanf() – форматированный ввод, fgets() – чтение одной строки, fgetc() – чтение одного символа, fread() – ввод заданного числа байтов (символов). Для записи информации в файл используются функции: fprintf() – форматированный вывод, fputs() – вывод строки, fputc() – вывод одного символа, fwrite() – вывод заданного числа байтов (символов).
  • 114. Некоторые функции доступа к файлам •fopen – открытие файла. •Прототип функции: •FILE * fopen (char * fname, char * mode); •Первый параметр fname задает имя открываемого файла, второй – режим открытия файла или вид его обработки. Параметр mode может задаваться в виде: •“r” – чтение файла, •“w” – запись в файл (если файл существует, он стирается), •“a” – добавление информации в конец файла, •“r+” – чтение и запись.
  • 115. Пример •FILE *fout, *fmod; • /* указатели на выходной и модифицируемый файлы */ •char fname[13]; /* имя модифиц. файла */ •fout = fopen (“f1.txt”, “w”); •puts(“Введите имя модифицируемого файла”); •gets (fname); •if ((fmod = fopen(fname, “r+”) ==NULL) •{ puts (“Файл в текущем каталоге не найден”); • exit (1); •}
  • 116. • Задача. Входной файл st.txt содержит сведения о сдаче студентами группы экзаменационной сессии. Каждая запись файла содержит фамилию и инициалы студента (15 символов) и пять оценок (5 символов) и завершается символом ”перевод строки”. Напечатать список студентов с указанием среднего балла каждого студента.
  • 117. • • • • • • • • • • • • Программа: /*-----------------------------------------*/ /* Печать среднего балла каждого студента */ /*-----------------------------------------*/ #include <stdio.h> #include <conio.h> struct STUDENT { char fio[15]; /* фамилия и.о. */ char oc[7]; /* 5 оценок + 'n' + '0' */ }; void main() { FILE *f; /* указатель на входной файл */ • struct STUDENT tz; /* текущая запись файла */ • int i, • s; /* сумма оценок */
  • 118. • if ((f= fopen("st.txt","r")) == NULL) • { puts ("Файл st.txt не найден"); • return; • } • puts ("nФамилия и.о. Ср.балл"); • puts ("------------------------------"); • while (fgets((char *)&tz, sizeof(struct STUDENT), f) != NULL) • { for (i=0,s=0; i<5; i++) • s+=tz.oc[i]-'0'; • tz.fio[14]='0'; • printf("%s %.1fn", tz.fio, (float)s/5); • } • fclose(f); • getch(); • }
  • 119. Массивы и функции как параметры • Указатели на функции • Функции, как и другие объекты программы, располагаются в памяти ЭВМ. Любая область памяти имеет адрес, в том числе и та, в которой находится функция. Имя функции без круглых скобок за ним представляет собой константный адрес этой области памяти. Таким образом, имея функции со следующими прототипами: • double sin(double x); • double cos(double x); • double tan(double x);
  • 120. • Можно описать и указатель на функцию. Например, для функции с аргументом типа double, возвращающей значение типа double, описание такого указателя будет выглядеть следующим образом: • double (*fn)(double x);
  • 121. • После того, как описан указатель на функцию, становятся возможными следующие операции: • • • • fn = sin; /* Настройка указателя на функцию sin a = fn(x); /* Вызов функции sin через указатель fn = cos; /* Настройка указателя на функцию cos b = fn(x); /* Вызов функции cos через указатель • Можно описать массив указателей на функцию и проинициализировать его: • double (*fnArray[3])(double x) = { sin, cos, tan }; • Теперь становится возможным следующий цикл: • for(i=0; i<3; i++) • printf( "F(x) = %lfn", fnArray[i](x) ); */ */ */ */
  • 122. • Можно описать функцию возвращающую значение указателя на функцию: • double (*fnFunc(int i)) (double x) • { • switch(i) • { • case 0 : return sin; • case 1 : return cos; • case 2 : return tan; • } • } • После описания функции fnFunc становится возможным следующий цикл: • for(i=0; i<3; i++) • printf( "F(x) = %lfn", fnFunc(i)(x) );
  • 123. Массивы и указатели • В языке C понятие массива тесно связано с понятием указателя. Действительно, как было описано выше, имя массива представляет собой адрес области памяти, распределенной под этот массив, или иными словами адрес первого элемента массива. Пусть описаны следующие данные: • int a[100], *pa; • и осуществлено присваивание: • pa = a;
  • 124. • Два существенных отличия массива от указателя: • массиву при описании выделяется память для хранения всех его элементов, а указателю только для хранения адреса; • адрес массива навсегда закреплен за именем, то есть имя массива является адресной константой и выражение вида a = pa недопустимо.
  • 125. Пример • double A[100], *pA, *pA100; • int i; • /* Заполняем массив A. Работаем с массивом */ • for (i=0; i<100; i++) A[i]=0; • /* Заполняем массив A. Работаем с указателями */ • for (pA=A, pA100=pA+100; pA<pA100; pA++) *pA=11.9;
  • 126. Указатели и двумерные массивы • Пусть имеются следующие определения массивов и указателей: • int A[4][2], B[2]; • int *p, (*pA)[4][2], (*pAstr)[2]; • Здесь A представляет собой двумерный массив из четырех строк и двух столбцов, B одномерный массив из двух элементов. Для каждого из этих массивов будет выделено соответствующее количество памяти, достаточное для хранения всех их элементов. • Указатель p представляет собой указатель на величину int, указатель pA - указатель на двумерный массив из четырех строк и двух столбцов, pAstr - указатель на одномерный массив из двух элементов.
  • 127. • Для вышеописанных указателей допустимы следующие операции присваивания, поскольку слева и справа от операции присваивания находятся указатели на один и тот же тип данных: • p = B; • p = &B[1]; • p = &A[0][0]; • p = A[2]; • Следующее присваивание: • p = A; /* неверно */ • является неверным, так как слева от операции присваивания находится указатель на тип int, а справа - указатель на первый элемент массива A, который (элемент) представляет собой массив из двух элементов типа int. В таких случаях компиляторы выдают предупреждающее сообщение о подозрительном преобразовании указателя.
  • 128. • Следующие присваивания корректны • pA = &A; /* Указатель на двумерный массив */ • pAstr = &B; /* Указатель на одномерный массив */ • и устанавливают следующее соответствие элементов: • (*pA)[i][j] эквивалентно A[i][j] • (*pAstr)[i] эквивалентно B[i] • Массивы указателей удобны для хранения символьных строк: • char *str[] = { • "Строка 1", • "Строка 2", • "Длинная строка 3" • };
  • 129. Пример • • • • • • • • • • • • #include <stdio.h> #define N 3 void p1(int *m,int k) { int i; for(i=0;i<k;printf("%d",m[i++])); puts("n"); } void p3(int *m,int k) { int i; for(i=k-1;i>=0;printf("%d",m[i--])); puts("n"); }
  • 130. Пример • • • • • • • • • • • void p2(void p(int *,int), int *mm,int nn) { p(mm,nn); } void main() { int mas[N],i; for(i=0;i<N;mas[i++]=i); p2(p1,mas,N); p2(p3,mas,N); }
  • 131. Технологии программирования •В проектировании и программировании активно применяются следующие технологии: •Структурное программирование. •Модульное программирование. •Объектно-ориентированное программирование. •Компонентное программирование.
  • 132. Структурное программирование… • Э. Дэйкстра (60-е годы): • Для любой простой программы можно построить функционально эквивалентную ей структурную программу, т.е. программу, сформированную на основе фиксированного базисного множества, включающего: •структуру последовательного действия, •структуру выбора одного из двух действий •структуру цикла, то есть многократного повторения некоторого действия с проверкой условия остановки повторения.
  • 133. Структурное программирование… •Простая программа – ровно один вход и один выход. •Базисные конструкции:
  • 134. Структурное программирование • Стандартизация и линейность программы – снижение сложности. • • • • • Некоторые соображения: Алгоритм должен иметь 1 вход и 1 выход. Никаких goto. Нет зависимости от языка программирования. Ясен набор операторов, который необходим в языках программирования.
  • 135. Модульное программирование... • Основная идея: разбиваем сложную задачу на подзадачи, каждую из них при необходимости разбиваем снова и т.д. • Получаем простые задачи, их решаем, объединяем.
  • 136. Модульное программирование • Структурное программирование – универсальный базис алгоритмических конструкций. • Модульное программирование – специфичный для задачи базис из модулей. – Более высокий уровень абстракции. – Настройка на конкретную задачу. – Возможности повторного использования. – Возможности коллективной разработки – разделение труда.
  • 137. Объектно-ориентированное программирование... • Дальнейшая борьба со сложностью. • Технология работает с этапа анализа. • Анализ – Проектирование – Программирование. • В основе – объектная модель и объектная декомпозиция.
  • 138. Объектно-ориентированное программирование • Основные принципы объектной модели: – абстракция; – инкапсуляция; – иерархия (наследование, агрегация); – полиморфизм; – модульность. • Объектная декомпозиция (в отличие от алгоритмической): элементы проекта – классы и объекты (а не алгоритмы). И только потом данные и алгоритмы.
  • 139. Компонентное программирование... • Компонентное программирование – развитие объектно-ориентированной идеологии. • Введен следующий уровень абстракции – классы объединяются в компоненты. • Основной принцип компонентного программирования: сборка приложения из готовых компонент, в общем случае написанных на разных языках.
  • 140. Компонентное программирование • Компонент: – программный код в виде самостоятельного модуля – м.б. использован в неизменном виде – может допускать настройку – обладает поведением (функциональностью). • Компонент изолирован от внешнего мира своим интерфейсом – набором методов (их сигнатурами). • Компонентная программа – набор независимых компонент, связанных друг с другом посредством интерфейсов.
  • 141. Структурная декомпозиция и нисходящее программирование • Задача • Дано целое n и вещественные x1, x2, ..., xn. Составить программу печати заданных вещественных чисел в порядке возрастания (не убывания).
  • 142. Вход: • Введите количество чисел: 5 • Введите числа: 12.5 6 14 -3 10 • Выход: • Упорядоченные числа:-3.0 6.0 10.0 12.5 14.0
  • 144. 1 этап. • Разработка алгоритма функции main().
  • 145. Алгоритм : • 1. n = Vvod(x); /* Ввод n и массива x */ • 2. Sort (x,n); /* Сортировка массива x по возрастанию*/ • 3. Вывод сортированного по возрастанию массива x
  • 146. 2 этап • Алгоритм функции ввода данных
  • 147. Алгоритм функции ввода данных • int Vvod (float x[]) • { • Ввод n; • for (i=0; i<n; i++) • Ввод x[i]; • Возврат n; • }
  • 148. Вывод массива x • Вывод заголовка "Упорядоченные числа:"; • for (i=0; i<n; i++) • Вывод x[i];
  • 149. Метод последовательного нахождения максимума • 2.5 6 14 элементов • 2.5 6 10 • • 2.5 6 10 • 2.5 6 -3 • • 2.5 6 -3 элементов • 2.5 -3 6 • 2.5 - 6 • -3 2.5 -3 10 // рассматривается n -3 14 -3 10 // рассматривается n-1 элементов // рассматривается n-2 // рассматривается n-3 элементов
  • 150. Алгоритм функции сортировки массива x по возрастанию • void Sort (float x[], int n) • { for (k=n-1; k>0; k--) • { Определение максимума среди • элементов x[0], ... , x[k] и его • индекса imax. • • } Обмен: x[imax] <--> x[k];
  • 151. 3 этап • Определение максимума среди элементов x[0], ... , x[k] и его индекса imax.
  • 152. Фрагмент программы: • imax =0; • for (i =1; i <= k; i++) • if (x[i] > x[imax]) imax = i;
  • 153. Программа: • • • • • • • • • • • • • • • #include <stdio.h> #define NMAX 100 /* Макс-е количество входных чисел */ /* Функция ввода данных * / int Vvod (float x[]) { int n; /* Количество чисел */ int i; /* Индекс текущего числа */ printf ("nВведите количество чиселn"); scanf ("%d", &n); printf ("Введите числаn"); for (i=0; i<n; ++i) scanf("%f", &x[i]); return n; }
  • 154. • /*Функция сортировки массива по возрастанию*/ • void Sort (float x[], int n) { • int k; /* Максимальный индекс просмотра*/ • float r; /* Для обмена */ • int imax; /* Индекс максимального элемента */ • int i; /* Индекс текущего числа */ • for (k=n-1; k>0; k--) • { imax =0; • for (i =1; i <= k; i++) • if (x[i] > x[imax]) imax = i; • /* Обмен x[imax] и x[k] */ • r = x[imax]; • x[imax] = x[k]; • x[k] = r;
  • 155. • /* Главная функция */ • void main (void) • { float x[NMAX]; /* Обрабатываемые числа*/ • int n; /* Количество чисел */ • int i; /* Индекс текущего числа */ • /* 1. Ввод массива x */ • n = Vvod(x); • /* 2. Сортировка массива x по возрастанию */ • Sort(x,n); • /* 3. Вывод массива x */ • printf("Упорядоченные числа:n"); • for (i=0; i<n; ++i) • printf (" %4.1f", x[i]); • }
  • 156. Модульное программирование • Технология модульного программирования предполагает разбиение программы на отдельные части – модули. Модуль может содержать одну или несколько взаимосвязанных функций и общие для функций данные. Каждый модуль помещается в отдельный файл (с расширением .c или .cpp) и компилируется автономно. Получившиеся в результате компиляции объектные модули объединяются в единый исполняемый модуль (exe-файл) с помощью компоновщика (Linker).
  • 157. • При разработке многомодульных программ нужно создавать проект (файл с расширением .prj). В проекте указывают, из каких файлов состоит программа. Это могут быть исходные файлы с расширением .c или .cpp, или объектные файлы с расширением .obj (полученные в результате компиляции исходных модулей), или библиотеки объектных модулей (файлы с расширением .lib). Заголовочные файлы (с расширением .h) в проекте не указывают, они должны быть в том же каталоге, в котором содержатся модули программы.
  • 159. Окно диалога “Add to Project List”
  • 160. Пример создания многомодульной программы • • • • • • • • • • • • • • #include <stdio.h> #include <stdlib.h> #include <string.h> #include <conio.h> #define MAXDL 9 /* макс. длина идентификатора (с признаком конца '0' ) */ struct EL_SP /* тип элемента списка { char id [MAXDL];/* идентификатор */ struct EL_SP *sled; /* ссылка на следующий элемент */ }; void Vkl ( struct EL_SP **p, char t_id[] ); void PechSp ( struct EL_SP *p ); */
  • 161. Файл “Vkl.c”: • • • • • • • • • • • • • • • • #include "spisok.h" /*-------------------------------------------------*/ /* функция включения очередного идентиф. в список */ /*-------------------------------------------------*/ void Vkl ( struct EL_SP **p, char t_id[] ) /* Вх. данные: *p - указатель списка идентификаторов в лексикографическом порядке, t_id - включаемый в список (текущий) ид-р */ /* Вых. данные: *p */ { struct EL_SP *pt,/* указатель включаемого эл-та */ *k,*j; /* указатели очередного и предыдущего элементов списка */ /* выделение памяти для нового эл-та списка */ pt = (struct EL_SP *) malloc(sizeof(struct EL_SP)); strcpy(pt->id, t_id);
  • 162. Файл “Vkl.c”: • if (*p==NULL || strcmp(pt->id,(*p)->id) < 0) • { /* включение ид-ра в начало списка */ • pt->sled=*p; *p=pt; • } • else • { /* поиск элемента списка, после которого нужно • включить идентификатор */ • k=*p; • while (k!=NULL && strcmp(pt->id,k->id)>=0) • { j=k; k=k->sled; • } • /* включение эл-та *pt после элемента *j */ • j->sled=pt; pt->sled=k; • } • }
  • 163. Файл “PechSp.c”: • #include "spisok.h" • / *-------------------------------------------------*/ • /* функция печати списка */ • / *-------------------------------------------------*/ • void PechSp ( struct EL_SP *p ) • /* Вх. данные: p - указатель начала списка */ • { struct EL_SP *i; • /* указатель текущего элемента списка */ • printf ("nРезультат:n"); • for ( i=p; i!=NULL; i=i->sled ) • puts (i->id); • }
  • 164. Файл “main.c”: • • • • • • • • • • • • • • • • • • • • • • • #include "spisok.h" /*---------------------------------------------*/ /* О С Н О В Н А Я П Р О Г Р А М М А */ /*---------------------------------------------*/ main() { struct EL_SP *p; /* указатель начала списка */ unsigned n ; /* количество идентификаторов */ unsigned i ; /* параметр цикла */ char t_id[MAXDL]; /* текущий идентификатор */ printf ("nВведите число идентификаторовn n="); scanf ("%u",&n); getchar(); /* пропуск символа "перевод строки" */ p=NULL; /* список пока пуст */ printf("Введите идентификаторы "); printf("после каждого нажимайте клавишу <Enter>n"); for ( i=1; i<=n; i++ ) { gets (t_id); Vkl (&p,t_id); /* включение ид-ра в список */ } PechSp (p); /* печать списка */ printf ("nДля завершения нажмите любую клавишуn"); getch(); }
  • 165. Работа с графикой на языке C и модуль graphics.h • Монитор ПК может работать в двух режимах текстовый и графический. В этих режимах по разному представляется видео память. Переход из режима в режим очищает экран. В графическом режиме необходимо пользоваться функциями из графической библиотеки graphics.h.
  • 166. Типы видео мониторов и их режимы • Существует много типов мониторов, на каждом из которых доступны кроме своего режима, и все более низкие режимы. Под режимом понимается разрешающая способность количество цветов. Кроме того мониторы делятся по аппаратной реализации: ЦИФРОВЫЕ и АНАЛОГОВЫЕ.
  • 167. Инициализация графики • Функции: • initgraph(int *GrDr,int *GrMod,char *Path) ; • i=graphresult() ; • closegraph() ; • Функция initgraph(...) инициализирует графический режим. В параметрах ей передается: • GrDr - Тип графического монитора, или DETECT Определить максимально возможный. Тип установленного оборудования возвращается в этих же переменных (поэтому они и передаются указателем). • GrMod - Режим. • Path - Путь до файлов *.bgi - драйверов графических режимов. Если указанно " " - то в текущем каталоге.
  • 168. Пример: • • • • • • • • • • • • • • • • • • #include <graphics.h> #include <conio.h> #include <stdio.h> int main(void) { int GrDr,GrMod,rez ; GrDr=DETECT ; initgraph(&GrDr,&GrMod," ") ; rez=graphresult() ; if(rez != grOk) { printf("n Ошибка инициализации графики") ; return(1) ; } /* Кон. if */ line(0,0,100,100) ; getch() ; closegraph() ; return(0) ; } /* Кон. main() */
  • 169. Система координат Основные графические функции Ниже используются обозначения: x,y,x1,y1,x2,y2 – координаты; *St – строка символов; rx,ry,r – радиусы; h – толщина изображения; Alfa1,Alfa2 – углы в градусах; DX,DY – размеры символа; Color – цвета.
  • 170. Функции рисования Функция Описание line(int x1,int y1,int x2,int y2) Линия rectangle(int x1,int y1,int x2,int y2) Прямоугольник bar(int x1,int y1,int x2,int y2) Закрашенный прямоугольник bar3d(int x1,int y1,int x2,int y2,int h) Закр. прям. с оттененением ellipse(int x,int y,int rx,int ry) Эллипс fillellipse(int x,int y,int rx,int ry) Закрашенный эллипс arc(int x,int y,int Alfa1,int Alf2,int r) Дуга (круг)
  • 171. Функции рисования Функция Описание outtextxy(int x,int y,char *St) Вывод строки текста putpixel(int x,int y,char Color) Поставить точку Color=getpixel(int x,int y) Получить цвет точки floodfill(int x,int y,char Color) Залить цвета cleardevice() Очистить экран clearviewport() Очистить порт вывода setviewport(int x1,int int y1) Установить порт вывода int x2,int y2,char flg) flg-вывод за пред. окна до границы указанного
  • 172. Функции изменения параметров рисования Функция Описание setcolor(char Color) Установить цвет рисования setbkcolor(char Color) Установить цвет фона setfillstyle(<Шаблон>,cahr Color) Установить цвет и стиль закраски фигур setlinestyle(<Шаблон>,int Bit,char h) Установить линий. стиль и толщину
  • 174. Шаблоны закраски Шаблон Ном. Изображение EMPTY_FILL 0 Цветом фона SOLID_FILL 1 Выбранным цветом LINE_FILL 2 --- LTSLASH_FILL 3 /// SLASH_FILL 4 /// BKSLASH_FILL 5 LTBKSLASH_FILL 6 HATCH_FILL 7 Light hatch XHATCH_FILL 8 Heavy crosshatch INTERLEAVE_FILL 9 Interleaving line WIDE_DOT_FILL 10 Точками CLOSE_DOT_FILL 11 Частыми точками