Функции

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

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

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

Здесь тип_функции – тип возвращаемого функцией значения, в том числе void, если функция не возвращает никакого значения. Тип функции может быть любым кроме массива  и функции. Имя_функции – идентификатор.

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

тип имя_параметра

или

тип имя_параметра= умалчиваемое значение.

Тело_функции - это блок или составной оператор, заключенный в скобки {}. Очень важным оператором тела функции является оператор возврата в точку вызова

return выражение;

или

return;.

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

Обращение к функции (вызов функции ) – это выражение вида

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

При обращении к функции формальные параметры заменяются фактическими, причем соблюдается строгое соответствие параметров по типам. Именно поэтому необходимо определить или хотя бы объявить функцию до ее вызова. Объявление функции (прототип) совпадает с заголовком определения функции после которого ставится ;. В списке формальных параметров в этом случае могут отсутствовать имена параметров.

Приведем несколько примеров.

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

# include <iostream.h>

int max (int n, int m )      // определение функции нахождения максимума

{return n<m?m:n;}

intcube(int);                   // прототип функции вычисления куба целого числа

void main (void)

{

int i,j,m;

cin >>i>>j;

m=cube(max(i,j));          // вложенные вызовы функций – m – куб

                                     // максимального из двух чисел

cout<<“\nmax=”<<m);

}

int cube(int x)                // Определение функции вычисления

                                     // куба целого числа

{return x*x*x;}

Пример 2.Определить функцию, подсчитывающую количество нулей в троичной записи натурального числа. Найти все пары натуральных чисел в диапазоне [n1,n2], разность между которыми равна 4 и в троичной записи которых равное число нулей.  Например, такой парой является пара 6(203) и 10(1013) (в троичной записи по одному нулю).

# include <iostream.h>

int oct (int a)                  // определениефункции

{int sum=0;

while (a>0)

{

    if (a%3==0) sum++;

    a/=3;

}

return sum;

}

void main()

{

int n1,n2;

cout <<"Enter n1,n2 ";

cin>>n1>>n2;

for (int i=n1;i<=n2-4;i++)                  // Проверяем все пары чисел,

                                                        //разность между которыми равна 4

    if(oct(i)==oct(i+4) && oct(i)>0)   // условие, содержащие

                                                        // три вызова функции oct

       cout <<i<<" "<<i+4<<"\n";

}

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

Пример 3. Напишите рекурсивную функцию, вычисляющую xn  (n-целое, неотрицательное).

# include <iostream.h>

float step(float x, int n)

{  float k;

if (n==0) return 1;

k=x*step(x,n-1);                               //рекурсивный вызов

return k;

}

void main()

{

float x;

int n;

cout<<"Enter x,n  ";

cin>>x>>n;

cout <<"\nStepen("<<x<<","<<n<<")= "<<step(x,n);

}

Для n=0 функция возвращает значение 1. В противном случае вызывается та же функция с уменьшенным на 1 значением параметра степени. Таким образом, организуется последовательность вычислений xn=x*xn-1, xn-1=x*xn-2…, x2=x*x1, x1=x*x0, x0=1. Обратите внимание, что последовательность рекурсивных обращений к функции прерывается только при вызове функции step(x,0). Таким образом, важным моментом при составлении любой рекурсивной функции является организация выхода их рекурсии. Каждая задача, решаемая рекурсивным образом, при некоторых наборах данных должна иметь элементарное нерекурсивное решение, например, в нашем примере x0=1.

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

Функции для работы со строками описаны в заголовочном файле string.h. Как было отмечено строка в языке С задается как массив символов и строковые функции работают именно с символьными массивами, завершающимися символом ‘\0’, причем вся ответственность за переполнение массивов ложится на плечи программиста.  Так как имя массива является указателем-константой на его первый элемент, то параметрами строковых функций чаще всего являются именно указатели-константы на объект типа char(constchar*). Рассмотрим описание некоторых функций библиотеки string.h

1.

# include<string.h>

unsigned int  strlen(char * str)

Функция  strlen() возращает длину строки str. Завершающий нулевой символ не учитывается.

Пример использования функции:

char s[255]; cin.getline(s,255);

cout<< “Длина строки равна ”<<strlen(s);

2.

#include<string.h>

int strcmp(const char *str1, const char* str2);

Функция strcmp() сравнивает в лексикографическом порядке две строки и возвращает целое значение, зависящее от результата сравнения следующим образом: значение меньше нуля, если str1<str2; ноль, если str1=str2; больше нуля, если str1>str2. Приведем пример использования этой функции – фрагмент программы, проверяющий упорядочены ли два слова по алфавиту:

chars1[20], s2[20];

cin>>s1>>s2;

int k=strcmp(s1,s2);

if(k<0) cout<< “Слова упорядочены по алфавиту”;

elseif(k==0) cout<< “Слова одинаковы”;

elsecout<< “Слова не упорядочены по алфавиту”;

3

#include <string.h>

char * strcpy (char *str1, const char* str2);

Функция strcpy() копирует содержимое строки str2 в строку str1 и возвращает значение указателя str1. Если заданные символьные массивы перекрываются, поведение функции не определено. Приведем пример использования этой функции – ввести в клавиатуры слово и скопировать его в новую строку.

char str1[20],str2[20];

cin>>str1;

strcpy(str2,str1);

cout<<str1<<"   "<<str2;

Функции для работы с файлами описаны в заголовочном файле stdio.h. ([8] стр. 131). В языке не предусмотрены никакие предопределенные структуры фалов: все файлы рассматриваются как последовательности, потоки байтов.  Для файла определен маркер (указатель чтения/записи), который определят текущую позицию, к которой осуществляется доступ.  В программе возможно открывать потоки ввода-вывода и связывать их либо с файлами на диске либо с физическими устройствами (например, принтером), записывать в них или считывать из них информацию. Доступ к потоку осуществляется с помощью типа FILE, определенного в файле stdio.hследующим образом:

FILE* идентификатор;

Описанный указатель можно связывать с конкретным файлом в момент открытия данного файл. Это осуществляется с помощью функции

FILE* fopen(constchar*fname, constchar* mode);

Функция fopen() открывает файл, имя которого задает параметр fnameи возвращает поток, связанный с этим файлом. Строка fnameдолжна представлять собой имя файла, которое разрешено определенными  в данной операционной системе правилами. Если указанный файл не удается открыть, функция возвращает нулевой указатель. Типы операций, которые разрешено выполнять с файлом, определяются параметром mode. Существует таблица значений параметра mode. Наиболее часто используемые значения:

  • “r” – открывает текстовый файл для чтения;
  • “w” – создает текстовый файл для записи;
  • “a” – открывает текстовый файл для записи в конец файла;
  • “r+” – открывает текстовый фал для чтения и записи;
  • “w+” – создает текстовый файл для чтения и записи;
  • “a+” – открывает текстовый файл для чтения и записи в конец файла.

Приведем фрагмент программы, иллюстрирующий корректный способ открытия файла.

FILE *fp=fopen("1.txt","r");

     if(fp==NULL)  {cout<<"Не удается открыть  файл "; exit(1);}

     else {….}

В данном примере происходит попытка открыть файл с именем “1.txt” в текущем каталоге для чтения. Если такого файла не существует, на экран выдается соответствующее сообщение и с помощью функции exit(), описанной в заголовочном файле stdlib.h, происходит завершение программы.  При открытии  файла для записи с параметром “w” также рекомендуется делать проверку, так как диск может быть защищен от записи или заполнен.

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

int fclose (FILE * stream);

После обращения к функции fclose() указатель streamбольше не связан с конкретным файлом. При успешном выполнении функции возвращается ноль, в противном случае возвращается значение EOF. Попытка закрыть уже закрытый файл расценивается как ошибка.

Опишем назначений основных функций ввода и ввода данных.

Функция intfgetc(FILE* stream);  считывает из входного потока streаmследующий символ, соответствующий текущей позиции, при достижении конца файла возвращает значение EOF.

Функция char* fgets(char*str, intnum, FILE* stream);  считывает из входного потока streamне более num-1 и помещает их в массив, адресуемый указателем str. Символы читаются пока не будет прочитан символ новой строки или конец файла либо пока не будет достигнут заданный предел. По завершении чтения символов сразу за последним прочитанным символом размещается нулевой символ. Символ новой строки сохраняется и остается частью строки.  При успешном выполнении функции возвращается значение str, при неуспешном – нулевой указатель.

Функцияint fscanf (FILE * stream, const char * format, …);   читаетинформациюизпотокаstream.  Управляющая строка, задаваемая параметром format  состоит из символов трех категорий: спецификаторы формата, пробельные символы и символы, отличные от пробельных. Спецификаторы формата – им предшествует знак процента – сообщают, какого типа данные будут прочитаны. Например спецификатор %dпрочитает целое значение, а спецификатор %с прочитает символ. Пробельные символы заставляют функцию пропустить один или несколько пробельных символов во входном потоке. Не пробельный символ заставляет функцию прочитать и отбросить соответствующий символ из входного потока. Символ *,  стоящий после знака % и перед кодом формата прочитает данные заданного типа, но запретит их присваивание. В качестве неопределенных параметров функции могут использовать параметры зависимости от управляющей строки. Например, функция fcsanf(fp, “%d%d”, &a, &b) прочитает очередные два целых числа из файлового потока fpв переменные a, b, а функция fcsanf(fp, “%d%*d”, &a) считает два целый числа, но в переменной а сохранит только первое из них. Функция возвращает количество аргументов, которым действительно присвоены значения.

Функция intfputc(intch, FILE* stream);  записывает символ chв заданный поток streamв текущую позицию файла, а затем передвигает индикатор позиции файла. Возвращает значение записанного символа, а в случае ошибки значение EOF.

Функция intfputs(constchar*str, FILE* stream);  записывает в заданный поток stream  содержимое строки, адресуемой указателем str. При этом завершающий нулевой символ не записывается. При успешном выполнении возвращается неотрицательное значение, при неудачном – значениеEOF.

Функция intfprintf(FILE* stream, constchar*format, …);  - записывает в файловый поток streamзначения параметров из заданного списка параметров в соответствии со строкой форматирования format. Например, функция fprintf(fp, “%d”, a) запишет значение целой переменной aв файловый поток fp. Функция возвращает количество реально выведенных символов, а при возникновении ошибки- отрицательное значение.

Для проверки, достигнут ли конец файла используют функцию

intfeof(FILE*stream);

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

Для изменения индикатора позиции файла используют функцию

int fseek ( FILE*  stream,long offset,  int origin);

Функция устанавливает индикатор позиции файла, связанного с потоком stream, в соответствии со значением смещения offset(количество байтов) и  исходного положения origin.  Параметр originможет принимать одно их следующих значений: 0 -  начало файла, 1 – текущая позиция, 2 – конец файла.  При успешном выполнении функция возвращает нулевое значение, при возникновении сбоя – ненулевое. Функция очищает признак конца файла. Вообще говоря функцию fseek() следует использовать только при работе с двоичными файлами. При использовании же с текстовыми файлами параметр originдолжен иметь значение 0, а параметр offset– значение, полученное в результате вызова функции

longftell(FILE* stream);

которая возвращает текущее значение индикатора позиции файла.

Приведем фрагмент программы, считывающей  из файлового потока fp  каждый третий  символ

char a;

while ((a=fgetc(fp))!=EOF && fseek(fp,2,1)==0)

cout<<a<<" ";

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

int  a;

 while (fscanf(fp, "%d%*d%*d ", &a)!=EOF && fseek(fp,ftell(fp),0)==0)

 cout<<a<<" ";

Добавить комментарий


Защитный код
Обновить

Мобильные устройства

Технологические системы

Программирование

Реклама

Яндекс.Метрика
© 2011-2016 pc-4you.ru Копирование материалов разрешено только с указанием активной ссылки на первоисточник