Основы алгоритмизации и программирования.
ОСНОВЫ АЛГОРИТМИЗАЦИИ И ПРОГРАММИРОВАНИЯ.
ЯЗЫК С/С++. СТРУКТУРНЫЙ ПОДХОД
Краткий курс лекций
Тирасполь 2000
СОДЕРЖАНИЕ
1. ОБЗОР ЯЗЫКа ПРОГРАММИРОВАНИЯ С. 5
2. ЭТАПЫ СОЗДАНИЯ ПРОГРАММЫ.. 5
3. СТРУКТУРА ПРОГРАММЫ НА ЯЗЫКЕ СИ. 6
3.1. Внутренняя структура программы. 6
3.2. Пример программы на СИ. 6
4. БАЗОВЫЕ ЭЛЕМЕНТЫ ЯЗЫКА СИ. 7
5. ДАННЫЕ В ПРОГРАММЕ НА СИ. 8
5.1. Константы. 8
5.2. Базовые стандартные типы переменных. 9
6. ОПЕРАЦИИ ЯЗЫКА СИ. 11
6.1. Арифметические операции. 11
6.2. Операции отношения. 12
6.3. Логические операции. 12
6.4. Операции с разрядами. 13
6.5. Операции сдвига. 13
6.6. Операция условия ?: 14
6.7. Преобразование типов. 14
6.8. Операции приведения. 14
6.9. Дополнительные операции присваивания. 15
7. ОПЕРАТОРЫ ЯЗЫКА СИ. 15
8. СТАНДАРТНЫЕ ФУНКЦИИ ВВОДА И ВЫВОДА. 22
8.1. Функция вывода данных на экран printf () 22
8.2. Модификаторы спецификаций преобразования. 23
8.3. Функция ввода данных с клавиатуры sсanf() 23
8.4. Функции ввода/вывода одного символа getchar(), putchar() 24
8.5. Функции небуфиризированного ввода с клавиатуры. 24
8.6. Ввод/вывод в поток в С++. 24
8.7. Форматирование вывода. 25
9. МАССИВЫ.. 26
9.1. Одномерные массивы. 26
9.2 Многомерные массивы. 28
10 ФУНКЦИИ. 30
10.1 Cоздание и использование пользовательских функций. 31
10.2 Параметры функции. 32
10.3 Возвращение значения функцией. 33
10.4 Inline-функции. 33
10.5 Значение формальных параметров функции по умолчанию.. 33
10.6 Перегрузка функций. 34
11 КЛАССЫ ПАМЯТИ И ОБЛАСТЬ ДЕЙСТВИЯ. 35
11.1 Глобальные переменные. 35
11.2 Локальные переменные. 36
11.3 Доступ к функциям в многомодульной программе. 37
12 ПРЕПРОЦЕССОР ЯЗЫКА СИ. 39
12.1 Подстановка имен. 39
12.2 Включение файлов. 40
12.3 Условная компиляция. 40
13 УКАЗАТЕЛИ. 41
13.1 Операция косвенной адресации * 41
13.2 Описание указателей. 41
13.3 Использование указателей для связи функций. 42
13.4 Указатели на одномерные массивы. 42
13.5 Указатели на многомерные массивы. 43
13.6 Операции над указателями. 43
13.7 Передача массива в качестве параметра в функцию.. 44
13.8 Указатель на void * 45
14 СИМВОЛЬНЫЕ СТРОКИ И ФУНКЦИИ НАД СТРОКАМИ. 46
14.1 Массивы символьных строк. 46
14.2 Массивы указателей. 47
14.3 Указатель как возвращаемое значение функции. 47
Передача указателя как параметра функции. 47
14.4 Функции, работающие со строками. 48
14.5 Стандартные библиотечные функции. 48
14.6 Преобразование символьных строк. 49
15 ССЫЛКИ. 50
16 Параметры КОМАНДНОЙ СТРОКИ. 51
17 ПРОИЗВОДНЫЕ ТИПЫ ДАННЫХ. 52
17.1 Структуры. 52
17.2 Объединения. 56
17.3 Синоним имени типа. 56
17.4 Определение именнованных констант. 57
17.5 Перечисления. 57
17.6 Битовые поля. 58
18 ДИНАМИЧЕСКОЕ ВЫДЕЛЕНИЕ ПАМЯТИ. 59
18.1 Операция new и delete в С++. 60
18.2 Операция new с массивами. 61
18.3 Инициализаторы с операцией new. 61
18.4 Ошибки при использовании динамичской памяти. 62
19 ФАЙЛ. 64
19.1 Открытие файла fopen() 64
19.2 Закрытие файла fclose() 64
19.3 Функции ввода/вывода одного символа fgetc(), fputc() 64
19.4 Функции форматированного ввода/вывода в файл. 65
19.5 Функции ввода/вывода строки символов в файл. 65
19.6 Функции управления указателем в файле. 66
19.7 Ввод/вывод записей фиксированной длины. 66
20 ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ. 68
20.1 Однонаправленные связные списки. 68
20.2 Бинарные деревья. 71
21 РАЗМЕЩЕНИЕ ДАННЫХ В ПАМЯТИ. 74
22 МОДЕЛИ ПАМЯТИ. 75
ЭТАПЫ СОЗДАНИЯ ПРОГРАММЫ
1) Программа готовится с помощью любого текстового редактора и запоминается в исходном файле с расширением *.С, *.СРР.
2) Преобразуется компилятором в объектный файл *.obj.
3) Вместе с другими объектными файлами преобразуется в исполняемый файл программой, называемой загрузчиком или редактором связей *.EXE.
Этот файл уже может быть исполнен компьютером.
СТРУКТУРА ПРОГРАММЫ НА ЯЗЫКЕ СИ
Программа на языке Си определяется как совокупность одного или нескольких модулей. Модулем является самостоятельно компилируемый файл. Модуль содержит один или несколько функций. Функция состоит из операторов языка Си. Рис.1.
Рис.1 Структура программы на языке Си.
Внутренняя структура программы
Исполняемая программа на Си состоит из 4 частей: область команд, область статических данных, область динамических данных, область стека. см. Рис.2.
1. Область команд содержит машинные команды;
2. Стек используется для временного хранения данных и адресов возврата при вызовах подпрограмм;
3. Область статических данных для хранения переменных программы;
4. Область динамических данных для размещения дополнительных данных, которые появляются в процессе работы программы.
Пример программы на СИ
заголовок
# include < stdio.h > //включение файла
void main (void) /*пример*/- имя функции и комментарии
{
тело функции
int num;
num = 1;
printf("пример программы"); // вывод на экран
printf("на Си");
} // конец тела функции
Программа Си всегда имеет функцию main(). С нее начинается выполнение программы.
Рис.2. Внутренняя структура программы на Си.
БАЗОВЫЕ ЭЛЕМЕНТЫ ЯЗЫКА СИ
1. Комментарии – используются для документирования программы.
§ // - далее все игнорируется до конца строки.
§ /* Текст */ - в любом месте программы
§ /* Строка 1 - для комментария любой длины
строка 2
строка 3
*/
2. Идентификатор - это имя, которое присваивается какому-либо объекту (переменной). Используются строчные и прописные английские буквы, цифры и знак подчёркивания. Строчные и прописные буквы различаются. Начинаются с буквы или знака подчеркивания. Длина не ограничена.
В современном программировании часто используется для создания идентификаторов Венгерская нотация. Например: WordParametrFormat или Word_Parametr_Format.
3. Служебные слова – это слова, с которыми в языке жестко сопоставлены определённые смысловые значения и которые не могут быть использованы для других целей. Это имена операторов, команды препроцессора и так далее.
ДАННЫЕ В ПРОГРАММЕ НА СИ
Каждая программа оперирует в программе с данными. Они присутствуют в программе в виде переменных и констант.
Данные, которые могут изменяться или которым может присваиваться значения во время выполнения программы, называются переменными.
Данные, которым устанавливаются определенные значения и они сохраняют свои значения на всем протяжении работы программы, называются константами.
Константы
Константы - это фиксированные значения. Значение, будучи установлено, больше не меняется.
Типы констант:
a) Целые и длинные целые. Записываются в десятичной, восьмеричной и шестнадцатеричной системе счисления.
Десятичная система:
Размер:Диапазон чисел:
16 битов ± 32768 знаковое
0 – 65535u беззнаковое - (unsigned)
32 бита ± 2147483648l знаковое длинное – (long)
0 – 4294967295ul беззнаковое длинное - (unsigned long )
Пример: 12, 12567, 24u, 135l, 4567ul
Восьмеричная система:
Если число начинается с цифры 0, оно интерпретируется как восьмиричное число
16 битов 0 ¸ 077777
0100000 ¸ 0177777u
32 бита 0200000 ¸ 01777777777l
020000000000 ¸ 037777777777ul
Пример: 0674
Шестнадцатеричная система:
Если число начинается с символа 0х, то оно интерпретируется как шестнадцатиричное
16 битов 0x0000 ¸ 0x7FFF
0x8000 ¸ 0xEFFFu
32 бита 0x10000 ¸ 0x7FFFFFFFl
0x80000000 ¸ 0xFFFFFFFFul
Пример: 0х3D4
b) Вещественные константы. Это числа с плавающей точкой. Значение имеет дробную часть. По умолчанию все вещественные константы имеют тип двойной точности double. Занимают в памяти 8 байт. Диапазон значений ± 1 e ±308.
Принудительно можно задать формат одинарной точности. Число будет занимать 4 байта. (5.75 f)
А также расширенной точности – 10 байт. (3.14L)
Знак + можно не писать. Разрешается опускать либо десятичную точку, либо экспоненциальную часть, но не одновременно (.2; 4е16). Можно не писать дробную либо целую часть, но не одновременно (100.; .8е-5)
c) Символьные константы. Это набор символов, используемых в ЭВМ.
Делятся на 2 группы: печатные и непечатные (управляющие коды). Символьная константа включает в себя только 1 символ, который необходимо заключить в апострофы и занимает 1 байт памяти.
Любой символ имеет своё двойное представление в таблице ASCII
Символ 'А' 'a' ' ' '\n'
Его код 65 97 32 10
Как целый тип данных 'A'=01018, 010000012, 4116, 6510.
Управляющие коды начинаются с символа \ и тоже заключаются в апострофы. Наиболее распространенные управляющие коды:
\n – переход на новую строку
\t – табуляция (сдвиг курсора на некоторое фиксированное значение)
\b – шаг назад (сдвиг на одну позицию назад)
\r – возврат каретки (возврат к началу строки)
\f – подача бланка (протяжка бумаги на 1 страницу)
\\ - слеш
\’ - апостроф
\” - кавычки
Последние три знака могут выступать символьными константами, а также применяться в функции вывода на экран printf() , поэтому применение их в качестве символов может привести к ошибке. Например, если мы хотим вывести строку «Символ \ называется слеш», то оператор должен выглядеть так:
рrintf( «Символ \\ называется слеш»
d) Строковые константы - содержат последовательность из 1 и более символов,
заключённых в " ". Расходуется по 1 байту на любой символ + 1байт на так называемый ноль-символ - признак конца строки. Ноль-символ – не цифра ноль, он означает, что количество символов в строке (N) должно быть на 1 байт больше (N+1), чтобы обозначать конец строки.
ОПЕРАЦИИ ЯЗЫКА СИ
Операции в языке Си применяются для представления арифметических выражений. Насчитывается около 40 операций и 16 приоритетов. Величина, над которой выполняется операция, называется операндом. Операции могут быть унарные (один операнд), бинарные (два операнда) и тернарные.
Арифметические операции
Можно выполнять действия над переменными, переменными и константами, константами.
Самый высокий приоритет у скобок ()
1) Изменение знака - r = -12; -r (2)
2) Умножения * сm = 2,54 *in; (3)
3) Деления / var = 12.0 / 3.0; (3)
Операции отношения
Меньше <, (7) Больше или равно > =, (7)
Меньше или равно <=, (7) Не равно != (8)
Больше > (7) Равно = = . (8)
Используются для сравнения в условных выражениях. Вырабатывают значения «истина» и «ложь».
Не следует путать знаки = и = =. С помощью операции присваивания (=) некоторой переменной слева от этого знака присваивается значение. А с помощью операции отношений (= =) проверяется равенство выражений, стоящих слева и справа от этого знака.
Все операции отношений возвращают результат «истина» или «ложь» (0 или 1). Значение переменных при этом не изменяется.
При сравнении float лучше пользоваться только операциями < и >, т.к. ошибки округления могут привести к тому, что числа окажутся неравными, хотя по логике они должны быть равны. (например 3*1/3 равно 1,0, но 1/3 в вещественном формате будет представлена как 0,999999…, и произведение не будет равно 1)
Приоритет больше чем у операции присваивания, но меньше чем у +, -.
y > x+2; - сначала сложение, затем сравнение.
Логические операции
Используются для проверки условия, вырабатывая значение истина или ложь.
1) && "И"(операция логического умножения.)
Выражение истинно только в том случае, если истинны выражения, стоящие до и после &&. Если первое – ложь, то дальше не проверяется. (12)
2) || "ИЛИ" (логическое сложение.)
Выражение истинно, если одно из выражений истинно. Если первое – истина, дальше не проверяется (13)
3) ! "НЕ" (отрицание) (2)
Булева логика:
x | y | && | || | ! |
0 11 | ||||
Примеры:
if(x>0 && x<10) действие
5>2 && 4>7 - ложь
5>2 || 4>7 - истина
!(4>7) – истина
У операции ! (НЕ) очень высокий приоритет (выше только у скобок). && и || выше присваивания, но ниже чем отношения.
a>b && b>c || b>d
((a>b) && (b>c) || (b>d))
Операции с разрядами
Поразрядные логические операции. Приводят к изменению значения переменной. Действия производятся над данными класса целых и char. Они называются поразрядными, потому что они выполняются отдельно над каждым разрядом независимо от разряда, находящегося слева или справа.
1) ~ Дополнение до 1 или поразрядное отрицание. Это унарная операция изменяет каждую 1 на 0, а 0 на 1.
~(11010) получим (00101)
2) & Поразрядное Ислужит для сбрасывания битов. Эта бинарная операция сравнивает последовательно разряд за разрядом два операнда. Результат равен 1, если оба соответствующих разряда операндов равны 1
(10010011) & (00111101) => (00010001)
3) | Поразрядное ИЛИ служит для установки битов. Эта бинарная операция сравнивает последовательно разряд за разрядом два операнда. Результат равен 1, если один (или оба) из соответствующих разряда операндов равен 1.
(10010011) | (00111101) => (10111111)
4) ^ Исключающее ИЛИ. Результат равен 1, если один из разрядов равен 1 (но не оба)
(10010011) ^ (00111101) => (10101110)
Операции сдвига
Операции сдвига осуществляют поразрядный сдвиг операнда. Величина сдвига определяется значением правого операнда. Сдвигаемые разряды теряются. При сдвиге вправо знаковый разряд размножается.
1) << сдвиг влево Разряды левого операнда сдвигаются влево на число позиций, указанное правым операндом. Освобождающиеся позиции заполняются нулями, а разряды, сдвигаемые за левый предел левого операнда, теряются.
(10001010)<<2 = = 00101000
2) >> сдвиг вправо Разряды левого операнда сдвигаются вправо на число позиций, указанное правым операндом. Разряды, сдвигаемые за правый предел левого операнда, теряются. Для беззнаковых чисел освобожденные слева разряды заполняются нулями. Для чисел со знаком левый разряд принимает значение знака.
(10001010)>>2 = = 00100010
Эти операции выполняют эффективное умножение и деление на степени 2:
number<<n – умножает number на 2 в n-й степени
number>>n – делит number на 2 в n-й степени
6.6. Операция условия ?:
Операция состоит из двух частей (? и :) и содержит три операнда (операнд1 ? операнд2 : операнд 3). Это более короткий способ записи оператора if else и называется «условным выражением».
Например: условное выражение x = (y<0)? –y : y; означает, что если у меньше 0, то х = -у, в противном случае х = у. В терминах оператора if else это выглядело бы так:
if(y<0)
x = -y;
else
x = y;
Условные выражения более компактны и приводят к получению более компактного машинного кода.
Т.о. если условие операнда 1 истинно, то значением условного выражения является величина операнда 2, если условие операнда 1 ложно – величина операнда 2.
Условное выражение удобно использовать, когда имеется некоторая переменная, которой можно присвоить одно из двух возможных значений.
max = (а>b) ? a : b;
6.7. Преобразование типов
В операторах и выражениях должны быть данные одного и того же типа. Но на Си возможно это нарушить (в отличии от Паскаля). Си компилятор автоматически преобразует типы, но следует соблюдать определенные правила:
1.Если производится операция над данными 2-х разных типов, то обе величины приводятся к высшему типу (происходит "повышение" типа).
2. Типы от высшего к низшему: double, float, long, int, short, char. Применение слова unsigned повышает ранг соответствующего типа со знаком.
3. В операторе присваивания конечный результат вычисления выражения в правой части приводится к типу переменной, которой должно быть присвоено это значение ( при этом может быть как повышение так и понижение типа). "Понижение" типа приводит к отбрасыванию разрядов.
4. При вычислениях величин типа float они автоматически преобразуются в тип double (для сохранения точности вычислений, это уменьшает ошибку округления). Конечный результат преобразуется обратно в float, если это диктуется оператором описания.
Операции приведения
Хотя в СИ и возможно преобразование типов, лучше избегать этого и указывать точно тип данных. Это называется привидением типов.
int num;
num = 1,6+1,7; 3,3 => 3. Сначала числа складываются, затем результат приводится к указанному типу.
num = (int)1,6+(int)1,7; 1+1 = 2. В это случае, числа сначала приведены к данному типу, а затем складываются.
ОПЕРАТОРЫ ЯЗЫКА СИ
Основу программы на Си составляют выражения, а не операторы. Большинство операторов в программе являются выражениями с ‘;’. Это позволяет создавать эффективные программы.
Оператор является законченной конструкцией языка Си. Операторы служат основными конструкциями при построении программы. Выражение состоит из операций и операндов (операнд – то, над чем выполняется операция, простейшее выражение может состоять из одного операнда). Оператор служит командой компьютеру. Операторы бывают простые и составные. Простые операторы оканчиваются ‘;’ .
Простые операторы:
1. Пустой оператор ‘;’
2. Оператор описания int x, y;
3. Оператор присвоенияcount = 0.0;
4. Оператор выражение (управляющий оператор)
sum = sum+count;
var = (var + 10)/4;
5.Оператор вызова функции
printf("Привет \n");
6. Оператор следоаания ‘,’
x=7, y=10;
Составные операторы или блоки:
Это группа операторов, заключенных в фигурные скобки {...}.
7. Оператор ветвления if ... else.
If(условное выражение1)
оператор1;
If(условное выражение2)
оператор1;
}
else оператор2;
// Пример задачи на использование оператора
#include <stdio.h>
#define LIMIT 12600
#define MAX 25200
#define NORMA 60
#define PEOPLE 20
void main(void)
{
float kwh; //количество киловат
float bill; // плата
int p,house;
printf("Укажите количество израсходованных кВт/ч.\n);
scanf("%f",&kwh);
printf("Укажите количество человек в семье.\n);
scanf("%d",&p);
house=NORMA+PEOPLE*p;
if(kwh<=house)
bill=kwh*LIMIT;
else
bill= house*LIMIT + (kwh-house)*MAX;
printf("Плата за %f составляет %f.\n",kwh,bill);
}
Switch (целое выражение)
{
case конст1:
оператор;
case конст2:
оператор;
default:
оператор;
}
В начале вычисляется выражение в скобках за ключевым словом. Затем просматривается список меток case 'a': пока не будет найдена, соответствующая этому значению. Если нет такой метки, то будет выполнен default. Метка default может отсутствовать, тогда оператор switch ничего не выполнит и программа перейдет на следующий оператор. Оператор break служит для выхода из оператора switch и перехода к следующему оператору. Метки в операторе switch должны быть константами целого типа, включая chаr. Могут следовать несколько меток подряд.
//пример программы на множественный выбор
#include <stdio.h>
void main(void)
{
int x, y;
char c;
printf("Введите 2 целых числа и знак операции");
scanf(“ %d %d %c”, &x, &y, &c);
switch (c) {
case '+': printf("x + y = %3d\n”, x+y);
break;
case '-': printf("x - y = %3d\n”, x-y);
break;
case '*': printf("x * y = %3d\n”, x*y);
break;
case '/': printf("x / y = %3d\n”, x/y);
break;
default:
printf("Такой операции нет!\n);
}
}
Операторы цикла while
Цикл – это многократно повторяющиеся действия или группа действий.
Операторы цикла могут быть трех видов: с предусловием, с постусловием, со счетчиком.
а) с предусловием:
Оператор while состоит из трех частей: это ключевое слово while, затем в круглых скобках указывается проверяемое условие, и тело цикла - оператор, который выполняется, если условие истинно (таких операторов может быть несколько, тогда они заключаются в {} и получается составной оператор). Если оператор один, то действие оператора while распространяется от ключевого слова while до ‘;’.
while (условное выражение) или while (условное выражение){
оператор; операторы;
}
Схема выполнения цикла
while Истина
Ложь (переход к следующей операции)
Тело цикла может состоять из нескольких операторов. В этом случае оно заключается
в фигурные скобки.
Пример 1: Пример 2:
index = 0; index = 0;
while (index++ < 10) while (index++ < 10) {
sum = 10*index + 2; sum = 10*index + 2;
printf ("sum = % d \n", sum); printf ("sum = % d \n", sum);
}
В примере 1 в цикл включен только один оператор присваивания. Печать данных будет производиться только 1 раз – после завершения цикла (будет выведено – sum=102). В примере 2 в цикл включено два оператора, поэтому печать результатов будет выводиться на каждом шаге работы цикла.
В операторе цикла с предусловием, решение о прохождении цикла принимается до прохождения цикла. Поэтому возможно, что цикл никогда не будет пройден.
Последовательность действий, состоящая из проверки выражения и выполнения оператора, периодически повторяется до тех пор, пока выражение не станет ложным. Каждый такой шаг называется «итерацией».
//Пример программы с циклом while
#include <stdio.h>
void main(void)
{
int guess=1;
char res;
printf("Задумайте число от 1 до 100. Я попробую его угадать");
printf("\n Отвечайте д, если моя догадка верна и”);
printf( «\n н, если я ошибаюсь.\n»);
printf("Итак ваше число %d?\n", guess);
while((res=getchar()) != 'д')
if(res!='\n')
printf("Тогда оно равно %d?\n", ++guess);
printf("Ура, я угадала!!!");
}
б) Оператор цикла с постусловием (истинность условия проверяется после выполнения каждой итерации цикла. Решение, выполнять или нет очередной раз тело цикла, принимается после выполнения всех итераций). Этот цикл всегда выполняется хотя бы 1 раз.
do или do {
оператор; операторы;
while (условное выражение); } while (условное выражение);
Проверка истинности осуществляется после выполнения оператора или блока операторов. Хотя бы один раз этот цикл будет выполнен.
Схема выполнения цикла
Do while Истина
Ложь
Рассмотрим два примера:
Пример 1 Пример 2
do { while((ch = getchar()) ! = '\n')
ch = getchar(); putchar (ch);
putchar (ch);
} while(ch ! = '\n')
Функция getchar() получает один символ, поступающий с клавиатуры и передает его программе, аргументов она не имеет. Функция putchar получает один символ, поступающий из программы, и пересылает его для вывода на экран, эта функция имеет один аргумент, т.е. в скобках необходимо указывать символ, который будет выведен на печать. Можно использовать эту функцию в следующем виде: putchar(getchar()) – эта запись компактна и не требует введения вспомогательных переменных.)
Во втором примере на экран будут выводиться все символы до появления символа «новая строка». А в первом примере будут выводиться все символы, включительно и символ «новая строка» (только после печати этого символа, если он введен, в цикле производится проверка символа «новая строка» и действие цикла завершается).
Цикл выполняется хотя бы один раз, так как проверка осуществляется только после его завершения.
в) Оператор цикла со счетчиком
for (выр1; выр2; выр3) или for (выр1; выр2; выр3) {
оператор; операторы;
}
Выр1 – инициализация, проводится только 1 раз в начале цикла.
Выр2 - проверка условия окончания цикла (производится перед каждым возможным выполнением тела цикла. Когда выражение становится ложным, цикл завершается).
Выр3 – наращивание счетчика цикла (выражение вычисляется в конце каждого выполнения тела цикла).
Схема выполнения цикла
for Истина
Ложь
Если какое-либо из выражений отсутствует, то ‘;’ все равно ставится. Могут отсутствовать все выражения, и тогда цикл бесконечен. Цикл for очень многообразен.
Примеры:
1). for (n = 1; n < 1000; n++) ; счет в порядке возрастания
2). for ( i = 10; i > 0; i--) ; счет в порядке убывания
3). for (n = 2; n < 60; n = n + 12) ; значение переменной n будет увеличиваться на 12 при каждом выполнении тела цикла (после этой команды можно ввести printf(“%d\n”,n) и тогда на экран будут выводиться числа 2,14,26,38,50,62)
4). Можно вести подсчет с помощью символов:
for (ch = 'a'; ch <= 'z'; ch++) ;
printf(«Величина кода ASCII для %c равна %d.\n», ch, ch);
на печать будут выведены все буквы от a до z вместе с их кодами ASCII.
5). Наращивание может происходить и после выполнения действий в выражениях (значение переменных будет меняться при каждой итерации):
for (x = 1; y <= 75; y = 5*(x++)+10) ;
for (i = 1, cost = 20; i <= 16; i++, cost+= 17) ;
6). Можно опустить одно или более выражений (но нельзя опустить символы ;). Необходимо только включить в тело цикла несколько операторов, которые приведут к завершению его работы.
ans = 2;
for (n = 3; ans <=25;)
ans=*n;
Значение переменной asn сначала будет равно2, затем на первой итерации цикла примет значение 6, затем 18 и 54.
7). Бесконечный цикл
for (;;) ;
пустое условие всегда считается истинным.
8). Первое выражение не обязательно должно инициализировать переменную. Там может стоять оператор некоторого специального вида, например printf. Необходимо только помнить, что первое выражение выполняется только один раз, до начала выполнения остальных частей цикла.
for (printf ("Запомните введение числа!\n"); num = =6;)
scanf (" % d, &num);
г) Вложенные циклы
Если внутри одного цикла находится другой цикл, то эта конструкция называется вложенный цикл. Внутренний цикл выполняется столько раз, сколько задано во внешнем цикле.
// Пример программы на вложенные циклы
// Вывести на экран числа от 0 до 99 по 10 в каждой строке
#include <stdio.h>
void main(void)
{
int num=0;
int i, j;
for(i=0; i<10; i++) {
for(j=0; j<10; j++)
printf("%4d",num++);
printf("\n");
}
}
Форматирование вывода
Для форматирования вывода можно установить несколько флагов, для этого используются функции-члены setf, unsetf.
unsigned v =12345;
cout << "Before: " << v << endl;
cout.setf(cout.hex); //Модификация потока
cout << "After: " << v << endl;
Для форматирования можно подключить заголовочный файл Iomanip.h, тогда используем манипуляторы
cout << "In hexadecimal v == " << hex << v << endl;
cout << "In decimal v == " << dec << v << endl;
ends вставить нулевой завершающий символ в строку
endl начать новую строку
oct 8-ричная система счисления
Для выравнивания по правому краю целочисленных переменных можно задать: cout.width(8); но он не оказывает влияние на следующее выводимое значение.
Заключительная программа
Задача. Три бригады собирают в саду яблоки. Написать программу учета сбора яблок каждой бригадой. Определить, сколько яблок было собрано за день и средний заработок в каждой бригаде.
# include <stdio.h>
# include <conio.h>
void main (void) {
int worker1, worker2, worker3; //Кол-во человек в бригадах
int weight1, weight2, weight3; //Вес яблок
char ch;
float cost; //Стоимость яблок
int num, w; //Номер бригады и вес яблок
clrscr();
weight1 = weight2 = weight3 = 0;
printf("Введите количество студентов в каждой бригаде\n");
scanf ("%d %d %d",&worker1,&worker2,&worker3);
printf("Введите стоимость 1 кг. яблок \n");
scantf("%f",&cost);
for(;;) {
printf("В. номер бригады и количество собранных яблок\n");
scanf("%d %d",&num,&w);
switch (num) {
case 1:
weight1 += w;
break;
case 2:
weight2 += w;
break;
case 3:
weight3 += w;
break;
default:
printf("Вы неверно ввели номер бригады\n");
}
printf("Для окончания нажмите клавишу q\n");
ch = getche();
if (ch == 'q')
break;
}
printf("Собрано яблок \n");
printf("1 б-й = %d, 2 б-й = %d, 3 б-й = %d\n”, weight1,weight2,weight3);
printf("Всего за день собрано %d яблок\n ",weight1+weight2+ weight3);
printf("Заработок в 1-й бригаде=%f\n", (float)weight1*cost/worker1);
printf("Заработок в 2-й бригаде=%f\n", (float)weight2*cost/worker2);
printf("Заработок в 3-й бригаде=%f\n", (float)weight3*cost/worker3);
}
МАССИВЫ
Одномерные массивы
Массив - это набор переменных, расположенных последовательно в памяти, имеющих одно имя и отличающихся друг от друга числовым признаком.
float mas [20]; - объявляет массив mas, состоящий из 20 членов или элементов. 1 элемент mas [0], последний mas [19].
mas [5] = 32.54; присваивание значения элементу массива
float y = mas[5];
Массивы могут быть образованы из данных любого типа. Одномерные массивы называются вектором, двумерные – матрицей.
4б 4б 4б
Обращение к элементу массива осуществляется с помощью индекса. Индекс изменяются от 0 до n-1, где n размерность массива.
Для работы с массивами часто используются циклы.
#include <stdio.h>
void main (void) {
int i, a[10];
for (i=0; i<10; i++)
scanf (" %d",&a[i]); //ввод с клавиатуры
printf ("Вывести следующие результаты \n");
for (i=0; i<10; i++)
printf (" %5d", a[i]); // вывод на экран.
}
Многомерные массивы
Определяются в программе также как и одномерные с указанием размерности каждого индекса в квадратных скобках.
float rain[5][12];
Количество выделяемой памяти рассчитывается как 4*5*12 байт.
Каждый индекс изменяется от 0 до n-1. В памяти все элементы располагаются последовательно, но индексы меняются следующим образом:
//Пример программы ввода кол-ва осадков помесячно за 5 лет и расчета среднего за каждый год и за 5 лет
void main(void){
int i,j;
float mas[5][12], sumyear, sum=0;
for (i=0; i<5; i++){
printf("Ввести кол-во осадков за %d год помесячно\n", i+1);
sumyear=0;
for (j=0; j<12; j++){
scanf ("%f",&mas[i][j]);
sumyear+=mas[i][j];
}
sum+=sumyear/12;
printf(Ср. за %d год = %.2f\n”,sumyear/12);
}
printf(Ср. за 5 лет = %.2f\n”,sum/5);
}
ФУНКЦИИ
Функция – это фрагмент программы со своим именем, к которому можно обратиться для выполнения необходимых действий.
Функция содержит как данные, так и операции над этими данными. Если для объекта имя ссылается на область памяти, где он хранится, то и имя функции ссылается на начало кода этой функции. Функции в Си играют ту же роль что и функции, программы, процедуры в других языках.
- они освобождают от повторного программирования, если конкретную задачу нужно решать в программе несколько раз.
- повышают уровень модульности программы, облегчают её чтение, внесение изменений, коррекцию ошибок. Например:
void main (void){
float list[50];
read list (list); // ввод набора чисел
sort list (list); // сортировка
average (list); // поиск среднего
bargaph (list); // печать графика
}
- cозданные функции можно использовать и в других программах.
Функции бывают библиотечные и пользовательские. Для использования библиотечных функций нужно указать заголовочный файл, в которых они объявлены (директива #include).
Параметры функции
Вернёмся к рассмотренной задаче. Пусть функция starbar() печатает любой символ, указанный в вызывающей программе. Он передается в функцию как аргумент.
#inсlude <stdio.h>
void starbar (char); // объявление функции
void main (void) {
starbar ('_'); // вызов функции
printf ("ПГУ");
printf ("им.Т.Г.Шевченко");
printf ("25 октября, 200");
starbar('#'); // вызов функции
}
void starbar (char x) { // определение функции
int count;
for (count=1; count<=65; count++)
putchar (x);
putchar ('\n');
}
Определение функции начинается с заголовка void starbar (char x) {
Переменная x - является формальным параметром. Это новая переменная и под нее должна быть выделена отдельная ячейка памяти. При вызове функции мы присваиваем формальному аргументу значение фактического аргумента.
starbar (‘-‘); x = '-';
Фактический аргумент может быть константой, переменной или сложным выражением.
Можно передавать в функцию несколько фактических аргументов, разделенных запятыми.
printnum (int i, int j) {
printf ("Первый аргумент %d, вторй аргумент %d\n", i, j);
}
Inline-функции
Перед определением функции может быть использован спецификатор inline для того, чтобы компилятор помещал код функции непосредственно в место вызова функции.
#include <stdio.h>
#include <conio.h>
#include <dos.h>
inline float Circle(float r) {
return 2*3.14*r;
};
void main(void)
{
float y;
y = Circle(2);
printf(“%.2f\n”,y);
}
Это увеличивает код программы, но ведет к увеличению быстродействия работы программы. Inline-функции не должны содержать сложные программные конструкции.
Перегрузка функций
Имена функций могут быть перегружены в пределах одной области видимости. Компилятор отличает одну функцию от другой по сигнатуре. Сигнатура задается числом, порядком следования и типами ее параметров.
#include <stdio.h>
#include <string.h>
int Name (int first) {
return first*first;
}
int Name (unsigned first) {
return first*first;
}
char Name (char first) {
return first*first;
}
int Name (int first,char *second) {
return first*strlen(second);
}
float Name (float r) {
return r*r;
}
double Name (double r) {
return r*r;
}
void main(void) {
printf("%d\n", noName(4));
printf("%d\n", noName((unsigned)4));
printf("%c\n", noName('c'));
printf("%d\n", noName(4,"cлово"));
printf("%0.2f\n", noName((float)1.2));
printf("%0.2lf\n", noName((double)1.2));
}
Глобальные переменные
1. Extern - внешние переменные
Хранятся в области данных программы. Определяются до main() и доступны в любой функции программы. Время жизни - программа. При определении инициализируются по умолчанию 0 на стадии компиляции. Область видимости вся программа.
int count;
void main (void){
count ++;
.........
}
fun (){
printf ("%d\n", count);
}
Переменная count является внешней и доступна в обеих функциях.
Если в программе есть одноименная локальная переменная, она закрывает глобальную переменную. Для расширения видимости операция расширения доступа ::
int count;
void main (void){
int count; //автоматическая переменная
::count++;
..........
printf(“%d”,::count);
}
void fun (void){
count ++;
printf ("%d\n",count);
}
Если переменная определяется в одном модуле, но к ней есть обращение в другом, то нужно обязательно это указать, объявив ее как внешнюю, иначе будет создана новая переменная с этим именем.