Разработка комплексов программ на языке С для решения прикладных задач. Учебное пособие
.pdf1.const – говорит компилятору о том, что переменная не может изменяться в процессе исполнения программы:
Пример: const int i = 1;
2.volatile (изменчивый) – говорит о том, что переменная может быть изменена внепрограммно.
Пример: volatile int i;
Допустимо одновременное использование const и volatile: Пример:
volatile const int i = 1;
Примеры возможных значений констант в зависимости от используемого для них типа данных приводятся в таблице 5.
Таблица 5
|
Примеры констант |
|
|
|
|
Тип |
|
Пример констант |
char |
|
„a‟ „\n‟ „9‟ |
int |
|
1 123 -234 |
float |
|
123.3 4.3e-3 0.3E5 |
double |
|
123.3 4.3e-3 0.3E5 (то же, что и для float) |
1.3. Операции
Операторы сравнения и логические операторы
Втермине оператор сравнения слово "сравнение" относится
кзначениям операндов. В термине логический оператор слово "логический" относится к способу, которым устанавливаются эти отношения. Поскольку операторы сравнения и логические операторы тесно связаны друг с другом , мы рассмотрим их вместе. Операторы сравнения и логические операторы приведены в таблице 6.
11
|
|
Таблица 6 |
Операторы сравнения и логические операторы |
||
|
|
|
Оператор |
Обозначения |
Действие |
|
в математике |
|
|
Операторы сравнения |
|
> |
> |
Больше |
>= |
> |
Больше или равно |
< |
< |
Меньше |
<= |
< |
Меньше или равно |
== |
= |
Равно |
!= |
≠ |
Не равно |
|
Логические операторы |
|
&& |
˄ |
И |
|| |
˄ |
ИЛИ |
! |
– |
НЕ |
Оператор присваивания
Оператор присваивания (=) не обязан стоять в отдельной строке и может входить в более крупные выражения. Составные операторы присваивания объединяют логические и арифметические операторы с оператором присваивания.
Условный оператор
Условный оператор обозначается 2-мя символами „?‟ и „:‟ Синтаксис:
<условие> ? <выражение1> : <выражение2>
/* если условие = true, то выполняется выражение1, иначе – выражение2 */
Пример:
a = 1 ? 2 : 3; // a = 2 b = 0 ? 2 : 3; // b = 3 c = -1 ? 2 : 3; // c = 2
Инструкции if, if ...else
Синтаксис: if (условие)
<инструкции;>
12
Пример 1: if (x<y) x++;
Пример 2: if (x<y)
{
x++; y--;
}
Синтаксис: if (условие)
<инструкция1;> else
<инструкция2;>
Инструкция switch
Синтаксис:
switch (выражение)
{
case конст1: инстр.1; case конст2: инстр.2;
.....
case констN: инстр.N; default: инстр.;
}
Пример 3: int a=2, b=0; switch(a)
{
case 0: case 1:b++;
case 2:b+=2; case 3:b+=3;
}
//b=5;
Замечание 1: инструкция с меткой default. Замечание 2: вариант default – в любое место.
13
Инструкция while
Синтаксис:
while (выражение) <инструкции;> Инструкция do...while Синтаксис:
do
{
<инструкции;>
}
while (выражение); Пример :
int a=-2; do
a++;
while(a);
//a=?
Инструкция for
Синтаксис:
for (инициализация; условие; выражение) <инструкции;> Пример:
int x;
for (x=0;x<100;x++) printf (“%d”, x);
Здесь инициализация выполняется один раз перед началом цикла. Выражение вычисляется после каждой операции цикла. Условие проверяется каждый раз перед выполнением инструкции. Замечание: инициализация, условие, выражение могут отсутствовать.
Инструкция break
Прекращает работу блока switch и циклов. Пример:
int a=2, b=0; switch(a)
{
14
case 0: break; case 1:
{
b++;
break;
}
}// b=2;
Пример:
int a=-2, b=1; while (a)
{
a++; b--; if (!b)
break;
} //a=-1;
Инструкция continue
Завершает текущую операцию цикла и передает управление на вычисление условия цикла.
Пример:
int a=-2, b=1; while (a)
{
a++;
if (!(a+b)) continue; b--;
}// a=0, b=0
Инструкция goto
Выполняет безусловный переход к другой инструкции внутри того же файла. Замечание: goto используется только для выхода наверх из нескольких вложенных управляющих инструкций.
Пример: while (a)
{
15
...
while (b)
{
...
while(c)
{
...
if (!c) goto m;
}
}
}
m: printf(“error”);
Контрольные вопросы
1.Что называется идентификатором?
2.Как обычно записываются числа в языке программирования С? Привести примеры.
3.Что означает и определяет тип данных?
4.Дать понятие переменной. Что необходимо выполнить для ее использования?
5.Перечислите базовые типы данных?
6.Перечислите целочисленные типы данных?
7.Назвать вещественные типы языка С.
8.Как представляются символьные данные в языке С?
9.Что означает тип void?
10.Какую структуру имеет программа?
11.Поясните понятия «операция» и «операнд». Перечислите виды операций.
12.Какие существуют операции отношения и логические операции?
13.Какие операции относятся к операциям присваивания?
14.На какие группы делятся операции присваивания? Привести примеры.
15.Какие существуют операторы перехода в языке С?
16.Для чего используют операторы break, continue и return?
16
2. СТРУКТУРИРОВАННЫЕ ТИПЫ ДАННЫХ
2.1. Одномерные массивы
Язык программирования С позволяет создавать переменные сложных типов данных, основанных на базовых типах или на типах, определенных пользователем.
Одномерным массивом называется набор данных одного типа. В языке С различают статические и динамические массивы. Статический массив описывается следующим образом:
int x[15]; // описание массива из 15 целочисленных элементов.
Память для хранения статического массива выделяется автоматически непосредственно после описания. Таким образом, для хранения массива x выделено 60 байт.
Нумерация элементов массива начинается с 0. Для обращения к заданному элементу массива используются []. Например, фрагмент программы:
int x[5]; x[0]=10;
задает значение элемента с индексом 0. Таким образом, могут быть заданы значения всех элементов массива.
Инициализация статического массива может быть проведена и при описании:
float y[5] = {1.1,2.2,3.3,4.4,0.05};
В этом случае y[0] = 1.1, y[1] = 2.2, y[2] = 3.3, y[3] = 4.4, y[5] = 0.05.
Основные ошибки при работе со статическими массивами:
обращение к несуществующему элементу массива, например, в программе объявлен массив из 10 переменных, а обращаются к элементу с индексом 10, такая ошибка относится к разряду логических ошибок, не определяющихся при компиляции;
использование еще не проинициализированных элементов массива также относится к логическим ошибкам, например, в следующем фрагменте программы массив x описан, но не про-
17
инициализирован, тем не менее, элемент массива с индексом 0 участвует в вычислении значения переменной y:
int x[10];
int y =x[0]+15;
Значение переменной y в этом случае не может быть определено однозначно.
Если программа должна уметь обрабатывать массивы произвольной размерности, целесообразней использовать динамические массивы. При описании указателей Вы познакомились с функциями выделения памяти malloc() и calloc(). В рассмотренном примере память выделялась под один элемент. Язык С позволяет выделить память под несколько элементов:
int* x = (int*)malloc(sizeof(int) *15); /* выделение памяти под массив из 15 элементов */
Таким образом, понятия «указатель» и «массив» очень тесно связаны между собой. Имя массива в С – это указатель на первый элемент массива. Обращение к элементу динамического массива с заданным индексом не отличается от обращения к элементу статического массива. Инициализировать элементы динамического массива возможно только поэлементно, после выделения необходимой памяти. Следующий фрагмент программы описывает и инициализирует элементы динамического массива x.
int *x,i; int n = 5;
x = (int*) malloc(sizeof(int)*n); for(i=0;i<n;i++) x[i]=i;
После выполнения этого фрагмента программы элементы массива x определены следующим образом:
x[0]=0,x[1]=1,x[2]=2,x[3]=3,x[4]=4.
Освобождение памяти после работы с динамическими массивами нужно выполнять следующим образом:
free(x); – функция стандартной библиотеки языка С, предназначенная для освобождения ранее выделенной динамической памяти. Функция принимает указатель на область памяти, подлежащую освобождению, или NULL.
18
Основная ошибка при работе с динамическими массивами – не выделение памяти под массив. Эта логическая ошибка приводит к совершенно непредсказуемым результатам работы программы.
2.2. Многомерные массивы
Многомерные массивы принято называть матрицами. Матрица – это таблица однотипных данных, имеющая заданное количество строк и столбцов. По определению, каждый элемент характеризуется двумя индексами – номером строки и номером столбца. Статические матрицы в С описываются следующим образом:
float y[5][4]; /* вещественная матрица из 5 строк и 4-х столбцов. */
Обращение к элементу матрицы, находящемуся в i-й строке и j-м столбце – y[i][j]. Всегда первый индекс – номер строки, второй индекс – номер столбца. Инициализация элементов статической матрицы может выполняться при описании:
int z[2][2] = {1,2,3,4};
Элементы при такой инициализации записываются построчно, то есть, элементы строки с номером 0 – {1,2}, строки с номером 1 – {3,4}.
При работе с матрицами разной размерности возможно использование динамических матриц. Если одномерный массив описывается в С как указатель, матрица описывается как указатель на указатель. Обязательно выделение памяти, которое проводится по следующему алгоритму:
1)под указатель на указатель выделяется память под массив указателей (каждый элемент этого массива сам будет массивом);
2)под каждый элемент полученного массива указателей выделяется память под одномерный массив.
Ниже приведен фрагмент программы, описывающий динамическую матрицу и выделяющий память для элементов такой матрицы.
19
int **M;
int n = 10,i; // количество строк int m = 5; // количество столбцов
M = (int**)malloc(sizeof(int*)*n);
for(i=0;i<n;i++) M[i] = (int*)malloc(sizeof(int)*m);
Освобождение занятой памяти происходит в обратном порядке:
for(i=n-1;i>=0;i--) free(M[i]); free(M);
2.3. Строки
Определение и инициализация строк
Литерал – строковые константы, заключенные в двойные кавычки в отличие от символов. Строкой называется массив символов, который заканчивается символом "пусто" "\0" (нулевой байт). Поэтому строка объявляется как обычный символьный массив:
char *str; char str[10];
При инициализации строки размерность массива лучше не указывать.
Пример:
char *str="This is a string"; char str[]="This is a string";
Стандартные функции для работы со строками
Стандартные подпрограммы обработки строк (функции семейства str...) описаны в библиотеке string.h. Ниже описание этих функций приводится в виде:
<тип результата><имя функции>(<формальные параметры>); Предполагается, что существуют следующие описания: char c, ch;
char *string1, *string2; int m;
20
