Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебное пособие2013_09_28.doc
Скачиваний:
24
Добавлен:
20.05.2015
Размер:
2.72 Mб
Скачать

Указатели на структуры

Указатель на структуру мы можем определить таким же способом, как и указатель на значение любого другого типа. Например,

struct anketa *uk;

определяет указатель на структуру типа anketa. Этот указатель на структуру далее может быть исползован как обычно. Однако использование составных (квалифицируемых) имен в этом случае несколько меняется. Например, если имеют место определения

struct anketaa1;

uk= &a1;

то запись(*uk).tarifобеспечивает доступ к полюtarifструктурыa1,на которую ссылается указатель uk. Скобки здесь необходимы, так как операция “точка” имеет более высокий приоритет, нежели '*'. Эта запись означает "мне нужно поле tarif той структуры, на которую ссылается указатель uk".

В языке С/С++ есть, однако, более элегантная конструкция использования указателя для доступа к полям структуры, а именно, доступ к элементу структуры по указателю с помощью операции "–>" в виде: <указатель на структуру> "–>" <элемент_структуры>.

uk->tarif

Обе формы использования указателя здесь равноправны и соответствуют записи a1.tarif. Использование ”стрелки”, т.е. пары символов ( –>) делает использование указателей на структуры более выразительным.

Есть немало причин использования указателей на структуры. Одна из них – обеспечить двустороннюю связь с функциями. Например, для начисления заработной платы ( sum ) служащим по известной часовой тарифной ставке ( tarif ) и количеству отработанных часов (work) можно воспользоваться функцией summa4(), которая в качестве аргумента получает указатель (адрес) на структуру типа anketa, что обеспечивает двустороннюю передачу информации

// 4)возврат функцией результата через указатель

// прототип: void summa4(struct anketa *)

void summa4(struct anketa *uk)

{

uk->sum=(uk->tarif*uk->work);

}

Для вызова такой функции (в цикле с параметром k используется массив структур vedom[]) следует записать

summa4(&vedom[k]);

Обратите внимание, что имя структуры vedom[k]– не адрес её (!). Поэтому наличие символа & перед именем структуры необходимо.

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

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

// 3a) аргумент - ссылка на структуру.

void summa3a(anketa &nachisleno)

{

nachisleno.sum = (nachisleno.tarif*nachisleno.work);

}

Для вызова такой функции (в цикле с параметром k используется массив структур vedom[]) достаточно записать

// 3а)передача функции ссылки на структуру в качестве аргумента

summa3a(vedom[k]);

Структуры как параметры функций

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

Задача 161. Рассмотрим механизм взаимодействия формальных и фактических параметров для этих случаев на примере функции summa(), вычисляющей зарплату (sum) каждого служащего по заданной тарифной ставке (tarif) и количеству отработанных часов (work).

// vozv_ank_2011.cpp

#include "stdafx.h"

#include <string.h>

#include<conio.h>

#include<stdio.h>

#include <iostream>

using namespace std;

// Массив анкет, Функции и структуры, возврат структур

#define LIM 30 // число служащих

struct anketa // anketa - имя нового типа!

{ char fio[30];

int tabn;

float tarif;

int work;

float sum;

};

// Варианты функции summa (1-5)

// 1) параметры - элементы структуры

//double summa1(double x, int y)

//{

// return x*y;

//}

// 2) арг - указатель на структуру

//double summa2(const struct anketa *uk)

//{

// return (uk->tarif*uk->work);

//}

// 3) арг - сама структура

//double summa3(anketa nachisleno)

//{

// return (nachisleno.tarif*nachisleno.work);

//}

// 3a) арг - ссылка на структуру.

//Чаще всего параметры-структуры передаются в функции по

//ссылке (при объявлении за именем типа структуры ставят знак &).

//В этом случае фактически в функцию передается адрес структуры

//и функция работает с тем же экземпляром, что и вызывающая

//программа.

void summa3a(anketa &nachisleno)

{

nachisleno.sum = (nachisleno.tarif*nachisleno.work);

}

// 4)возврат результата через указатель

// двусторонняя передача информации

// прототип: void summa(struct anketa *)

//void summa4(struct anketa *uk)

//{

// uk->sum=(uk->tarif*uk->work);

//}

// 5) возврат функцией результата через возврат структуры

// здесь функция создает собственную копию структуры vedom[]

//struct anketa summa5(struct anketa rab)

//{

// rab.sum=(rab.tarif*rab.work);

// return rab;

//}

int main()

{

anketa vedom[LIM]; //массив структур типа anketa

int k=0,i; system ("chcp 1251");

cout<<"Введи до "<<LIM<<" фамилий"<<'\n';

cout<<"Для прекращения - Enter в начале строки"<<'\n';

cout<<"Фамилия "<<k+1<<" -го служащего";

while((gets(vedom[k].fio)!=NULL)&&

(vedom[k].fio[0])!='\0' &&k<LIM )

{

cout<<"табельн номер - "<<vedom[k].fio; cin>>vedom[k].tabn;

cout<<"часовой тариф - "<<vedom[k].fio; cin>>vedom[k].tarif;

cout<<"отраб часов - "<<vedom[k].fio; cin>>vedom[k].work;

// непосредсвенное вычисление поля sum без функции

// vedom[k].sum = vedom[k].tarif*vedom[k].work;

// 1) передача функции элементов структуры

// vedom[k].sum = summa1(vedom[k].tarif,vedom[k].work);

// 2) передача функции указателя на структуру

// vedom[k].sum = summa2(&vedom[k]);

// 3) передача функции всей структуры в качестве аргумента

// vedom[k].sum = summa3(vedom[k]);

// 3а) передача функции ссылки на структуру как аргумент

summa3a(vedom[k]);

// 4) возврат функцией результата через указатель

// summa4(&vedom[k]);

// 5) возврат функцией результата через возврат структуры

// vedom[k]=summa5(vedom[k]);

//ВНИМАНИЕ!!!

fflush(stdin); //очистить входной поток!

// Иначе 2-ю фамилию уже не введем, gets() определяет NULL

k++;

if(k<LIM)

cout<<"Фамилия "<<k+1<<" -го служащего ";

}

cout<<"\n\n\n\tВедомость на выплату зарплаты\n\n";

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

printf("\n%-20s \t %10.2f\t %6d %10.2f\t ", vedom[i].fio,vedom[i].tarif,vedom[i].work, vedom[i].sum );

getch();return 0;

}

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

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

struct anketa //anketa - имя нового типа!

{

char fio[30];

int tabn;

float tarif;

int work;

float sum;

};

void strsort(anketa str[],int n); //прототип

// функция вычисления зарплаты

//void summa (anketa *uk)//указатель на структуру

//{

// uk->sum = uk->tarif*uk->work;

//}

double summa(anketa rab) // параметр - сама структура

{

return rab.tarif*rab.work;

}

int main()

{

//массив структур типа anketa

anketa vedom[]={ { "Иванов И. И.", 1234} ,

{ "Петров П. П.", 2345},

{ "Бендер О. И.", 3456} ,

{ "Ивановский П. А.", 4567},

{ "Петров А. П.", 6789 },

{ "", 0} //признак конца списка

};

system("chcp 1251"); //переключаем в кодировку win1251

int k=0,i; //setlocale(NULL, ".1251");-без ввода строки

//LIM - реальное (!) число записей

int LIM = sizeof(vedom)/sizeof(anketa);

for(i=0; i< LIM-1; i++)

printf("\n%-20s %8d \n",

vedom[i].fio,vedom[i].tabn);

//getch();

cout<<"Введи до "<<LIM-1<<" записей"<<'\n';

while((vedom[k].fio[0])!='\0'&& k<LIM )

{

cout<<"часовой тариф - "<<vedom[k].fio<<" ";cin>>vedom[k].tarif;

if(!vedom[k].tarif) break;

cout<<"отраб часов - "<<vedom[k].fio<<" ";cin>>vedom[k].work;

//vedom[k].sum = vedom[k].tarif*vedom[k].work; //без функции

//summa(&vedom[k]); //к функции с указателем на структуру

vedom[k].sum=summa(vedom[k]);//к функции аргумент - сама структура

k++;

}

//getch();

// обратиться к сортировке

strsort(vedom,k);

cout<<"\n\n\n\t\tВедомость на выплату зарплаты\n\n";

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

printf("\n%20s %10.2f %8d %10.2f",

vedom[i].fio,vedom[i].tarif,vedom[i].work, vedom[i].sum );

//*************** ПОИСК ПО ФИО с 2010г.***********

char name[30]; int found=0; k=0;

cout<<"\n\n\nВВЕДИ Фамилию "; cin >> name;

while(vedom[k].fio[0]!='\0' && k<LIM)

{

if(strstr(vedom[k].fio, name))

if(vedom[k].fio[strlen(name)]==' ')//fio завершается пробелом?

// если этот оператор не вставить, то по введенной name Макогон будут

// обработаны и Макогоненко и Макогонский и...

{ printf("\n%-20s %8d %10.2f", vedom[k].fio,

vedom[k].tabn, vedom[k].sum);

found++;

}

k++;

}

if(found>0)

cout<<"\nНАЙДЕНО "<<found << " фамилии "<<name<<'\n';

else

cout << name<< "-Фамилия отсутствует в справочнике\n";

getch();return 0;

}

// для массива структур - сортировка

void strsort(anketa str[],int n)

{

anketa rab; int i,j;

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

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

if(strcmp(str[i].fio,str[j].fio)>0)

{ rab=str[i] ;

str[i]=str[j];

str[j]=rab;

}

}