ФУНКЦИИ. ИСПОЛЬЗОВАНИЕ МАССИВОВ И ФУНКЦИЙ В КАЧЕСТВЕ ФОРМАЛЬНЫХ ПАРАМЕТРОВ




Цель работы

Изучение способов обработки массивов данных с помощью функций.

 

Методические указания

Передача массивов в качестве аргументов функции. Простой способ передачи массива функции демонстрирует пример 1:

#include <stdio.h>

void print(int* massiv); /*Прототип функции*/ void main(void) { intv[3],i; for (i=0; i<3; i++) v[i]=i;

print(v); /*Вызов функции и передача адреса массива*/ for (i-0; i<3; i++) printf("%d ",v[i]);

} void print(int mass[3]

{ int i; for(i=0;i<3;i++) printf("%d ",mass[i]++); printf("\n");}

В результате работы этой программы на экране увидим:

012 123.

До вызова функции print массив v содержал элементы 0, 1 и 2. Функция print приняла адрес массива v и присвоила этот адрес переменной mass. После вы­вода каждое значение массива mass (первая строка результатов) увеличивает­ся на единицу. Поскольку переменная mass указывает на массив v, на единицу увеличились элементы массива v (вторая строка результатов). Другими сло­вами, массивы v и mass расположены в одной и той же области памяти, и из­менение в mass означает изменение в v.

В этом примере размер массива, обрабатываемого функцией print, дол­жен быть известен до компиляции. Такая реализация необязательна: функции print нужен лишь начальный адрес массива, а количество элементов можно передать еще одним аргументом, как в примере 2:

void print(int* massiv, int lines); /*Прототип функции*/

void main(void)

{ int v[3],i; for (i=0; i<3; i++) v[i]=i;

print(v,3); /*Передаем адрес массива и количество элементов*/ for(i=0;i<3;i++)printf(“%d",v[i]);

}

void print(int mass[], int m)

{ int i; for (i = 0); i<m; i++) printf("%d ",mass[i]++); printf("\n");}

Результаты, выводимые на экран, не изменились. Но теперь, при изме­нении в функции main размера массива v нет необходимости что-либо менять в функции print. Как и в примере 1, массивы v и mass расположены в одной и той же области памяти, и изменение в mass означает изменение в v.

Общее в примерах 1 и 2 в том, что массив в функцию можно передать и как ссылку на его первый элемент. Например, в примере 2 массив в функцию print можно передать так:

Пример 3.

void print(int* mass, int m)

{ int i; for (int i = 0; i<m; i++) printf("%d ",mass[i]++); printf("\n");}

В случае многомерных массивов многое совпадает со случаем одномер­ного массива. Рассмотрим примеры с двумерным массивом:

Пример 4.

#include <stdio.h>

void print(int matrix[2][3]); /*Прототип функции*/

void main(void)

{ int v[2][3], i, j; for (i=0; i<2; i++) for (j=0; j<3; j++) v[i][j]=i+j;

print(v); /*Вызов функции и передача адреса массива*/

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

{ for (j=0;j<3;j++) printf("%d",v[i] [j]); printf("\n");}

} void print(int mass[2][3])

{ inti.j;

for (i=0; i<2; i++) { for (J=0;j<3;j++) printf("%d ",mass[i][j]++); printf("\n");}

}

Функция print выводит на экран элементы массива mass (первые две строки) и увеличивает их значения на единицу (последние две строки).

В следующих примерах размеры двумерного массива в функции print определяют с помощью аргументов.

Можно поступить так: сообщить компилятору, что первый параметр -массив строк по 3 элемента, а второй - количество строк.

Пример 5.

void print(int matrix[][3], int lines); /*Прототип функции*/

void main(void)

{ int v[2][3], i, j; for (i=0; i<2; i++) for (j=0; j<3; j++) v[i] [j] = i+j;

print(v,2); /*Передаем адрес массива и количество строк*/'

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

{ for (j=0; j<3; j++) printf("%d ",v[i][j]); printf("\n");}

}

void print(int mass[][3], int m) { int i, j;

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

{ for (j=0; j<3; j++) printf("%d ",mass[i]|j]++); printf("\n");}.

Результаты не изменились. Но теперь при изменении количества строк

матрицы v в функции main не нужно изменять что-либо в функции print.

Этот пример можно развивать далее. Если функция работает лишь с одной строкой двумерного массива, то можно передать адрес этой строки.

Пример 6. void print(int* massiv, int columns);

void main(void) { int v[2][3], i, j; for (i=0; i<2; i++) for (j=0; j<3; j++) v[i][j]=i+j;

for (H); i<2; i++)

print(v[i],3); /"'Передаем адрес строки и количество элементов*/ for (i=0; i<2; i++) { for (j=0; j<3; j++) printf("%d ",v[i][j]); printf("\n");}}

void print(int* mass, int n)

(int i; for (i-0; i<n; i++) printf("%d ",mass[i]++); printf("\n");}

Результаты, выводимые на экран, не изменились. Но теперь, при изме­нении любого размера матрицы v нет необходимости что-либо менять в функ­ции print. При таком подходе мы накладываем ограничения на работу функ­ции print: она работает только с одной строкой матрицы.

В примере 7 функция print свободна от таких ограничений и в качестве аргументов принимает адрес первого элемента, количество строк и столбцов матрицы:

Пример 7. void print(int** matrix, int lines, int columns);

void main(void) { int v[2][3], i, j; for (i=0; i<2; i++) for 0=0; j<3; j++) v[i](j]=i+J;

print ((int**)v, 2, 3);

for (i=0; i<2; i++) { for j=0;j<3;j++) printf(“%d",v[i][j]); printf("\n");}}

void print(int** mass, int m, int n)

{ int *p=(int*)mass, i, j;

for (i=0; i<m; i++) { for (j=0;j<n;j++) printf(“%d", р[i*п+j]++); printf("\n");}}

Здесь переменная р является указателем на первый элемент двумерного

массива. Элементы двумерного массива в памяти расположены построчно и непрерывно. То есть, с точки зрения размещения в памяти, двумерный массив представляет собой одномерный массив. Для доступа kj-му элементу i-ой строки достаточно вычислить относительный адрес i*n+j и отсчитать его от первого элемента p[i*n+j].

Результаты, выводимые на экран, не изменились. Но теперь, при изме­нении любого размера матрицы v нет необходимости что-либо менять в функ­ции print, и эта функция свободна от предыдущих ограничений.

Описание имени типа директивой typedef

Директива typedef позволяет связать любой основной или производный тип с некоторым именем, а затем использовать это имя типа. Такое описание используется для создания более коротких или осмысленных имен типов.

Синтаксис описания имени типа:

typedef <описание_типа> <имя1>[,<имя2>...]:

typedef- это ключевое слово компилятора Си.

<описание_типа> может быть именем известного типа (даже из списка <имя1>[,<имя2>...]) или описанием типа. Например:

typedef int MyInt;

typedef MyInt MyInt;

Имена <имя1>[,<имя2>...] становятся синтаксически эквивалентными ключевому слову и именуют тип, указанный в <описание_типа>. Они не мо­гут совпадать с именами переменных, формальных параметров, перечисли­мых констант и функций. Имена могут быть переопределены внутри блоков программы. Имена для типов указателя, структуры или совмещения могут быть объявлены прежде чем эти типы будут описаны. Имена типов можно использовать в описаниях переменных и функций как ссылки на этот тип.

Примеры:

typedef int WHOLE;

typedef void DRAW(int, int);

typedef WHOLE MASSIV[10];

В первом примере объявляется WHOLE как синоним для int.

Во втором примере представлен тип DRAW для функции не возвра­щающей значения и требующей два аргумента типа int. Это означает, напри­мер, что объявление DRAW box; эквивалентно объявлению void box(int, int);

В третьем примере описывается тип массива десяти целых элементов с именем MASSIV, которое можно использовать так:

MASSIV myList;

Указатели на функцию, их использование в качестве параметра функции

Любую функцию можно вызвать или получить ее адрес. Имя "функции, возвращающей...", всегда преобразуется в "указатель на функцию, возвраща­ющую..." (т.е. имя функции это то же, что и указатель на функцию), если только оно не является аргументом вызова другой функции. Можно явно описать «указатель на функцию». Синтаксис описания такой переменной сле­дующий:

<тип> (*<имя>)(<список_формальных_параметров>);

<тип> - это тип возвращаемого значения функций, на которые может затем указывать <имя>.

<список_формальных_параметров> - это список формальных парамет­ров функций, на которые может затем указывать <имя>. Список задается по правилам объявления функций.

Пример.

int myfunc1(double*, int, int); /*Первая функция*/

int myfunc2(double*, int, int); /*Вторая функция*/

int (*myfunc)(double*, int, int); /*Указатель на такие функции*/

void main(void)

{ double x=2.3; int i=4, k=5;

myfunc=&myfunc1; /*Берем адрес вызываемой функции*/ i=(*myfunc)(&x, i, k); /*Вызываем эту функцию (myfunci)*/

}

Для вызова функции по указателю нужно выполнить операцию обратной ссылки *<имя>. Поскольку круглые скобки справа от имени имеют больший приоритет, чем звездочка слева, то операцию обратной ссылки нужно заключить в круглые скобки: (*<имя>). Правила передачи аргументов одинаковы для вызовов по имени функции и по указателю на функцию.

Удобно описать имя типа "указатель на функцию". Например,

typedef int (*MYFUNC)(double*, int, int);

Это имя типа можно использовать различным образом. Например,

MYFUNC myfunc, myfuncs [] =

{ myfunc1, myfunc2, myfunc3, myfunc4 };

означает, что myfunc является указателем на функции, a myfuncs – массивом указателей на функции. Можно описать и инициализировать указатели:

MYFUNC* funcs= myfuncs.

Переменная funcs необязательна для вызова функций. Для вызова можно пользоваться и массивом myfuncs. Но удобно одновременно хранить адрес вызываемой функции и адрес массива указателей на функции.

Вызов функции по индексу тогда выглядит таким образом.

(*funcs[i]) (&x, i, k); /*Вызываем функцию myfunci*/

Указатель на функции может быть формальным параметром функции. Например,

int func(char* с, int sz, MYFUNC f)

{…

if((*f)(&x,i,k)>0)...}

void main(void)

{ …

к=func("Вызов с первой функцией", 15, myfunc1);

}

Массив указателей на функции также может быть формальным пара­метром функции. Например,

typedef MYFUNC funcs[4];

int func(funcs);

функция func принимает массив из 4 указателей на функции и возвращает целое. Функции могут возвращать указатели на функции.

Например,

typedef int F(void);

F*g(...) {/*..*/} или MYFUNC fnctn(...);

 

Пример выполнения задания

 

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

#include <stdio.h> /*Прототипы функций*/ double Add(double, double);

double Sub(double, double);

/"'Описание имени типа указателя на функции*/ typedef double (*MYFUNC)(double, double);

/*Прототип функции, которая вызывает указанную параметром функцию*/ void function(char*, double, double, MYFUNC f);

void main(void) { function("Сумма 4 и 2 равна:", 4., 2., Add);

function("Разность 4 и 2 равна:", 4., 2., Sub);

} double Add(double x, double y) { return x+y;}

double Sub(double x, double y) { return x-y;}

void function(char* str, double x, double y, MYFUNC f)

{ printf("%s %lf\n", str, (*f)(x,y));}

Результаты работы программы на экране отобразятся так:

Сумма 4 и 2 равна: 6 Разность 4 и 2 равна: 2.

 

Контрольные вопросы

1. Что передается функции, если единственный аргумент массив?

2. Как передать адрес строки двумерного массива?

3. Каковы составляющие синтаксиса описания имени типа?

4. Каковы правила описания указателя на функции?

5. Как описать массив указателей на функцию?

6. Каким образом описать функцию в роли формального параметра?

7.Каким образом описать функцию в роли типа возврата?

 

Варианты заданий

 

1. Функция принимает массив символов S1, читает с клавиатуры после­довательность символов S2 и возвращает количество совпадений символов в массивах S1 и S2.

В вариантах 2-15 использовать указатели на функции.

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

3. Решить задачу 2., используя массив указателей на функции.

4. Найти корень уравнения x*x-cos(x)=0 методами Ньютона, итераций и половинного деления.

5. Решить задачу 4., используя массив указателей на функции.

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

7. Решить задачу 6., используя массив указателей на функции.

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

9. Решить задачу 8., используя массив указателей на функции.

10. Для выбора максимального элемента заданного массива по указателю вызвать одну из функций.

11. Решить задачу 10., используя массив указателей на функции.

12. Вычислить f(x)/g(x), где в качестве f(x) и g(x) могут быть четыре различные функции, возвращающие вещественные значения.

13. Решить задачу 12., используя массив указателей на функции,

14. В соответствии с номером выбранного пункта меню выполнить ту или иную функцию.

15. Решить задачу 14., используя массив указателей на функции. 16- Передать функции массив имен и приветствовать всех заданных в массиве по имени (например, «Здравствуйте, Вася!»).

17. Описать функцию, которая принимает массив и транспонирует его.

18. С помощью функции, возвращающей указатель на двумерный мас­сив, с точностью до трех верных знаков решить систему Ах == l х по формуле

– длина вектора хi х0 = {1,0,...,0},i= 0,1,2,...,

А – заданная n*n матрица.

19. Определить массив номеров i максимальных коэффициентов c(i,n)=n!/(i!(n-i)!), 0<i<n<10 для различных n.

20. Вычислить значение полинома

Pn(x)=anxn+ an-1xn-1... +a2x2+a1x + а0 по схеме Горнера

Рn(х)=((an)x+an-1)x+an-2)x +ап-з)х +... +a1x +a0 и значение функции

z(x)= Pn(x)/ Рm(х) при различных значениях х и массивах коэффициентов полиномов.

21. В заданном массиве символов S1 все символы увеличить на величину axn 2+ bxn + c (п – позиция символа в строке, а, b, с - аргументы функции), из полученного массива символов S2 восстановить исходный массив другой функцией. Вернуть количество ошибок восстановления.

22. Вычислить массив коэффициентов c(i,n) при всех степенях полинома (1+х)". Использовать формулы

c(0,n)==c(n,n)=l; c(i,n)=c(i,n-l)+c(i-l,n-l): 0<i<n.

23. Вычислить длину самой длинной строки в массиве строк.

24. Вычислить количество слов в массиве строк и вернуть массив, содержащий количество слов в каждой строке.

25. Преобразовать массив символов в массив целых и вернуть его.

 

Лабораторная работа № 14

 

С Т Р У К Т У Р Ы

 

Цель работы

Изучение производных типов данных. Структуры и объединения.

 

Методические указания

 

1. Назначение структур

 

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

 

2. Описание структурных переменных

 

Для описания структурных переменных прежде всего необходимо указать тип структуры, который определяется так:

struct

{

<список описаний элементов>

} список переменных;

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

Пример:

struct

{

int k; /* список */

float l; /* описаний */

char m; /* элементов */

} список переменных;

Для описания структурных переменных существуют несколько способов:

а) без имени структуры.

В этом случае структурные переменные описываются так:

<тип данных> <список имен структурных переменных>,

где <тип данных > – это тип структуры для переменных, имена которых указаны в списке. Ниже приведены примеры описания структурных переменных.

Пример.

Конструкция

struct

{

int x;

float y;

} a, b, c;

описывает три структурные переменные a, b и c, каждая из которых представляет собой структуру, состоящую из двух элементов x и y.

Пример.

Дата состоит из нескольких частей: день, месяц, год. Для представления даты можно использовать структуру, которая будет иметь элементы: day (день), month (месяц), year (год).

Конструкция

struct

{

int day; /* день */

int month; /* месяц */

int year; /* год */

} date1;

определяет структурную переменную date 1.

б) через определение типа структуры.

При использовании этого способа сначала в программе с типом структуры связывается некоторое имя с помощью ключевого слова typedef:

typedef struct

{

<список описания элементов>

} <имя типа структуры>;

В дальнейшем это <имя типа структуры> можно использовать в программе для определения структурных переменных. Например, для представления комплексного числа можно использовать структуру:

typedef struct

{

float real; /* действит. часть */

float imag; /* мнимая часть */

}

COMPLEX;

Теперь, чтобы определить в программе два комплексных числа, достаточно записать:

COMPLEX A1, A2;

в) через метку структуры.

В этом случае с типом структуры связывается метка структуры:

struct <метка структуры>

{

<список описаний элементов>

};

Теперь, используя метку структуры, можно определить структурные переменные с помощью конструкции:

struct <метка структуры> <список имен структурных переменных>;

Например, пусть дано описание

struct DATE /*DATE – это метка структуры */

{

int day; /* день */

int month; /* месяц */

int year; /* год */

};

Тогда конструкция

struct DATE date 2, date 3, date 4;

определяет три структурные переменные date 2, date 3, date 4.

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

 

3. Обращение к элементам структур

 

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

<имя структуры>. <элемент>

Примеры:

date2. day = 1;

date3. month = 7;

date4. day = 3.

 

4. Инициализация структур, ввод–вывод

 

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

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

struct A

{

int b;

char c;

};

static struct A a 1 = {1, ‘ R ’};

Значения константных выражений из каждого списка инициализаторов присваиваются элементам структуры в порядке их следования. Так, в приведенном выше примере элементу b структуры a 1 присваивается значение 1, а элементу c – значение ‘ R ’.

Если в списке инициализаторов меньше элементов, чем в структуре, то оставшиеся элементы структуры неявно инициализируются нулевыми значениями. Если же число инициализаторов больше, чем требуется, то выдается сообщение об ошибке.

Ниже приведен пример, иллюстрирующий инициализацию структуры и ввод–вывод элементов структуры.

# include < stdio.h>

struct person

{

char name [25]; /* фамилия */

int year; /* год рождения*/

};

struct person p = {“Иванов”, 1980};/*инициализация элементов структуры p*/

void main ()

{

printf (“\n Фамилия: % s”, p. name);

printf (“\n Год рождения: %d”, p. year);

printf (“\n Введите фамилию: “);

scanf (“%s”, p.name);

printf (“\n Введите год рождения: “);

scanf (“%d”, & p.year);

printf (“\n\n Фамилия: %s”, p.name);

printf (“\n Год рождения: %d\n”, p.year);

}

 

5. Массивы структур

 

Пусть, например, ведомость, содержащая сведения о ста служащих, состоит из следующих граф: фамилия, должность, год рождения. Эту ведомость можно описать как массив структур:

struct person

{

char name [25]; /* фамилия */

сhar post [25]; /* должность */

int year; /* год рождения */

};

struct person Vedomost [100]; /* Vedomost – массив структур */

В этом примере определяется массив Vedomost, элементы которого являются структурами. Массив состоит из 100 элементов. Каждый элемент массива – это структура, состоящая из трех компонентов с именами name, post, year.

Пример:

Vedomost [0]. year = 1950; /* присвоить значение 1950 */

/* компоненту year структуры, */

/* которая имеет индекс 0 */

 

6. Вложенные структуры

 

Допускается использование структуры в качестве элемента другой структуры.

Пример.

С помощью структуры можно описать учетную карточку служащего:

struct employee

{

char name [25]; /*фамилия */

struct DATE birthdate; /* дата рождения */

};

Структура employee содержит в себе структуру типа DATE (структурный тип DATE был описан выше).

Определим структурную переменную e 1:

struct employee e 1;

Тогда e 1. birthdate. month будет ссылаться на месяц рождения служащего.

 

7. Указатели на структуры

 

Допускается использование указателя на структуру.

Например, конструкция

struct DATE *pd, date 5;

определяет указатель pd на структуру типа DATE и структурную переменную date 5. Для использования указателя pd в программе, ему необходимо сначала присвоить значение, например

pd = & date 5; /* присвоить указателю pd адрес структурной переменной date 5 */

8. Обращение к элементам структур через указатели

 

Если p – указатель на структуру, то с помощью записи вида

p – > элемент

можно обратиться к конкретному элементу структуры.

Пример:

pd ® year

Доступ к элементу структуры через указатель можно осуществить и другим способом:

(* p). элемент

где p – указатель на структуру. Таким образом, конструкции

pd ® year

и

(* pd). year

эквиваленты.

Примеры обращений к элементам структуры через указатель:

pd ® month

(* pd). day

9. Использование структур в функциях

 

Если аргументом функции является структура, то можно передавать параметры одним из трех способов:

– передавать элементы структуры по отдельности;

– передавать всю структуру целиком;

– передавать указатель на структуру.

Функция в качестве значения может возвращать структуру. Рассмотрим пример, демонстрирующий использование указателей на структуры в функциях.

Пусть, например, нужно выполнять сложение и вычитание комплексных чисел. Для представления комплексного числа будем использовать структуру, а для сложения и вычитания комплексных чисел – функции add и sub. Аргументами этих функций являются указатели c 1, c 2, c 3 на структуры (c 1, c 2 – это указатели на структуры, которые служат исходными данными для операций сложения и вычитания, c 3 – это указатель на структуру, которая является результатом выполнения этих операций).

#include <stdio.h>

typedef struct

{ float real;

float imag;

} COMPLEX;

void assign_real(COMPLEX *c,float r) /* Присвоить значение r */

{ /* действительной части */

c->real=r; /* комплексного числа */

}

void assign_imag(COMPLEX *c,float i) /* Присвоить значение i */

{ /* мнимой части */

c->imag=i; /* комплексного числа */

}

void add(COMPLEX *c1,COMPLEX *c2,COMPLEX *c3)

{

c3->real=c1->real+c2->real;

c3->imag=c1->imag+c2->imag;

}

void sub(COMPLEX *c1,COMPLEX *c2,COMPLEX *c3)

{

c3->real=c1->real-c2->real;

c3->imag=c1->imag-c2->imag;

}

void print_complex(COMPLEX *c)

{

printf("\n Действительная часть = % f, мнимая часть = % f’’, с – > real,

c – > imag);

}

/* пример использования функций для работы с комплексными числами */

void main()

{

COMPLEX a1,a2,a3; /* три комплексных числа */

assign_real(&a1,5); /* пусть дейст. часть 1-го комплексного числа равна 5 */

assign_imag(&a1,7); /* пусть мнимая часть 1-го комплексного числа равна 7*/

assign_real(&a2,3); /* пусть действ. часть 2-го комплексного числа равна 3 */

 

assign_imag(&a2,4); /* пусть мнимая часть 2-го комплексного числа равна 4*/

printf("\n Первое комплексное число:”);

print_complex(&a1);

printf("\n Второе комплексное число:");

print_complex(&a2);

add(&a1,&a2,&a3); /* Сложить комплексные числа a1 и а2*/

printf("\n Результат сложения двух комплексных чисел:");

print_complex(&a3);

sub(&a1,&a2,&a3); /* а1 – а2 */

printf("\n Результат вычитания комплексных чисел:");

print_complex(&a3);

}

 

 

10. Объединения

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

Пример.

union

{

int x;

float y;

double Z;

} A, B; /* определение двух переменных типа объединение */

Пример.

union number

{

int x;

float y;

double Z;

};

union number F; /* определение переменной F типа объединение */

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

Обращение к элементу объединения осуществляется так:

<имя объединения>. <элемент>

Пример.

F. x = 5; /* присвоить элементу x значение 5 */

F.y = 3.2; /* присвоить элементу y значение 3.2 */

 

Контрольные вопросы

 

1. Что такое структура? В чем состоит назначение структуры?

2. Чем отличается структура от массива?

3. Каким образом описывается структурная переменная?

4. Как осуществляется обращение к элементу структуры?

5. Каким образом можно инициализировать структуру?

6. Что такое вложенная структура? Приведите пример.

7. Как присвоить значение указателю на структуру?

8. Каким образом осуществляется обращение к элементу структуры через указатель? Приведите пример.

9. Чем отличается объединение от структуры?

10. Как описывается объединение?

Варианты заданий

 

В каждом задании ввести и вывести элементы структур.

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

2. Описать массив структур и поместить в него сведения (автор, название, издательство, год издания, тираж, число страниц) о четырех книгах.

3. Массив структур содержит информацию о студентах: фамилия, номер группы, средний балл в сессию (каждый элемент массива содержит информацию об одном студенте). Заполнить массив данными для пяти студентов.

4. Описать массив структур, содержащий сведения о трех журнальных статьях: автор, название статьи, название журнала, год издания, номер.

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

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

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

8. Описать массив структур и поместить в него сведения (номер аудитории, вместимость, площадь) о пяти аудиториях.

9. Организовать массив структур и поместить в него информацию (название кинотеатра, вместимость, число залов) о пяти кинотеатрах.

10, 11, 12. Определить структуру, содержащую сведения о товарах на складе (шифр товара, наименование товара, количество единиц, стоимость единицы). Описать массив структур и поместить в него сведения о пяти канцелярских товарах (задание №10), пяти продовольственных товарах (задание №11), пяти промышленных товарах (задание №12).

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

14. Сводка о выполнении плана содержит сведения: наименование изделия, шифр, единица измерения, план выпуска, фактически выпущено, отклонение от плана (перевыполнение, недовыполнение). Описать массив структур и заполнить его данными для пяти позиций сводки.

15. Описать и заполнить массив структур сведениями о выполнении плана выпуска продукции по следующей форме (для трех изделий):

  № п/п   Наименование   Единица измерения     Шифр   План выпуска
          Всего По кварталам
II III IIII IIV

 

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

17. Таблица содержит результаты спортивных соревнований: Ф.И.О., время на 100 м, время на 1 км, прыжок в высоту, прыжок в длину. Описать массив структур и заполнить его данными для шести спортсменов.

18. Описать массив структур, содержащий сведения о библиотечных книгах: автор; название книги; год издания; шифр книги; количество экземпляров, имеющихся в библиотеке.

Заполнить массив данными о трех книгах.

19. Описать массив структур, содержащий сведения об учебных дисциплинах: название дисциплины, преподаватель, номер группы. Заполнить массив информацией о пяти дисциплинах.

20. Описать массив структур, содержащий сведения о расписании экзаменов: дисциплина; дата консультации; время консультации; аудитория, в которой проводится консультация; дата экзамена; время экзамена; аудитория, в которой проводится экзамен. Заполнить массив информацией об экзаменах прошедшей сессии в Вашей группе.

21. Описать массив структур, содержащий сведения о библиотечных книгах, читаемых в данный момент: название книги, читатель, дата выдачи, срок возврата. Заполнить массив данными для четырех книг.

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

23. Таблица содержит сведения о расписании и состоит из следующих граф: номер группы, дисциплина, преподаватель, аудитория, неделя (числитель, знаменатель), день недели, время. Описать массив структур и заполнить его данными для трех строк таблицы.

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

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


 

Лабораторная работа № 15

 

 

ФАЙЛЫ

Цель работы

Изучение средств создания и обработки файлов последовательного и прямого доступа.

 

Методические указания

 

 

1. Понятие файла

 

Файл – это упорядоченная совокупность произвольного числа компонент, расположенная на внешнем запоминающем устройстве и имеющая единое имя, называемое физическим именем файла. В программе на языке Си файлу соответствует внутреннее логическое имя файла <поток>. Для пользователя все файлы в языке Си рассматриваются как последовательности, потоки байтов.

Для файла определен маркер (указатель чтения/записи). Он указывает текущую позицию файла, к которой осуществляется доступ.

С началом работы любой программы автоматически открываются некоторые стандартные потоки, например, стандартный ввод (stdin) и стандартный вывод (stdout). По умолчанию они связаны с клавиатурой и экраном терминала соответственно.

 

 

2. Объявление файла

 

Внутреннее логическое имя файла <поток> должно быть объявлено в программе с помощью оператора FILE*<поток>;

Тип FILE – это структура, определенная в stdio.h с помощью средства typedef и содержащая некоторую информацию о файле: например, флаги состояния файла, размер буфера, указатель на буфер и др.

Например, после объявления

FILE * fp;

fp будет являться указателем на структуру типа FILE. С файлами можно производить такие действия, как создание и открытие файла, чтение и запись, закрытие файла. Чтобы в программе использовать функции для работы с файлом, необходимо директивой # include включить в программу файл stdio.h.

3. Открытие файла

 

 

Перед выполнением операций ввода–вывода данных файла необходимо его открыть с помощью функции fopen:

<поток> = fopen (“<имя файла>”, “<тип>”);

Эта функция связывает внутреннее логическое имя файла <поток>, объявленное в программе как указатель на структуру типа FILE, с физическим именем файла, указанным параметром <имя файла>. При успешном открытии файла функция fopen возвращает указатель на структуру типа FILE. Этот указатель используется для последующих операций с файлом.

Параметр <тип> определяет, как должен использоваться файл:

r ” – файл открывается для чтения (файл должен существовать);

w ” – файл открывается для записи;

a ” – файл открывается для записи в конец файла (добавления).

Например, с помощью оператора

fp = fopen (“ data. txt ”, “ r ”);

открывается для чтения файл data. txt и связывается с указателем fp.

Можно задавать не только имя файла, но и путь к файлу.

Если для записи (“ w ”) или добавления (“ a ”) открывается несуществующий файл, то он создается.

Внимание: если для записи (“ w ”) открывается существующий файл, то его содержимое теряется.

Если при открытии файла произошла ошибка, то функция fopen возвращает значение NULL.

Пример:

# include <stdio.h>

void main ()

{

FILE *p;

if ((p = fopen (“data2”, “r”))! = NULL) / *проверка – успешно ли */

/*открыт файл */

{ …

/* работа с файлом */

}

else

printf (“\n Ошибка открытия файла data2”);

}

 

 

4. Закрытие файла

 

После окончания работы с файлом он обязательно должен быть закрыт с помощью функции

fclose (<поток>).

Пример:

FILE *p;

fclose (p); /*закрыть файл */

Функция fclose возвращает значение 0, если файл закрыт успешно, и значение EOF – в противном случае.

Константа EOF, определенная в файле stdio. h, обозначает признак конца файла. Пример использования константы EOF дан в п. 5.1.

 

 

5. Ввод–вывод данных файла

 

Функции, используемые для ввода с клавиатуры и вывода на экран, имеют аналоги для ввода-вывода данных файла. Особенностью функций ввода–вывода данных файла является то, что в них необходимо использовать указатель типа FILE, определяющий с каким файлом им следует работать. Рассмотрим функции, предназначенные для обмена данными различных типов с файлами.

 

 

5.1. Ввод–вывод символа

 

 

Обмен символьной информацией с файлом может быть осуществлен с помощью функций getc и putc.

Для вывода символа из файла служит функция getc. Функция getc возвращает значение типа int. Оператор вывода символа из файла в общем виде записывается так:

<переменная> = getc (<поток>).

Так, например, оператор

ch = getc (in);

обеспечивает вывод символа из файла, на который ссылается указатель in типа FILE, и при этом символ запоминается в переменной ch.

Если обнаруживается ошибка или достигается конец файла, то функция qetc возвращает значение EOF.

Функция

putc (<символ>, <поток>);

обеспечивает запись символа в файл. Например, оператор putc (‘ A ’, out); обеспечивает запись символа ‘ A ’ в файл, на который ссылается указатель out типа FILE.

Ниже приведена программа, в кото



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2017-04-20 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: