Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конспект лекций 1-21.docx
Скачиваний:
4
Добавлен:
01.03.2025
Размер:
434.58 Кб
Скачать

Лекция 26. Передача значений через глобальные переменные.

Областью дей­ствия описания программного объекта называется часть програм­мы, в пределах которой действует (учитывается) это описание. Если переменная описана внутри некоторого блока, то она локализо­вана в этом блоке и из других блоков, внешних по отношению к данному, «не видна». Если описание переменной находится вне блока и предшествует ему в тексте программы, то это описание действует внутри блока и называется глобальным. Глобальная пе­ременная «видна» из блока. Например:

double x;

int funс1() {int у;... } void main() {float у;...}

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

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

Пример 6.

int z; //Описание глобальной переменной

void MAX(int х, int у)

{if (x>y) z=x; else z=y;}

#include <iostream.h>

void main()

{ int a,b,c;

cout«"a="; cin»a;

cout«"b="; cin»b;

cout«"c="; cin»c;

MAX(a,b);

MAX(z,c);

cout«"max="«z; }

Результат выполнения функции max заносится в глобальную переменную z, которая «видна» также и из основной функции. Поэтому при втором обращении эта переменная играет одновре­менно роль аргумента и результата. Здесь оператор обращения к функции выглядит подобно обращению к процедуре в Паскале, а глобальная переменная z играет роль var-параметра.

Классы памяти. Под всякую переменную, используемую в про­грамме, должно быть выделено место в памяти ЭВМ. Выделение памяти может происходить либо на стадии компиляции (компо­новки) программы - либо во время ее выполнения. Существуют 4 класса памяти, выделяемой под переменные:

  • автоматическая (ключевое слово auto);

  • внешняя (extern);

  • статическая (static);

  • регистровая (register).

Под глобальные переменные выделяется место во внешней памя­ти (не нужно думать, что речь идет о магнитной памяти; это опе­ративная память класса extern). Глобальную переменную можно объявить либо вне программных блоков, либо внутри блока с клю­чевым словом extern. Обычно это делается в тех случаях, когда программный модуль хранится в отдельном файле и, следователь­но, отдельно компилируется.

Пусть, например, основная и вспомогательная функции хра­нятся в разных файлах.

Пример 7.

Файл 1: Файл 2:

int var void funcO

void main() { extern int var;

{var=5; var=10*var;

funcO; }

cout«var;

}

Здесь обмен значениями между основной и вспомогательной функцией f unc () происходит через общую глобальную перемен­ную var, для которой во время компиляции выделяется место во внешнем разделе памяти. В результате выполнения данной про­граммы на экран выведется число 50.

Локальные переменные, объявленные внутри блоков, распреде­ляются в автоматической памяти, работающей по принципу стека. Выделение памяти происходит при входе выполнения програм­мы в блок, а при выходе из блока память освобождается. Клю­чевое слово auto писать необязательно (подразумевается по умолчанию).

Статическая память выделяется под переменные, локализован­ные внутри блока, но в отличие от автоматической памяти не освобождается при выходе из блока. Таким образом, при повтор­ном вхождении в блок статическая переменная сохраняет свое прежнее значение. Пример объявления статической переменной:

f О

{static int schet=10; ...}

Инициализация статической переменной происходит толь­ко при первом вхождении в блок. Если инициализация явно не указана, то переменной автоматически присваивается нулевое начальное значение. Статические переменные можно использо­вать, например, для организации счетчика числа вхождений в блок.

Регистровая память выделяется под локальные переменные. Регистры процессора — самый быстрый и самый маленький вид памяти. Они задействованы при выполнении практически всех операций в программе. Поэтому возможность распоряжаться ре­гистровой памятью лучше оставить за компилятором.

Наконец рассмотрим пример, в котором используются различ­ные способы описания переменных.

Пример 8.

int var //описана внешняя переменная var

main ()

{extern int var; // та же внешняя переменная var

}

funс1 ()

{extern int varl;//новая внешняя переменная varl

//внешняя var здесь также видна }

func2()

{... //здесь переменная var видна, а переменная

} // varl не видна

int varl; //глобально описана переменная varl

func3()

{ int var; //здесь var — локальная переменная,

//видна внешняя переменная varl }

func4 ()

{auto int varl; //здесь varl —локальная переменная,

//видна внешняя глобальная var

}

Лекция 27.

Рекурсивные определения функций.

Проил­люстрируем определение рекурсивной функции на классическом примере вычисления факториала целого положительного числа.

long Factor(int n)

{ if (n<0) return 0;

if (n==0) return 1;

return n*Factor(n-1); }

В случае если при вызове функции будет задан отрицательный аргумент, она вернет нулевое значение — признак неверного об­ращения.

Лекция 28.

Структуры

Это структурированный тип данных, представляющий собой поименованную совокупность разнотип­ных элементов. Тип структура обычно используется при разра­ботке информационных систем, баз данных.

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

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

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

Формат описания структурного типа следующий:

struct имя_типа

{определения_элементов};

В конце обязательно ставится точка с запятой (это оператор). Для рассмотренного примера определение соответствующего структурного типа может быть следующим:

struct student {char fam[30]; int kurs;

char grup[3];

float stip;

};

После этого student становится именем структурного типа, который может быть назначен некоторым переменным. В соответ­ствие со стандартом Си это нужно делать так:

struct student studl, stud2;

Правила Си++ разрешают в этом случае служебное слово struct опускать и писать

student studl, stud2;

Здесь studl и stud2 — переменные структурного типа. Допускаются и другие варианты описания структурных переменных. Можно вообще не задавать имя типа, а описывать сразу переменные:

struct {char fam[30]; int kurs;

char grup[3];

float stip;

studl, stud2, *pst;

}

В этом примере кроме двух переменных структурного типа объяв­лен указатель pst на такую структуру. В данном описании можно было сохранить имя структурного типа student.

Обращение к элементам (полям) структурной величины про­изводится с помощью уточненного имени следующего формата:

имя_структуры.имя_элемента

Примеры уточненных имен для описанных выше переменных:

studl.fam; studl.stip

Значения элементов структуры могут определяться вводом, при­сваиванием, инициализацией. Пример инициализации в описании:

student studl={"Кротов", 3, "Ф32", 350}; Пусть в программе определен указатель на структуру

student *pst, studl;

Тогда после выполнения оператора присваивания

pst=&studl;

к каждому элементу структурной переменной studl можно обра­щаться тремя способами. Например, для поля f am

studl.fam или (*pst).fam или pst->fam

В последнем варианте используется знак операции доступа к эле­менту структуры: —>. Аналогично можно обращаться и к другим элементам этой переменной:

pst->FIO, pst->grup, pst->stip.

Поля структуры могут сами иметь структурный тип. Такие ве­личины представляют многоуровневые деревья.

Допускается использование массивов структур. Например, све­дения о 100 студентах могут храниться в массиве, описанном следующим образом:

student stud[100];

Тогда сведения об отдельных студентах будут обозначаться, например, так: stud [ 1 ] . fam, stud [ 5 ] . kurs и т. п. Если нужно взять первую букву фамилии 25-го студента, то следует писать:

stud[25].fam[0].

Пример 1. Ввести сведения об N студентах. Определить фамилии студентов, получающих самую высокую стипендию.

#include <stdio.h>

#include <conio.h>

void main()

{

const N=30; int i; float maxs; struct student {char fam[15];

int kurs;

char grup[3];

float stip;

}

student stud[N];

clrscr ();

for(i=0;i<N;i++)

{ printf ("%d-й студент", i) ;

printf("\n"Фамилия:");scanf("%s",&stud[i].fam);

printf ("Курс: ") ; scanf ("%d", &stud[i] . kurs) ;

printf("Группа:"); scanf("%s",&stud[i].grup);

printf("Стипендия:"); scanf("%f",&stud[i].stip);

}

maxs=0; for(i=0;i<N;i++)

if(stud[i].stip>maxs) maxs=stud[i].stip; printf("\n Студенты,получающие максимальную стипендию %f py6.",maxs);

for(i=0; i<N; i++)

if(stud[i].stip==maxs) printf("\n%s",stud[i].fam);

}