Возврат из функции нескольких значений

Пусть функция должна возвратить два значения целого типа и получить одно значение того же типа. Для этого можно использовать два способа.

Первый способ заключается в использовании глобальной переменной.

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

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

# include <stdio.h> //uk5.cpp

# include <iostream.h>

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

Void main()

{

int a, kub, qv;

cin>>a; // ввод из потока

qv=fun(a,&kub); //исходное число, адрес ячейки, куда поместить

//второе значение

cout<<"для числа " << a<< "\t квадрат=" <<qv<<"\t куб=" <<kub;

}

int fun(int k, int* p)

{

*p=k*k*k; // значение куба помещаем по адресу *p

return k*k;

}

Стандартные типы даных

Объявление типа данных имеет формат вида

[<класс памяти>] <тип><идентификатор_1>

[ [ = <нач.значение1;> ] [ , <идентификатор_2>[ = нач.зн.2 ] ...];

Класс auto(автоматический) используется для описания локализованных в блоке переменных. Область действия ограничена той функцией или блоком, в котором она объявлена. Класс extern- внешний, используется для явного описания глобальных переменных или для определения ссылок на внешние переменные. Класс register - регистровый, описывает переменные, хранящиеся в сверхбыстродействующей памяти на регистрах; область действия - аналогична переменным класса auto. Переменные классаstatic (статитический) подобно автоматическим переменным локализуются в блоке или функции, где они описаны, но при выходе из блока значения сохраняют.

Примеры объявлений:

static char c, b; register int x=0;

Одни и те же стандартные типы могут иметь эквивалентные названия. Их классификация приведена в таблице 2.

Таблица 2

Типы данных

Обозначение Размер (байт) Диапазон Тип данных
char, signed char -128...127 Символьный со знаком
unsigned char 0...255 Символный без знака
short, short int, signed short , signed short int -32768... Короткое целое со знаком
unsigned short, unsigned short int 0...65535 Короткое целое без знака
int, signed, signed int 1, 2, 4 Зависит от реализации Целое
unsigned, unsigned int 1, 2, 4 Зависит от реализации Целое без знака
long, signed long, long int -2147483648… Длинное целое со знаком
unsigned long 0...4294967295 Длинное целое без знака
float -3.4e-38... 3.14e+38 Вещественное число с плавающей точкой
double -1.7е-308..1.7е308 Вещественное число удвоенной точности
long double   -3.4e-4932... 3.4e4932 Длинное вещественное число удвоенной точности


ТИПЫ, ОПРЕДЕЛЯЕМЫЕ ПОЛЬЗОВАТЕЛЕМ

Кроме рассмотренных ранее типов язык Си позволяет создавать еще 5 типов данных: - структуры (structure),

- объединения (union),

- поля битов (bit fieldse),

- перечисления или перечислимый тип (enumeration),

- с помощью оператора typedef

Структуры

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

Структура в языке С/С++ аналогична по смыслу записи в ТР. Вид ее описания:

struct <имя структуры>

{

тип <имя_поля1>; // Определение структуры

тип <имя_поля2>; // является оператором,

тип <имя_поляN>; // поэтому заканчивается

}; // точкой с запятой.

Определение структуры является оператором, поэтому заканчивается точкой с запятой.

Переменные, которые объединяются структурой, называются членами, элементами или полями структуры.

Пример определения структуры STUDENT (сведений о студенте)

struct STUDENT {

сhar Name[30];

char Groupe[5];

int Age;

};

Такая запись не задает никакой переменной и выделения памяти не производится. Под именем STUDENT задаетcя частный вид структуры или шаблон структуры, т.е. определен новый тип struсt STUDENT. Для объяв­ления конкретных переменных этого типа можно написать:

struct <имяструктуры> <список переменных>;

Пр. struct STUDENT stud1, stud2;

Переменные также могут задаваться одновременно с шаблоном

struct STUDENT {

сhar Name[30];

char Groupe[5];

int Age;

} stud1, stud2;

Теперь объявлены две переменные и компилятор автоматически выделит под них память (под каждую переменную непрерывный участок).

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

struct stud1="Графкин Е.","В-227",18;

Доступ к элементу поля осуществляется с помощью операции "точка" или "выделения элемента": <имя_переменной_стр>.<имя_поля>

Пр. strcpy(stud2.name, "Петров К.");

Для печати содержимого поля группы элемента структуры запись бу­дет иметь вид: printf(" %c", stud1.Grupe);

Для пятого го элемента этого поля - printf("%c",stud1.Grupe[4]);

На практике структурные переменные объединяются в массивы струк­тур. Для объявления массива структур сначала задается шаблон структу­ры, далее объявляется массив:

struct stud1 sudents[40]; // в памяти создается 30 переменных [0..29].

Если объявлены две переменные типа структура с одним шаблоном, то их можно присваивать друг другу: stud2=stud1;

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

Пример: void main() struct St1 m,k;

{struct St1 {int a; struct St2 l;

char b; k . a=1;

}; k . b=’f’;

struct St2 {int a; m=k; // верно

char b; l=k; // неверно

}; l . a=k . a; l . b=k . b; // верно

Переменная типа структура может быть глобальной, локальной или фор-мальным параметром. Любое поле структуры может быть пара­метром функции func1(int k.a); параметром может являтся и адрес поля func2(int &k.a).

Можно в качестве формального параметра передать по значению всю структуру, создать указатель на структуру и передать аргумент типа структуры по ссылке. Объявление указателя на структуру имеет вид:

struct <имя структуры> * <имя указателя>;

Например, struct St*uk; // uk – переменная типа указатель на структуру St.

Если передается стуруктура по значению, то все ее элементы заносятся в стек. Если она содержит в качестве своего элемента массив, стек может переполниться. Поэтому рекомендуется использовать ссылки. При передаче по ссылке в стек заноситься только адрес структуры, при этом копирование структуры не происходит, а так же появляется возможность менять содержимое элементов.

Указателю можно присвоить адрес переменной uk=&m.

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

(*uk).a или uk->a;

Структура операции доступа к полю по указателю

переменная_указатель -> имя_поля; ( перем_указ -> элемент_структуры;)

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

В качестве элементов структуры можно использовать массивы, другие структуры, и массивы структур. Например:

struct Adr сhar

{ city[30];

int ind;

char adres[40];

};

struct STUDadr сhar Name[30];

{ struct Adr addr;

char groupe[6]; } st1, st2;

Adr-шаблон структуры, определеный перед объявлением структуры STUDadr.

Для присвоения значения элементу ind структуры STUDadr значения надо записать: st1.addr.ind=50;

Поля битов

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

Доступ к биту обеспечивают поля битов (bit fields) – это специальный тип членов структуры, в котором определено, из скольких битов состоит каждый элемент. Полем считается последовательность соседних двоичных разрядов в числе типа int или unsigned (signed). Оно объявляется как элемент структуры.

Основная форма объявления структуры битовых полей

struct < имя структуры >

{ <тип имя 1>: <ширина>;

¼

<тип имя N>: <ширина>;

};

где <ширина> – целое число от одного до 16; <тип> – int или unsigned. <Имя> может отсутствовать, тогда отведенные биты не используются (пропускаются). Длина структуры всегда кратна восьми.

Пример 1. Для переменной obj будет выделено восемь бит, но используется только первый.

Struct onebit

{

unsigned b: 1;

}obj;

Пример 2.

struct М{ // значения диапазонов полей

int а:4; // а[-8, 7]

int b:1; // b[- 1, 0]

unsigned с:5; // с[0,31]

int :2; // пусто

int d :2; // d[-2,1]

unsigned е :2 } // е[0,3]

Расположение полей в структуре М из 16 бит получится следующее

А b с не спользуется d е
0 … 3 5 … 9 10 11 12 13 14 15

Операции для полей битов такие же, как и для структур:

Присваивание. Пусть struct М byte; то byte.а=3;

byte.b=0;

Доступ к полю(точка) byte.с=30;

Не допускаются массивы полей битов, указатели на поля битов и функции, возвращающие поля битов. К битовым полям не может применяться операция «&» (адрес).

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

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

Безымянное поле используется только как заполнитель. Для принудительного выравнивания к границе следующего целого числаиспользуется специальный размер Æ

Struct { int f1:1

int : 2;

int f2:1;

:Æ; stb.f3 заполняется в следующем int.

int f3:1 ;

} stb;

Объединения

Наши рекомендации