Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЭЛЕМЕНТЫ ЯЗЫКА C.doc
Скачиваний:
8
Добавлен:
05.11.2018
Размер:
476.16 Кб
Скачать
    1. Структура программ

      1. Составные части программы

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

  1. подключение заголовочных файлов – это строки, которые начинаются с #include

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

  3. тексты реализаций основной программы, функций и процедур.

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

    1. Функции в языке си

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

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

Выполнение всей программы начинается с функции основной программы со стандартным именем main (консольное приложение MVS – _tmain). Основная программа может располагаться как до всех процедур и функций, так и после них. Не рекомендуется вставлять ее между другими функциями, так как при этом ее сложно найти.

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

Рассмотрим текст программы:

// Подключение заголовочных файлов

#include "stdafx.h"

#include <conio.h>

#include <locale.h>

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

// Программа вычисления y - куба введенного x

{

// Описания локальных переменных

float x; // Аргумент

float y; // Результат

setlocale(LC_ALL, "russian"); // установка русского режима

// Вывод информации: Что делает программа

printf("Программа вычисления куба введенного числа\n");

// Вывод информации о необходимости ввода

printf("Введите значение вещественного числа, ");

printf("возводимого в куб\n");

// Ввод x

scanf("%f",&x);

// Решение

y = x*x*x;

// Вывод результата

printf("Значение куба введенного числа:\n%f", y);

//Завершение выполнения программы

printf("\n\nНажмите любую клавишу\n");

_getch();

return 0;

}

В функции _tmain описаны две локальные переменные типа float с плавающей точкой: x, y.

Выполнение всей программы начинается с первого исполняемого оператора _tmain: вызова стандартной (уже написанной) функции setlocale. Эта функция описана и там же имеется ссылка на библиотеку с ее кодом в подключенном заголовочном файле (header): locale.h, поэтому в текст программы добавлена строка: #include <locale.h>. Функция setlocale является артефактом реализации программы, то есть потребность в ней не следует из алгоритма вычислений. Функция настраивает вывод и ввод программы на русский язык, причем в соответствии с настройками «Язык и региональные стандарты» MS Windows конкретной машины.

Далее выполняются три вызова стандартной функции printf:

// Вывод информации: Что делает программа

printf("Программа вычисления куба введенного числа\n");

// Вывод информации о необходимости ввода

printf("Введите значение вещественного числа, ");

printf("возводимого в куб\n");

Функция printf описана в подключенном заголовочном файле (header): stdio.h. Обратите внимание на строку подключения заголовочного файла: #include "stdafx.h". Данная строка была автоматически сгенерирована MVS. Признаком подключения стандартных функций является пара скобок < >, между которыми заключается имя заголовочного файла. Использование пары скобок " ", заключающих имя файла "stdafx.h", означает, что этот файл находится там же, где находится файл языка СИ программы. Именно в автоматически сгенерированном MVS файле "stdafx.h" находится строка: #include <stdio.h>.

Первый вызов функции printf выводит на экран строку: «Программа вычисления куба введенного числа» и осуществляет перевод курсора к началу следующей строки.

Второй и третий вызовы функции printf выводят на экран строку: «Введите значение вещественного числа возводимого в куб», далее осуществляется перевод курсора к началу следующей строки.

Обратите внимание, что выводимая информация не содержит упоминания об имени переменной x. Эта информация не нужна пользователю.

Вызовом функции scanf осуществляется ввод значения. Функция scanf описана в подключенном заголовочном файле (header): stdio.h. О том, что требуется осуществить ввод именно значения числа с плавающей точкой указано литералом "%f". Назначение символа & будет рассмотрено позднее.

В секции «Решение» осуществляется возведение значения переменной x в куб умножением (операция *): x*x*x, результат умножения передается переменной y.

Далее вызовом функции printf выводится строка «Значение куба введенного числа:», осуществляется перевод курсора к началу следующей строки, и, наконец, с начала новой строки выводится значение числа с плавающей точкой из переменной y («%f»).

Строки текста «Завершение выполнения программы» являются артефактом реализации программы. Если бы их не было, программа после запуска мгновенно бы завершилась, и Вы не увидели бы результата ее выполнения. Вызовом функции printf сначала пропускается чистая строка «\n\n», далее выводится строка, инструктирующая пользователя «Нажмите любую клавишу», и, наконец, осуществляется перевод курсора к началу следующей строки.

Вызов функции _getch требует ввода с клавиатуры любого символа. Функция _getch описана в подключенном заголовочном файле: conio.h.

Выполнение оператора «return 0;» сообщит операционной системы факт безаварийного завершения функции _tmain.

При компиляции данной программы выдается предупреждающее сообщение (warning) о не безопасном использовании функции scanf. Надо вводить значение x в правильных форматах!

Рассмотрим текст следующей программы:

#include "stdafx.h"

#include <conio.h>

#include <locale.h>

// Описания глобальных переменных

float x; // Аргумент

float y; // Результат

// Возведение x в куб и передача результата y

void Cube(void); // Описание прототипа Cube

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

// Программа вычисления y - куба введенного x

{

setlocale(LC_ALL, "russian" ); // установка русского режима

// Вывод информации: Что делает программа

printf("Программа вычисления куба введенного числа\n");

// Вывод информации о необходимости ввода

printf("Введите значение вещественного числа, ");

printf("возводимого в куб\n");

// Ввод x

scanf("%f",&x);

// Решение

Cube(); // Вызов функции без параметров

// Вывод результата

printf("Значение куба введенного числа:\n%f", y);

//Завершение выполнения программы

printf("\n\nНажмите любую клавишу\n");

_getch();

return 0;

}

void Cube(void)

// Возведение x в куб и передача результата y

{

y = x*x*x;

}

Переменные x и y теперь описаны глобально. Сразу за описаниями переменных описан глобально прототип функции Cube:

void Cube(void); // Описание прототипа Cube

Из этого описания компилятору стало известно, что идентификатор Cube принадлежит функции. Функция Cube не имеет аргументов (void) и не возвращает результата void.

В секции «Решение» выполнение всех вычислений производится вызовом функции Cube.

Алгоритм Cube содержится в секции описания реализации Cube:

void Cube(void)

// Возведение x в куб и передача результата y

{

y = x*x*x;

}

Рассмотрим еще один вариант текста программы:

#include "stdafx.h"

#include <conio.h>

#include <locale.h>

// Описания глобальных переменных

float x; // Аргумент

float y; // Результат

// Возведение x в куб и передача результата y

float Cube(float z); // Описание прототипа Cube

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

// Программа вычисления y - куба введенного x

{

setlocale(LC_ALL, "russian" ); // установка русского режима

// Вывод информации: Что делает программа

printf("Программа вычисления куба введенного числа\n");

// Вывод информации о необходимости ввода

printf("Введите значение вещественного числа, ");

printf("возводимого в куб\n");

// Ввод x

scanf("%f",&x);

// Решение

y = Cube(x); // Вызов функции c параметром x

// Вывод результата

printf("Значение куба введенного числа:\n%f", y);

//Завершение выполнения программы

printf("\n\nНажмите любую клавишу\n");

_getch();

return 0;

}

float Cube(float z)

// Возведение z в куб и возврат результата q

{

float q;

q = z*z*z;

return q;

}

Теперь описан глобально прототип функции Cube:

float Cube(float z); // Описание прототипа Cube

Как видно он соответствует именно описанию функции, возвращающей значение типа float и имеющей один аргумент типа float.

В секции «Решение» имеется вызов функции Cube с фактическим параметром (аргументом) x. Результат расчета функции со значением фактического параметра x присваивается переменной y. Оформление вызова функции максимально приближено к традиционной математической форме. Например, оно близко к вызову стандартной математической функции sin(x).

Рассмотрим текст реализации функции Cube:

float Cube(float z)

// Возведение z в куб и возврат результата q

{

float q;

q = z*z*z;

return q;

}

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

y = 5.0*Cube(x)+1.0;

Далее Петя описал локальную переменную q и алгоритм преобразования формального параметра z в q:

q = z*z*z;

Наконец оператором return, Петя объяснил компилятору, что в качестве результата вычисления функция Cube должна возвратить в вызывающее ее арифметическое выражение на место своего вызова вычисленное значение q:

return q;

Для использования функции Васе надо знать лишь спецификацию использования функции.

Рассмотрим пример такой спецификации:

Функция Cube предназначена для вычисления значения куба вещественного аргумента, принадлежащего диапазону чисел:

.

Прототип вызова функции:

float Cube(float);

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

Теперь рассмотрим оформление функции как процедуры. Имеем программу:

#include "stdafx.h"

#include <conio.h>

#include <locale.h>

// Описания глобальных переменных

float x; // Аргумент

float y; // Результат

// Возведение x в куб и передача результата y

void Cube(float z, float *q); // Описание прототипа Cube

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

// Программа вычисления y - куба введенного x

{

// Описания локальных переменных

int iError; // =0 - нет ошибки ввода, !=0 - ошибка

setlocale(LC_ALL, "russian" ); // установка русского режима

// Вывод информации: Что делает программа

printf("Программа вычисления куба введенного числа\n");

// Вывод информации о необходимости ввода

printf("Введите значение вещественного числа, ");

printf("возводимого в куб\n");

// Ввод

iError = scanf_s("%f",&x);

// Решение

Cube(x, &y);// Вызов функции от x и результатом y

// Вывод результата

printf("Значение куба введенного числа:\n%f", y);

//Завершение выполнения программы

printf("\n\nНажмите любую клавишу\n");

_getch();

return 0;

}

void Cube(float z, float *q)

// Возведение z в куб и возврат результата q

{

*q = z*z*z;

}

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

Cube(x, &y);// Вызов функции от x и результатом y

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

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

В теле функции Cube:

*q = z*z*z;

мы использовали *q, что означает присвоение результата вычисления куба переменной, начинающейся с адреса q. Другими словами, мы изменили значение переменной y в функции _tmain!

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

В данной программе вместо процедуры ввода scanf использована функция scanf_s:

iError = scanf_s("%f",&x);

Теперь компилятор не находит никаких дефектов написания программы и сообщение warning пропало.

Функция scanf_s отличается от функции scanf тем, что при ее использовании не наступают форс-мажорные завершения при неправильном вводе значения числа с плавающей точкой. В случае выявления обстоятельства форс-мажорного завершения функции, функция возвращаемым значением в переменную iError сообщает в вызвавшую функцию _tmain код ее завершения. Теперь, используя значение переменной iError, программист должен позаботиться о дальнейшей обработке возвращенного кода завершения.