Главная страница
Навигация по странице:

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

  • Передача параметров в функцию

  • Примеры программирования. Пример 7

  • Варианты заданий. Общие требования.

  • Лабораторная работа 4 Программирование пользовательских функций. Цель работы


    Скачать 55.67 Kb.
    НазваниеЛабораторная работа 4 Программирование пользовательских функций. Цель работы
    АнкорLaboratornaya_rabota_4
    Дата18.04.2022
    Размер55.67 Kb.
    Формат файлаdocx
    Имя файлаNo4.docx
    ТипЛабораторная работа
    #481632

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


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

    1. Изучить методы создания и использования функций.

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

    Теоретические сведения.
    Функцией называется выделенная последовательность инструкций, предназначенных для решения определенной задачи. Ранее мы уже использовали библиотечные функции ввода-вывода printf() и scanf(), в данной лабораторной работе познакомимся с правилами создания своих (пользовательских) функций.

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

    Функция может многократно вызываться из различных частей программы, в

    общем случае она выполняет следующие действия:

    • получает параметры;

    • выполняет инструкции, согласно заложенному алгоритму;

    • может возвращать результат в вызывающую программу.


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

    • составной оператор;

    • определение функции.

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

    Глобальная переменная существует на протяжении всего времени выполнения программы.

    Локальная переменная существует только во время выполнения блока, в котором она определена.

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

    Переменная может быть видима в пределах:

    • блока;

    • модуля (файла);

    • во всех модулях (если программа располагается в нескольких файлах).


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

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

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



    int q=0; // глобальная переменная q

    void main()

    {int i=0; // локальная переменная функции main()

    q++;// глобальные переменные доступны во всех блоках и функциях



    {// _____________начало вложенного блок

    int k,l; // локальные переменные вложенного блока

    i++; // локальные переменные из объемлющего блока (функция main) доступны во вложенном блоке

    q++; k++; l++;

    }//_____________конец вложенного блок



    k++ // ошибка!!! переменной k уже нет

    }
    Функции, общие понятия.
    С использованием функций в языке С связаны понятия, которые условно можно разделить на две группы.

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

    Вторая группа, параметры и возвращаемое значение, обеспечивает связь функции с «внешней средой». Функция может многократно вызываться из различных частей программы, при этом необходимообеспечить её связь с вызывающей программой, из вызывающей программы в функцию передать необходимые для работы данные, а по окончанию работы принять результат.
    Определение функции – это описание действий, выполняемых функцией согласно требованиям алгоритма. Именно эта часть программы будет впоследствии многократно вызываться из других частей программы.

    Вызов функции обеспечивает связь с вызывающей программой. При вызове:

    • передаются параметры из вызывающей программы в функцию

    • управление передается первой инструкции в теле функции,

    • после завершения работы функции в вызывающую программу передается возвращаемое значение, управление возвращается в точку вызова.

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

    Определение функции состоит из заголовка и тела, например :
    double f1 (int a, int f) //заголовок

    { … } // тело
    В данном примере определена функция f1 с двумя параметрами int a и int f , возвращающая значение типа double

    Тип функции (в нашем примере double) определяет тип значения, которое возвращает функция. Если тип не указан, то предполагается, что функция возвращает целое значение, типа int. Если функция не должна возвращать значение, то используется тип void, который в данном случае означает отсутствие значения. В языке С функция может возвращать только одно значение, для этого её выполнение следует завершить оператором return, содержащим некоторое выражение. Следует отметить, что тип функции в определении должен соответствовать типу выражения оператора return в её теле.
    В заголовке функции параметры называются формальными ( в нашем примере int a, int f), и служат для её связи с вызывающей программой. Формальные параметры создаются в начале работы функции – это локальные переменные, которые инициализируются значениями, полученными из вызывающей программы при вызове функции. Параметры при вызове функции получают конкретные значения и называются фактическими параметрами, например вызов функции может выглядеть так :



    double z;

    int s1=10;



    z = f1(s1, 5); //вызов функции f1, s1 и 5 фактические параметры

    Использование переменных в функции.
    Локальные переменные.

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

    Пример 2: Функция находит максимальное значение из двух целых чисел

    . . .

    int max (int a, int b) // a, b - формальные параметры

    { //------------------------ тело функции

    int r; // локальная переменная r

    if (a>=b) r=a;

    else r=b;

    return (r); // Возврат результата

    }

    void main()

    { int x=4, y=10, big;

    // Вызов функции max, x,y - фактические параметры

    big = max (x,y);

    printf ("big=%d\n", big); // big=10

    printf ("r=%d\n", r); // ошибка, переменной r уже нет!!!

    }
    При вызове формальные параметры функции max() инициализируются фактическими значениями : a =4 b =10

    После окончания работы возвращаемое значение передается в точку вызова функции, значение локальной переменной r, возвращенное функцией max () возникает справа от знака присваивания в операторе big = max (x,y);
    Статические переменные.

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

    // определение функции plus1()

    void plus1()

    {static int x=0;//инструкция выполняется один раз

    int y=0; // выполняется при каждом вызове

    x=x+1;

    y=y+1;

    printf("x=%d , y=%d \n",x,y);

    } // переменная y уничтожается, переменная x сохраняется

    void main()

    {plus1();

    plus1();

    y++; // переменной y уже нет (будет ошибка!)

    plus1();

    x++; // переменная х существует, но не видна здесь (будет ошибка!)

    }
    Инструкция х=0 (в теле функции) выполняется только один раз, при первом вызове функции plus1(). Поскольку переменная х сохраняется ,происходит её увеличение на единицу при каждом вызове функции.

    Локальная переменная y создается каждый раз заново при вызове функции plus1(), при выходе из функции она уничтожается, и поэтому её значение не сохраняется между вызовами функции.

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

    При 1-ом вызове х=1, y=1

    При 2-ом вызове х=2, y=1

    При 3-ем вызове х=3, y=1
    Глобальные переменные.

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

    Переменная g доступна как в функции main(), так и во всех других функциях программы.

    #include "stdafx.h"

    #include

    #include

    int g=10; // глобальная переменная

    void plus1() // определение функции plus1()

    { int p=10; // локальная переменная

    g=g+1;

    p=p+1;

    printf("Плюс 1: g=%d\tp=%d\n",g,p);

    }

    void minus1() // определение функции minus1()

    { int m=10; // локальная переменная

    g=g-1;

    m=m-1;

    printf("Минус 1: g=%d\tm=%d\n",g,m);

    }

    // вызывающая программа

    int _tmain(int argc, _TCHAR* argv[])

    { setlocale(0,"Russian");

    printf("начало: g=%d\n",g);

    plus1();

    plus1();

    g++; // обращение к глобальной переменной g

    printf("Середина: g=%d \n",g);

    minus1();

    minus1();

    // локальные переменные здесь недоступны :

    p++; // ошибка доступа!

    m++; // ошибка доступа!

    printf("Конец g=%d \n",g);

    system ("pause");

    return 0;

    }

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

    Начало : g=10

    Плюс 1: g=11 p=11

    Плюс 1: g=12 p=11

    Середина : g=13

    Минус 1: g=12 m=9

    Минус 1: g=11 m=8

    Конец : g=11
    Глобальная переменная g доступна из любой функции программы, включая функцию main(). К переменным p и m доступа из функции main() нет, этих переменных просто не существует в момент выполнения функции main().

    Глобальные переменные по-умолчанию инициализируются нулем.

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

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

    int g=10; // глобальная переменная

    void plus1() // определение функции plus1()

    { static int k=0; // статическая переменная (сохраняется)

    int p=10; // локальная переменная (уничтожается)

    g=g+1;

    p=p+1;

    printf("Плюс %d: g=%d\tp=%d\n",k,g,p);

    }

    int _tmain(int argc, _TCHAR* argv[])

    { setlocale(0,"Russian");

    printf("начало: g=%d\n",g);

    plus1();

    plus1();

    plus1();

    . . .

    }

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

    Начало : g=10

    Плюс 1: g=11 p=11

    Плюс 2: g=12 p=11

    Плюс 3: g=13 p=11

    . . .

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

    • для каждого формального параметра создаётся локальная переменная;

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


    Пример 5:

    int sum(int a, int b)

    { return a+b;

    }

    void main()

    { int x =5,y=10,z;

    z = sum(x,y);

    }
    При вызове функции создаются две локальные a b переменные, которые инициализируются фактическими параметрами x y :

    a=x

    b=y

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

    Во всех предыдущих примерах вызываемой функции передавались не сами переменные, а лишь их значения. При таком вызове функция не может изменить саму переменную в вызывающей программе, она может изменить лишь её временную копию (параметр), значение которой теряется при выходе из функции.
    Пример 6: функция power() возводит base в n-ю степень.

    #define dec 25

    int power (int base, int n)

    { int p;

    for (p = 1; n > 0; --n)

    p = p * base;

    return p;

    }

    void main()

    { i, p=0;

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

    p=p+power(dec , i);

    ….

    }
    При вызове функции : base=dec, n=i

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

    int func (char s[100])

    { . . . }

    Такое определение функции ограничивает её применение, обрабатываться будут только массивы размером 100.
    Вызов функции :

    int A[100];

    func (A)


    • Передать массив неопределенного размера, определение функции:

    int func (char s[], int n)

    { . . . }

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

    // Пример обработки массива в 100 элементов.

    int A[100];

    func (A, 100)

    Примеры программирования.
    Пример 7: Вычисление суммы массива.

    В примере первый параметр определяет сам массив, а второй – его размер.



    int summa (int array[ ], int n)

    { int res=0;

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

    res+= array[i];

    return res;

    }
    void main()

    {// определение массива в 30 элементов

    int mas[30];

    // инициализация массива

    for (int i = 0; i < 30; i++)

    mas[i] = 2*i + 1;

    // создание переменной s и вычисление суммы

    int s = summa (mas, 30);

    }
    Пример 8: С помощью датчика случайных чисел создать матрицу вещественных чисел 5Х5, вывести на экран, найти минимальные элементы в строках и максимальные элементы в столбцах. Все действия с матрицей оформить в виде функций, создать следующие функции:
    #include

    #include

    #include

    #define raw 5 // количество строк

    #define col 5 // количество столбцов

    // ______область определения функций________________________

    //функция для инициализации матрицы;

    void initmatr(double M[raw][col])

    {int i,j;

    for (i=0;i
    for (j=0;j
    M[i][j]=rand()%100/3.;

    }

    //функция для печати матрицы

    void printmatr(double M[raw][col])

    {int i,j;

    for (i=0; i
    {for (j=0;j
    printf("%7.3f\t",M[i][j]);

    printf("\n");

    }

    }

    // поиск минимального элемента в строке.

    double rawmin (double M[raw][col], int traw)

    { double min;

    int i;

    for (i=0,min=M[traw][0];i
    if (min > M[traw][i]) min=M[traw][i];

    return min;

    }

    // поиск максимального элемента в столбце

    double colmax (double M[raw][col], int tcol)

    { double max;

    int i;

    for (i=0,max=M[0][tcol];i
    if (max < M[i][tcol]) max=M[i][tcol];

    return max;

    }

    //конец области определения функций____________________
    int _tmain(int argc, _TCHAR* argv[])

    { setlocale(0,"Russian");

    // область определения объектов (выделение памяти)

    double MATR[raw][col],cmax;

    int i;

    srand (time(0));

    initmatr(MATR);

    printf("Исходная матрица:\n");

    printmatr(MATR);

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

    for (i=0;i
    printf("%d строка - %7.3f\n",i+1,rawmin (MATR,i));

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

    for (i=0;i
    {cmax=colmax (MATR,i);

    printf("%d столбец - %4.3f\n",i+1,cmax);

    }

    return 0;

    }

    Функции initmatr() и printmatr() не возвращают значений и имеют по одному параметру, определяющему матрицу.

    Функции rawmin() и colmax() возвращают результат и имеют по два параметра, первый определяет матрицу, а второй обрабатываемую строку (столбец). Возвращаемое значение без запоминания выводится на экран, когда вызов функций rawmin() является параметром в функции printf(). Результат, возвращаемый функцией colmax() запоминается в переменной cmax, а затем выводится на экран.

    Вопросы.

    1. Поясните общие понятия, связанные с использованием функции: определение, вызов, параметры функции.

    2. Что такое прототип функции, когда он используется.

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

    4. Какую роль выполняют параметры в функции? Расскажите о формальных и фактических параметрах функции.

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

    6. Какая разница между локальной и глобальной переменными?

    7. Как передать массив в функцию?

    Варианты заданий.
    Общие требования.

    1. Все исходные массивы задавать с помощью генератора случайных чисел, который должен выдавать различные последовательности при многократном запуске программы.

    2. Все исходные массивы следует выводить на экран в форматированном виде (подобно примеру 8)

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

    Для каждого варианта создать специфические функции для решения поставленной задачи, например, для задания №1 написать функцию вычисления произведения произвольного массива, а затем 4 раза её использовать для разных массивов (для A,B,C,D)

    1. Выводить промежуточные результаты, например, в задании №1 вывести не только исходные массивы A,B,C,D и результат P, но и произведения по каждому из массивов.

    2. На экран выводить поясняющие тексты, подобные примерам.



    Номер варианта задания

    Задание

    1, 11, 21

    Задать значения вещественным элементам массивов

    А = {ai| i = 0,1,…,7}, B = {bjj = 0,1,…,5},

    C = {ck k = 0,1,…,9}, D = {dn n = 0,1,…,9} и вычислить



    2,12, 22

    Задать целочисленные значения переменным m, n, l, вычислить их факториалы и рассчитать значение формулы:

    если

    3,13,23

    Задать значения вещественным элементам массивов

    А = {ai| i = 0,1,…,15}, B = {bjj = 0,1,…,25}, сформировать массив С, состоящий из элементов, расположенных между минимальным и максимальным элементами каждого из массивов А и В. 




    4, 14, 24

    Задать значения вещественным элементам массивов

    А = {ai i = 0, 1,..., 6}, B = {bjj = 0, 1, 2, 3},

    C = {ck k = 0, 1, 2,..., 10} и вычислить



    5,15,25

    Задать целочисленные двузначные массивы

    А = {ai i = 0, 1,..., 25}, B = {bjj = 0, 1, … 33},

    C = {ck k = 0, 1, 2,..., 50} D = {dn n = 0,1,…,40} Определить количество повторяющихся элементов для каждого массива. Определить сумму массива с максимальным количеством повторяющихся элементов.

    6, 16 , 26

    Задать значения вещественным элементам массивов

    X = {xi| i = 0, 1, 2,..., 5}, Y = {yj| j = 0, 1, 2,..., 7},

    Z = {zk| k = 0, 1, 2,..., 9}, и вычислить

    если

    7,17,27

    Задать массив вещественных не повторяющихся чисел

    А = {ai i = 0, 1,..., 26}. Сформировать такой массив В, чтобы случайное число bi было меньше ai.

    Отсортировать массив В по убыванию.

    8,18,28

    Задать целочисленные двузначные массивы

    А = {ai i = 0, 1,..., 26}, B = {bjj = 0, 1, … 33},

    C = {ck k = 0, 1, 2,..., 10} D = {dn n = 0,1,…,39}

    В каждом из массивов найти:

    • среднее арифметическое всех элементов массива

    • количество элементов со значением меньшим, чем среднее арифметическое (вывести эти элементы на экран).







    9,19,29

    Задать целочисленные двузначные массивы

    А = {ai i = 0, 1,..., 20}, B = {bjj = 0, 1, … 30},

    C = {ck k = 0, 1, 2,..., 40}Для массива с максимальной суммой переместить положительные элементы в начало, а отрицательные – в конец.

    10,20,30

    Задать целочисленные двузначные массивы

    А = {ai i = 0, 1,..., 26}, B = {bjj = 0, 1, … 33} так, чтобы в каждом не было повторяющихся элементов. Найти минимальные элементы, отсортировать массивы по возрастанию.



    написать администратору сайта