Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Язык С начало.doc
Скачиваний:
11
Добавлен:
31.07.2019
Размер:
132.61 Кб
Скачать

Начнем изучать основные конструкции языка С, рассматривая в качестве примера конкретную программу. Большинство учебников языка С начинаются с программы, которая печатает “Здравствуй, Мир!”. Мы пойдем нетрадиционным путем и в качестве первой программы решим задачу поиска наименьшего элемента целочисленного массива.

#include<iostream.h> // 1

int minim(float a[], int n); // 2

float b[5]={3,2,0,4,7}; // 3

int main(void){

int no; // 4

no=minim(b,5); // 5

cout << “Наименьший элемент b[” << no << “]=” << b[no]; // 6

return(0); // 7

}

int minim(int a[],int n){ // 8

int nom=0; // 9

for(int i=1;i<n;i++) // 10

if( a[i]<a[nom] ) // 11

nom=i; // 12

return(nom); // 13

} // 14

Прокомментируем программу.

Строка 1 представляет собой директиву препроцессора. (Напомнить, что такое препроцессор и как осуществляется компиляция программы)

Строка 3 – это объявление и инициализация массива. Увидев данную строку, машина выделяет память под 5 целых переменных b[0], b[1],… b[4] и присваивает данным переменным значения 3,2,0,4,7.

Строки 4 и 8 – это объявления целых переменных. Поскольку переменные объявлены внутри функций, они являются локальными. Это означает, что переменная no видна только внутри функции main (если говорить более точно, ее область видимости – от точки, в которой она была объявлена, до конца функции), а переменная nom видна только внутри функции minim. В отличие от данных переменных, массив b объявлен как глобальная переменная (он виден обеим функциям - и main, и minim).

Строка 6 выводит данные на экран.

В данном случае на экране будет напечатано

Наименьший элемент b[2]=0;

Для поклонников классического языка С возможен вариант

printf(“Наименьший элемент b[%d]=%d”, no , b[no]);

Программы на языке С состоят из функций. Каждая функция решает отдельную задачу. В программе должна быть функция main, с которой начинается работа программы. В нашей программе есть еще функция minim, которая находит минимальный элемент массива.

Строка 2 представляет собой объявление функции minim. Объявление функции задает ее имя, тип возвращаемого значения и список передаваемых параметров. В данном случае функция minim зависит от целочисленного массива a, целой переменной n и возвращает целое значение. Возможны следующие варианты объявления функции minim:

int minim(float a[100], int n);

int minim(float *a, int n);

int minim(float *, int );

Строки 8-14 – это определение функции minim. Определение функции, содержит, кроме объявления, тело функции. Строка 13 – это оператор возврата. В строке 5 осуществляется вызов данной функции. При вызове вместо формальных параметров a и n подставляются фактические параметры b и 5. Далее выполняется тело функции (строки 9-13) до тех пор, пока не встретится оператор return. Увидев данный оператор, функция прекращает работу и возвращает управление в точку вызова (т.е. в строку 5). При этом также возвращается значение nom, которое и будет присвоено переменной no в строке 5.

В теле функции minim и происходят основные вычисления. Алгоритм поиска минимума заключается в следующем. Последовательно просматриваем элементы нашего массива. Номер самого маленького из уже просмотренных элементов держим в переменной nom. Сначала nom равно 0. Как только просматриваемый элемент оказывается меньше a[nom], кладем в nom его номер. После того, как просмотрим весь массив, переменная nom будет равна номеру наименьшего элемента массива.

Оператор цикла (строки 10-12) осуществляет просмотр массива.

Строки 11-12 составляют тело цикла. Если тело состоит из нескольких операторов, его необходимо заключать в фигурные скобки.

Упр. Нарисовать блок-схему работы данного цикла.

Простые переменные.

Переменная – это именованная область памяти, в которой хранятся данные определенного типа.

Переменная имеет имя, значение, класс памяти, адрес, тип, время жизни и область действия.

Перед использованием переменную необходимо объявить.

Пример.

static int x =5;

Увидев данное объявление, машина выделяет память (для 2 или 4 байта в зависимости от компилятора, в BC3.1 – 2 байта) под переменную x и присваивает ей значение 5.

Имя – x

Значение – 5

Класс памяти – static

Тип – int

Адрес - &x

Область действия и время жизни зависят от того, в каком месте программы данная переменная объявлена.

Тип переменной определяет:

  1. Формат представления в памяти компьютера

  2. Множество допустимых значений, которые может принимать принадлежащая к выбранному типу переменная.

  3. Множество допустимых операций, применимых к этому типу

Простые (базовые) типы данных языка С:

Тип

Название

Размер в байтах

Область значений

char

Символьный

1

От –128 до 127

int

Целый

Зависит от реализации (В TC2.0 и BС3.1 – 2 байта )

short

Короткий целый

2

От –32768 до 32767

long

Длинный целый

4

От –2 147 483 648 до 2 147 483 647

unsigned char

Беззнаковый символьный

1

От 0 до 255

unsigned

Беззнаковый целый

Зависит от реализации (В TC2.0 и BС3.1 – 2 байта

unsigned short

Беззнаковый короткий целый

2

От 0 до 65535

unsigned long

Беззнаковый длинный целый

4

От 0

до 4 294 967 295

float

Плавающий одинарной точности

4

От 3.4Е-38

до 3.4Е38

double

Плавающий двойной точности

8

От 1.7Е-308

до 1.7Е308

long double

Длинный плавающий двойной точности

10

От 3.4Е-4932

до 1.1Е4932

enum

Перечислимый тип

Показать на примере, как по размеру переменной найти область ее значений.

Перечислимый тип.

Перечислимый тип применяется, если мы хотим, чтобы переменная принимала “говорящие” значения.

Пример.

enum cifra{

nol,

odin,

dva

};

Теперь можно объявить переменную данного типа:

enum cifra x;

Переменная x будет принимать значения nol, odin, dva.

x = 1 и x = odin - это одно и то же.

Содержательный пример.

В файле graphics.h задан тип

enum colors{

BLACK,

BLUE,

GREEN,

CYAN,

RED,

MAGENTA,

BROWN,

LIGHTGRAY,

DARKGRAY,

LIGHTBLUE,

LIGHTGREEN,

LIGHTCYAN,

LIGHTRED,

LIGHTMAGENTA,

YELLOW,

WHITE

};

Таким образом, setcolor(4) и setcolor(RED) – это одно и то же.

Адрес переменной.

&x – это адрес переменной x.

Можно его распечатать

printf(“%p”,&x);

Получим нечто вроде 5B79:03AC.

Первая половина – номер сегмента, вторая половина – смещение.

Операция & - взятие адреса (по переменной находит ее адрес). Операция * - снятие адреса (по адресу переменной находит ее значение).

Подробный разговор про адреса будет, когда будем изучать тему “указатели”.

Прежде, чем говорить о времени жизни переменных и об областях действия, вспомним, как составлять программы из нескольких модулей (файлов).

Программы, состоящие из нескольких модулей.

(для компилятора BC3.1)

Как составить программу из нескольких файлов?

Пусть имеется 2 файла: file1.cpp и file2.cpp.

Создаем файл проекта с расширением .prj (Например, osn.prj).

В нем пишем:

file1.cpp

file2.cpp

В меню project\open project заносим имя проекта: osn.prj.

После этого компилируем, отлаживаем и выполняем программу обычным образом.

Область действия и время жизни переменной .

Блок – последовательность команд, заключенная в фигурные скобки.

По времени жизни переменные делятся на глобальные и локальные.

Глобальным переменным в течение всего времени выполнения программы отведена ячейка памяти.

Локальной переменной выделяется новая ячейка памяти при каждом входе в блок, в котором она определена. При выходе из блока память освобождается, переменная теряет значение.

Внешний уровень – за пределами всех блоков.

Внутренний уровень – внутри блока.

Переменные, определенные на внешнем уровне, имеют глобальное время жизни.

Переменные, определенные на внутреннем уровне, имеют локальное время жизни. Но можно, указав класс памяти static, сделать его глобальным.

Область действия переменной – в каких участках программы допустимо использование имени переменной.

Уровень

Класс памяти

Время жизни

Область действия

Примечание

Внешний

static

Глобальное

Остаток исходного файла

Внешний

extern

Глобальное

Остаток исходного файла

Можно сделать видимым в других файлах

Внутренний

extern

Глобальное

Блок

Внутренний

static

Глобальное

Блок

Внутренний

Auto или register

Локальное

Блок

Пример 1.

int x=1;

main(){

printf(“x=%d ”,x);

{ int x=2;

printf(“x=%d ”,x);

{ int x=3;

printf(“x=%d ”,x);

}

printf(“x=%d ”,x);

}

printf(“x=%d ”,x);

}

Результат: x=1 x=2 x=3 x=2 x=1

Пример 2.

void f(void);

void main(void){

f();

f();

}

void f(void){

int i=0;

printf(“%d”,i);

i++;

}

Результат: 00.

Если вместо int i=0 написать static int i=0, то результат будет 01.

Пример 3.

Программа состоит из двух файлов.

file1.c

file2.c

#include<stdio.h>

#include<conio.h>

extern int i;

extern void funk(void);

void main(void){

//место 1

funk();

//место 2

printf(“i=%d”,i);

getch();

}

int i=5;

void funk(void){

//место 3

i++;

}

Результат: i=6;

Если вставить i=1 на место 1, то результат i= 2.

Если вставить i=1 на место 2, то результат i= 1.

Если вставить int i=3 на место 3, то результат i= 5.

Если вместо int i=5 написать int i, то результат i= 1.

Если вместо int i=5 написать extern int i=5, то результат i= 6

Если вместо int i=5 написать extern int i, то результат ошибка.

В file1.cpp пишем extern int i=5, в file2.cpp пишем extern int i, результат i=6

В file1.cpp пишем extern int i=5, в file2.cpp пишем static int i, результат i=5.