Партнерка на США и Канаду по недвижимости, выплаты в крипто

  • 30% recurring commission
  • Выплаты в USDT
  • Вывод каждую неделю
  • Комиссия до 5 лет за каждого referral

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

Элемент структуры

Оформление в языке Си

Заголовок функции

тип_функции Имя (список_формальных_параметров)

Тело функции

{

последовательность

операторов

};

Завершение

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

Пример: Функция вычисления знака числа. Возвращает:

1, если число положительное,

-1, если число отрицательное,

0, если число равно нулю.

int sign(long double x) {

if (x>0) return 1;

if (x<0) return –1;

return 0;

}

При таком способе третье условие (х==0) не проверяется, так как при (х!=0) выход из функции произойдет раньше.

Можно записать эту функцию с одним оператором return и локальной переменной m:

int sign(long double x) {

int m = 0;

if (x>0) m = 1;

if (x<0) m = –1;

return m;

}

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

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

НЕ нашли? Не то? Что вы ищете?

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

Глобальная переменная может быть изменена в любом месте программы (в любой функции).

Вызов функции sign может осуществляться везде, где применимо выражение целочисленного типа. Например:

Int A=sign(x*x-5); // присвоить знак выражения переменной А

K=sign(x)*x; // присвоить переменной К значение модуля х

Printf(”Знак числа = %d\n”, sign(t+1)); // вывести знак выражения (t+1)

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

Передача параметров по значению

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

Передача параметров по значению осуществляется так:

тип_функции Имя (..., тип параметр, ... ) {

тело функции;

}

Передача параметров по ссылке

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

Фактическим выходным параметром может являться только имя переменной, а входным – имя переменной, константа или выражение.

Передача параметров по ссылке может осуществляться двумя способами:

1) Через указатели:

тип_функции Имя (..., тип* параметр, ... ) {

тело функции;

}

2) Через псевдонимы (только в С++):

тип_функции Имя (..., тип& параметр, ... ) {

тело функции;

}

Рассмотрим это на примере функции, производящей обмен двух целых чисел

Способ 1:

void swp1(int* A, int* B) {

int P=*A; // вспомогательная переменная для обмена

*A = *B;

*B = P;

}

Здесь нужно производить операцию «разыменования» (знак «*»), так как А и В являются адресами.

Способ 2:

void swp2(int& A, int& B) {

int P = A; // вспомогательная переменная для обмена

A = B;

B = P;

}

Здесь нужно производить операцию «разыменования» производить не нужно, так как А и В являются псевдонимами формальных параметров.

Вызов функций swp1 и swp2 также отличается:

swp1(&x, &y); // обмен содержимым переменных х и у

swp2(x, y); // обмен содержимым переменных х и у

Рассмотрим реализацию функции определения длины строки через индексы

unsigned int len(const char* str) {

unsigned int k;

for (k=0; str[k]; k++); // цикл завершается при str[k]==’\0’;

return k;

}

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

Передача массивов в функции

При передаче массива в функцию всегда передается указатель на его первый элемент, то есть, массив всегда передается по ссылке. При этом информация о количестве элементов массива теряется. Для строк (символьных массивов) фактическую длину можно определить по нуль-символу, а в случае массивов других типов их размер нужно передавать в качестве отдельного параметра (для многомерных массивов несколько параметров). Имя одномерного массива в списке формальных параметров указывают с пустыми квадратными скобками (int x[]) или как указатель (int* x). Внутри функции с массивом можно работать через индексы или указатели. В случае многомерного массива внутри функции он интерпретируется как одномерный, а в заголовке объявляется как указатель.

Пример 1: Функция заполнения и вывода массива

#include <stdio. h>

#include <stdlib. h>

#include <conio. h>

// Заполнение массива случайными числами

void masrnd(int x[], int n, int v=0, int a=-100, int b=100) {

// v, a,b – необязательные, так как указаны их значения

// v - вывод массива

for (int i=0; i<n; i++) {

x[i]=random(b-a+1)+a;

if (v) printf("%5d",x[i]);

}

}

main(){

clrscr();

const int n=10;

int a[n],b[n+5],i;

printf("Массив A:\n");

masrnd(a, n,1);

puts("");

printf("Массив B:\n");

masrnd(b, n+5,0,500,550);

for (i=0; i<n+5; i++) printf("%5d",b[i]);

puts("");

// masrnd(a, n,,0,20); - НЕЛЬЗЯ пропускать

// masrnd(a, n); - МОЖНО, ==> masrnd(a, n,0,-100,100);

// masrnd(a); - НЕЛЬЗЯ, мало параметров

getch();

}

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

-  Параметры по умолчанию должны быть последними в списке формальных параметров.

-  При вызове можно не указывать несколько последних параметров, но нельзя пропускать параметры.

Пример 2: Передача матрицы в функцию

#include <stdio. h>

#include <stdlib. h>

#include <conio. h>

// Функция подсчета числа отрицательных элементов матрицы

int neg(int *x, int n, int m){

int i, j,k=0;

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

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

if (*(x+i*m+j)<0) k++;

return k;

}

main(){

clrscr();

randomize();

const int n=10, m=5;

int i, j;

int *a=new int [n*m];

// или int *a=(int*)malloc(n*m*2);

for (i=0; i<n; i++){

for (j=0; j<m; j++){

printf("%5d",a[i*m+j]=random(100)-50);

}

printf("\n");

}

printf("Число отрицательных элементов = %d\n",neg(a, n,m));

delete a[];

getch();

}

Перегрузка и шаблоны функций

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

Механизм перегрузки заключается в следующем:

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

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

Пример: Функция сложения 2 чисел

#include <stdio. h>

#include <conio. h>

#include <stdlib. h>

// Функция для вещественных чисел

double sum(double x, double y){

return x+y; }

// Функция для целых чисел

int sum(int x, int y){

return x+y; }

main(){

clrscr();

double x=4.7, y=12.9;

int a=5, b=8;

printf("%d %0.3lf",sum(a, b),sum(x, y));

getch();

}

Другой способ – не писать похожие функции для разных типов аргументов, а создать шаблон функции. Формат простейшей функции-шаблона:

Template <class Type> заголовок {

Тело функции

}

Вместо слова Type может использоваться произвольное имя.

Пример: Программа с шаблоном для функции сортировки массива

#include <iostream. h>

#include <iomanip. h>

#include <stdlib. h>

#include <conio. h>

// шаблон T – формальный базовый тип элементов массива

template <class T>

void srt(T x[], const int n){

T a;

for (int i=0; i<n-1; i++){

int imin=i;

for (int j=i+1; j<n; j++)

if (x[j]<x[imin]) imin=j;

a=x[i]; x[i]=x[imin]; x[imin]=a;

}

}

void main(){

clrscr();

const int n=10;

int i, b[n];

double r[n];

for (i=0; i<n; i++){

b[i]=random(50);

r[i]=random(10)+1.0*random(10)/10;

cout<<setw(5)<<b[i];

}

cout<<"\n";

srt(b, n); // сортировка целочисленного массива

for (i=0; i<n; i++) cout<<setw(5)<<b[i];

cout<<"\n\n";

for (i=0; i<n; i++){ cout<<r[i]<<" "; }

cout<<"\n";

srt(r, n); // сортировка вещественного массива

for (i=0; i<n; i++){ cout<<r[i]<<" "; }

cout<<"\n";

getch();

}

Включаемые файлы

Включаемые файлы – это файлы, содержащие объявления типов данных, констант и определения функций, за исключением функции main. Их можно называть модулями. Если такой файл содержит только описания переменных, констант, типов данных и заголовки функций, его называют заголовочным файлом. Заголовочные файлы в языке Си имеют расширение «.h». Реализация функций часто размещается в одноименных файлах с расширением «.с» или «.срр». В принципе, программист может создавать свои модули и сохранять их в файлах с любым расширением.

Имя включаемого файла записывается либо в угловых скобках, либо в двойных кавычках. В настройках среды Turbo C++ (команда Options / Directories) есть поле Include Directories, в котором через символ «;» указывают список каталогов для поиска включаемых файлов. При указании имени включаемого файла в угловых скобках он ищется последовательно в списке этих каталогов. При указании имени включаемого файла в кавычках он ищется сначала в активной директории, а затем - в том же списке каталогов. Если файл не найден, выдается сообщение об ошибке. В угловых скобках обычно указывают стандартные модули, а в кавычках – файлы пользователей.

Примеры:

#include <stdio. h>

#include ”MyModule. cpp”

Для упрощения можно размещать в файлах с расширением «.h» не только заголовки (прототипы), но и тела функций. Таким образом можно создать свою библиотеку и использовать ее в разных программах.

Задания для подготовки к работе

Изучите структуру функций, структуру программы с функциями.

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

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

Изучите задания к работе и разработайте алгоритмы и программы их решения.

Задания к работе

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

2.  Разработать программу с использованием функций типа void. Входные данные должны передаваться через параметры функции. Варианты заданий приведены в приложении 2.

3.  Измените любую из программ таким образом, чтобы использовалась перегрузка функций.

4.  Создайте программу с шаблоном функции на основе любой из предыдущих программ.

5.  Разместите ваши типы данных и функции из заданий 1 и 2 в отдельном заголовочном файле. Измените программы таким образом, чтобы они вызывали функции из этого файла.

Варианты к заданию 1

Вариант задания

Условия задачи

Примечания

1

Вычислить большие корни квадратных уравнений x2-ax+b=0 cy2-dx-f=0

Все корни действительные

2

Подсчитать число точек, находящихся внутри круга радиусом r с центром вначале координат; координаты заданы массивами X(100); Y(100)

Расстояние точки от начала координат вычислять в подпрограмме

3

Определить периметры треугольников, заданных координатами их вершин XA(5),XB(5),XC(5),YA(5),YB(J), YC(5)

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

4

Подсчитать число точек, находящихся внутри круга радиусом r с центром в точке с координатами (1,1); координаты заданы массивами X(80); Y(80)

Расстояние точки от центра круга определять в подпрограмме

5

Вычислить z=u1+u2+u3/3, где u1,u2,u3 - объемы шаров с радиусами r1,r2,r3 соответственно

u1 вычислять в подпрограмме

6

Вычислить суммы положительных элементов массивов X(N),Y(M),Z(K)

N<60,M<60, K<70

7

Вычислить среднее арифметическое положительных элементов для массивов A(N1),B(N2),C(N3)

N1<100,N2<100, N3<100

8

Подсчитать количество элементов матриц X(10,15) и Y(20,12), удовлетворяющих условиям 0<XIJ<1 и 0<YIJ<1

9

Вычислить суммы положительных элементов каждой строки для матриц А(10,12),В(15,10)

10

Вычислить Z=xm1+xm2/2, где xm1 и xm2 - наименьшие элементы массивов X1(70), X2(80)

11

Вычислить суммы элементов главных диагоналей матриц А(N, N), B(M, M)

M<20, N<30

12

Вычислить z=s+s/2, где s - сумма положительных элементов массива Х(50); s - сумма отрицательных элементов массива Y(60)

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

13

Подсчитать число нулевых элементов для матриц A(N, M) и B(M, N)

M<20, N<20

14

Вычислить суммы элементов нижних треугольных матриц А(15,15), B(20,20)

15

Определить число положительных элементов до первого отрицательного в массивах X(40),Y(50),Z(N)

N<50

Варианты к заданию 2

1.  Вычислить , где S1 и S2 – суммы положительных элементов 1-го и 2-го массивов, k1 и k2 – количества этих элементов соответственно.

2.  Вычислить и записать в 2 массива суммы положительных элементов каждой строки матриц A(10x15) и B(14x8). Вывести матрицы и массивы на экран.

3.  Вычислить , где x1 и x2 – корни уравнения 2x2 + x – 4 =0, y1 и y2 – корни уравнения ay2 + 2y – 1 =0.

4.  Найти наибольшие элементы и их порядковые номера для 2 массивов разного размера и поменять их местами. Вывести на экран массивы до и после обмена.

5.  Переписать положительные элементы 3 массивов разной длины в 4-й массив подряд. Вывести все 4 массива на экран.

6.  Напишите функцию, которая будет выводить матрицу на экран, выделяя локальные минимумы в этих матрицах красным цветом.

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

8.  Найти средние значения и стандартные отклонения для 3 массивов.

9.  Преобразовать несколько массивов, расположив в них подряд только положительные элементы. Вместо остальных элементов записать нули. Вывести массивы до и после преобразования на экран.

10.  Поменять местами элементы 2 главных диагоналей квадратных матриц.

11.  Вычислить с помощью функции количество положительных, отрицательных и нулевых элементов разных матриц.

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

13.  Написать функцию, которая сортирует строки матрицы по возрастанию, используя в качестве критерия сортировки числа в 1-м столбце, если они совпадают – во 2-м, в 3-м и т. д.

14.  Написать функцию, которая в квадратной матрице сдвигает крайние элементы по кольцу, то есть, 1-я строка замещает последний столбец, последний столбец – последнюю строку, последняя строка – 1-й столбец, а 1-й столбец – 1-ю строку.

Написать функцию построения на экране текстового окна по координатам верхнего левого угла, ширине и высоте поля редактирования, с заголовком, цветом фона и символов, типом рамки (одиночная / двойная). Поле редактирования должно создаваться функцией window из модуля conio. h. Должна производиться проверка возможности построения окна в пределах экрана. В программе, используя функцию нужно вывести на экран несколько перекрывающих друг друга окон с текстом.

Содержание отчета

Отчет должен содержать:

Тексты заданий (по вариантам);

Тексты программ с комментариями;

Протоколы работы программ;

Выводы по работе.

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

1.  При каких условиях целесообразно использование подпрограмм, какие выгоды они предоставляют пользователю?

2.  Как в языке Turbo C++ объявляются функции?

3.  Что такое прототип функции?

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

5.  Объясните различие между формальными и фактическими параметрами.

6.  Указать конструкции, которые могут быть формальными и фактическими параметрами.

7.  Как передать подпрограмме в качестве параметра одномерный массив? Многомерный массив? Строку?

8.  Чем отличаются функции типа void?

9.  Какие существуют способы обращения к подпрограммам?

10.  Указать способы передачи параметров в подпрограмму.

11.  Можно ли не указывать все параметры при вызове функции?

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

13.  Что такое рекурсия?

14.  Что такое «перегрузка функций»?

15.  Для чего и как создаются шаблоны функций?

16.  Чем функции отличаются от макросов?

17.  Как создать свой библиотечный модуль?

Литература

33.  . С/С++. Программирование на языке высокого уровня. – СПб.: Питер, 2002. – 464с.

34.  , . С/С++. Структурное программирование: практикум. – СПб.: Питер, 2002. – 240с.

35.  Митницкий теории алгоритмов и язык программирования С. Учебное пособие. –М.: МФТИ, 2001. – 180с.

36.  Могилев А. В. и др. Информатика. М.: Изд. центр “Академия”, 2000. – 816 с.

37.  Подбельский С++: Учебное пособие. – М.: Финансы и статистика, 2002 – 560с.

38.  , Фомин на языке Си. – М.: Финансы и статистика, 2002 – 600с.

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

Обработка файлов записей

Цели работы:

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

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

Краткие теоретические сведения

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

В языке Си существует два типа потоков: текстовый (text) и двоичный (binary).

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

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

Текстовый файл можно рассматривать и как текстовый, и как двоичный, а двоичный как текстовый – нельзя.

Двоичный файл можно рассматривать как файл из байтов (это самый простой случай), но очень часто данные в нем имеют определенную структуру. Например, запись о рабочем хранит информацию о фамилии, табельном номере, разряде, профессии и т. д. Можно объединить эти данные в одну структуру, которая в языке Си так и называется – «структура», а в большинстве других языков программирования и теории баз данных – записью.

Запись – это структура данных, которая может содержать несколько полей. У каждого поля может быть свой тип данных (числовой, строка, массив, другая запись, ...). Каждое поле занимает фиксированный размер, а в памяти они хранятся последовательно друг за другом. Группа таких записей может храниться в двоичном файле или массиве. Зная общий размер записи, можно перемещаться по файлу к нужной записи.

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

typedef struct {

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

unsigned int tab; // табельный номер

unsigned char q; // разряд

char prof[20]; // профессия

} worker;

Размер этой записи можно определить с помощью операции sizeof(worker).

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

Работа с файлом состоит из нескольких этапов:

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

-  Операции чтения-записи;

-  Закрытие файла. (при этом происходит сохранение изменений на диске).

Рассмотрим основные функции для работы с файлами.

fopen - открытие файла. Данная функция выполняет два действия:

1) Открывает поток и связывает файл на диске с этим потоком.

2) Возвращает указатель, ассоциируемый с этим файлом.

Прототип функции: FILE* fopen (char*filename, char*mode);

где

filename - это строка, содержащая имя открываемого файла;

mode - это строка, содержащая режим открываемого файла.

Возможные режимы открытия файлов:

“rb” – открыть двоичный файл только для чтения.

“wb” – создать новый двоичный файл для записи.

“ab” - открыть двоичный файл для добавления в конец файла.

“r+b” – открыть двоичный файл для чтения и записи.

“w+b” – создать новый двоичный файл для чтения и записи.

“a+b” – открыть двоичный файл для добавления или создать для чтения и записи.

Если файл открыт для записи, то существующий файл уничтожается и создается новый. При открытии файла для чтения требуется чтобы он существовал. В случае открытия для чтения и записи существующий файл не уничтожается, однако создается, если он не

существует.

Чтобы объявить указатель на файл используется оператор FILE* ИмяПеременной.

Пример:

FILE* fw; // объявление файловой переменной

fw=fopen(”work. dat”, ”w+b”); // создание нового файла для чтения и записи

fclose – закрытие файла.

Пример: fclose(fw);

fread – читает блок данных из потока.

Формат вызова функции:

fread(АдресБуфера, РазмерЗаписи, ЧислоЗаписей, ФайловаяПеременная);

Пример:

unsigned x;

worker buf;

x = fread(&buf, sizeof(buf), 5, fw);

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10