Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Visual_Studio_2010

.pdf
Скачиваний:
109
Добавлен:
03.03.2016
Размер:
5.94 Mб
Скачать

Результат выполнения программы представлен на рис.10.6.

Рис. 10.6. Пример выделения слов из строки

Задание5

1.В программу включите обработку символов: запятая ',', точка с запятой ';', точка '.' в качестве разделителей слов.

2.Используйте символ пробела для разделения слов «фамилия, имя, год поступления в вуз».

3.В программу включите прототип функции wordstr().

4.Изучите возможность применения в программе функций strcpy_s() и strtok_s().

Пример 6. Написать программу расчета суммы и среднего арифметического числовых произвольного количества данных. В качестве ключевых слов для выбора варианта расчета принять mean (среднее) и sum (сумма).

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

1 n

m n xi ,

i 1

где n – количество числовых данных, xi – текущее число. Программный код решения примера

#include <stdio.h>

#include <conio.h> #include <string.h> #include <stdarg.h>

#include <float.h>

/* Прототип функции с переменным числом аргументов*/ double varfun(char str[], double v1, ...);

171

int main(void)

{

double v1 = 10.0, v2 = 2.5, control;

char str[121];

printf("\n Enter one of the key words 'mean' or 'sum': "); gets_s(str, 120);

control = varfun(str, v1, v2, 7.5, 0.0); if (control < DBL_MAX)

printf("\n Result: %lf\n", control);

else

printf("\n Invalid input keyword.\n");

printf("\n\n ... Press any key: "); _getch();

return 0;

}

/* Определение функции с переменным числом аргументов */ double varfun( char str[], double v1, ...) {

/* Указатель на переменные списка аргументов */ va_list parg;

double sum = v1;

double value = 0.0; /* значение аргумента */

int count = 1; /* начальное количество аргументов */ int k, p;

char *ch = "mean"; char *ch2 = "sum";

// Лексиграфическое сравнение строк k = strcmp(str, ch);

if ( !k ) // k == 0 p = 1;

else if ( k ) // k != 0

{

k = strcmp(str, ch2); if ( !k )

p = 2;

else

p = 0;

}

if ( p == 1 ) {

va_start(parg,v1); /* инициализация указателя parg */

172

/* Просмотр списка аргументов*/

while( (value = va_arg(parg, double)) != 0.0)

{

// Суммирование числовых аргументов функции varfun() sum += value;

count++;

}

/* Завершение процесса счтывания аргументов */ va_end(parg);

return sum/count;

}

if ( p == 2 )

{

va_start(parg,v1);

while( (value = va_arg(parg, double)) != 0.0)

{

sum += value; count++;

}

va_end(parg);

return sum;

}

return DBL_MAX;

}

Возможный вариант выполнения программы показан на рис. 10.7.

Рис. 10.7. Пример выполнения программы

Задание 6

1.Напишите функцию с явным указанием количества аргументов.

2.Включите в программу расчет исправленной выборочной дисперсии (D), которая рассчитывается по формуле

 

1

n

2 ,

D

(xi m)

 

 

n 1i 1

 

где m – среднее арифметическое заданных чисел.

173

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

1.Что лежит в основе всех программ, созданных на языке С?

2.Какие типы данных функция возвращать может и что не может?

3.Что такое прототип функции? Какие элементы объявления функции входят в ее прототип?

4.В чем разница между фактическими и формальными параметрами функции?

5.Какой способ передачи параметров в функциях предусматривает синтаксис языка С?

6.Как можно изменить значение аргумента функции в теле самой функции?

7.Какова область видимости переменных, определенных в теле функции?

8.Можно ли использовать функцию без параметров и без служебного слова void? К каким последствиям это может привести?

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

БИБЛИОГРАФИЧЕСКИЙ СПИСОК

1.Шилдт Г. Полный справочник по С : пер. с англ./Г. Шилдт. – 4-е изд. –

М. : Вильямс, 2007. – 704 с.

2.Кочан С. Программирование на языке С : пер. с англ./С. Кочан. –

3-е изд. – М. : Вильямс, 2007. – 496 с.

3.Харбисон С. П. Язык программирования С : пер. с англ./С. П. Харбисон, Г. Л. Стил. – М. : Бином-Пресс, 2004. – 528 с.

4.Березин Б. И. Начальный курс С и С++/Б. И. Березин, С. Б. Березин. –

М. : ДИАЛОГ-МИФИ, 1998. – 288 с.

5.Подбельский В. В. Программирование на языке Си : учеб. пособие/ В. В. Подбельский, С. С. Фомин. – 2-е изд., доп. – М. : Финансы и стати-

стика, 2007. – 600 с.

6.Хусаинов Б. С. Структуры и алгоритмы обработки данных. Примеры на языке Си (+CD) : учеб. пособие / Б. С. Хусаинов. – М. : Финансы и стати-

стика, 2004. – 464 с.

7.Дейтел Х. М. Как программировать на С : пер. с англ. / Х. М. Дейтел, П. Дж. Дейтел. – 4-е изд. – М. : Бином-Пресс, 2006. – 912 с.

174

Тема 11

УКАЗАТЕЛИ И ФУНКЦИИ В ЯЗЫКЕ ПРОГРАММИРОВАНИЯ С

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

ТЕОРЕТИЧЕСКАЯ ЧАСТЬ

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

Ранее было отмечено, что в языке С аргументы передаются в функции по значению и не существует прямого способа изменить переменную вызывающей функции, действуя внутри вызываемой. Благодаря аргументам-указателям функция может обращаться к объектам в вызвавшей ее функции, в том числе модифицировать их [1]. В качестве примера рассмотрим функцию swap(), в задачу которой входит обмен элементов местами. Для решения такой задачи необходимо передать из вызывающей программы (например, из главной функции main()) в функцию указатели на переменные, которые нужно изменить.

Программный код решения примера

#include <stdio.h>

#include <conio.h>

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

int main (void)

{

int a = 10, b = -20;

// Вывод на консоль исходных значений переменных printf("\n Initial values:\n a = %d, b = %d\n", a, b);

//Вызов функции swap() с фактическими параметрами swap(&a, &b);

//Результат после обращения функции swap() printf("\n New values:\n a = %d, b = %d\n", a, b);

printf("\n ... Press any key: ");

_getch(); return 0;

}

175

// Определение функции

void swap(int *pa, int *pb)

{

int temp; temp = *pa;

*pa = *pb; *pb = temp;

}

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

Результат выполнения программы показан на рис. 11.1.

Рис. 11.1. Результат обмена данными, выполненного функцией swap()

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

Общая форма определения функции, которая возвращает указатель,

следующая:

тип *имя_функции ( аргументы функции )

{

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

тип *имя_указателя;

return имя_указателя;

}

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

176

Программный код решения примера

#include <stdio.h> #include <conio.h> #include <stdlib.h>

int *out2(int A[], int B[], int);

int main (void) { int i, n;

int A[] = {1,2,3,4,5}; int B[] = {2,2,2,2,2}; int *ptrAB = NULL;

n = (sizeof(A)/sizeof(A[0]));

puts("\n The initial arrays: "); for (i = 0; i < n; i++)

printf(" %d", A[i]);

puts("");

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

ptrAB = out2(A, B, n);

puts("\n\n Result from function: "); for (i = 0; i < n; i++)

printf(" %d", ptrAB[i]);

puts("\n\n Control of the arrays: "); for (i = 0; i < n; i++)

printf(" %d", A[i]);

puts("");

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

free(ptrAB); // освобождение выделенной памяти printf("\n\n ... Press any key: ");

_getch(); return 0;

}

int *out2(int A[], int B[], int n) { int i;

int *ptr = (int *)calloc(n, sizeof(int)); //выделение памяти

for (i = 0; i < n; i++) ptr[i] = A[i] + B[i];

return ptr;

}

177

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

Указатели возвращаются подобно значениям любых других типов данных. Чтобы вернуть указатель, функция должна объявить его тип в качестве типа возвращаемого значения. Таким образом, если функция возвращает указатель, то значение, используемое в ее инструкции return, также должно быть указателем. В частности, многие библиотечные функции, предназначенные для обработки строк, возвращают указатели на символы.

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

Указатель на функцию – это переменная, содержащая в памяти адрес, по которому расположена функция [2]. Имя функции – это адрес начала ее программного кода. Указатели на функции могут передаваться функциям в качестве аргументов, возвращаться функциями, сохраняться в массивах и присваиваться другим указателям на функции [2].

Типичное определение указателя на функцию следующее:

тип_возвращаемый_функцией(*имя_указателя_на_функцию)(аргументы);

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

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

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

178

ПРАКТИЧЕСКАЯ ЧАСТЬ

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

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

Программный код решения примера

#include <stdio.h> #include <conio.h>

// Прототип функции

void bsort (int* const, const int);

int main (void) {

int A[] = {56, 34, 2, 0, 1, -21, 6, 8, 7}; int i, n;

//Размерность массива

n = sizeof(A)/sizeof(A[0]);

puts("\n Data items in original order:");

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

// Вызов функции сортировки - bsort() bsort (A, n);

puts("\n\n Data items in ascending order:"); for (i = 0; i < n; i++)

printf(" %3d", A[i]);

printf("\n\n ... Press any key: "); _getch();

return 0;

}

// Определение функции

void swap(int *pa, int *pb) { int temp;

temp = *pa; *pa = *pb;

*pb = temp;

}

void bsort (int *const arr, const int size) {

int pass,j; //счетчик проходов и счетчик сравнений

// Прототип функции обмена - swap() void swap (int*, int*);

179

// Цикл для контроля проходов

for (pass = 0; pass < size - 1; pass++ )

{

// цикл для контроля сравнений на данном проходе for (j = 0; j < size - 1; j++)

{

// обмен значений при нарушении порядка возрастания if (arr[j] > arr[j + 1])

{

swap(&arr[j], &arr[j+1]);

}

}

}

}

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

Прототип функции swap() включен в тело функции bsort(), потому что это единственная функция, которая вызывает функцию обмена swap().

Пример выполнения программы представлен на рис. 11.2.

Рис. 11.2. Пример сортировки массива методом пузырька

Задание 1

1.Напишите программу сортировки семи вещественных чисел, которые должны быть случайными по равномерному закону из интервала [–Х;+Х], где Х – номер компьютера, на котором выполняется лабораторная работа.

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

180

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]