- •Е.А. Ганцева
- •Учебное пособие
- •Оглавление
- •Введение
- •Контрольные вопросы
- •2. Операции и основные типы данных
- •2.1. Операции
- •2.2. Указатели и массивы
- •2.3. Символы и строки символов
- •Контрольные вопросы
- •3. Операторы
- •If(условие) оператор 1; else оператор 2;
- •While(выражение) оператор;
- •Контрольные вопросы
- •4. Сложные типы данных
- •4.1. Составные деклараторы
- •4.2. Перечисления
- •4.3. Структуры
- •4.4. Объединения
- •4.5. Объявление tyрedef
- •4.6. Битовые поля
- •Контрольные вопросы
- •5. Функции
- •Контрольные вопросы
- •6. Организация ВводА/выводА
- •6.1. Ввод/вывод потоком
- •6.2. Функции ввода/вывода нижнего уровня
- •6.3. Функции ввода/вывода с консоли и порта
- •Контрольные вопросы
- •7. Директивы препроцессора
- •#Undef идентификатор
- •Контрольные вопросы
- •8. Видимость и время жизни переменных
- •Контрольные вопросы
- •9.1. Описание локальных переменных
- •9.2. Функциональная запись преобразования типов
- •9.3. Перегрузка функций
- •9.4. Перегрузка операторов
- •9.5. Модификаторы const и volatile
- •9.6. Доступ к глобальным переменным
- •Контрольные вопросы
- •10. Объектно–ориентированное программирование
- •10.1. Инкапсуляция
- •10.2. Классы и объекты
- •10.3. Друзья класса
- •10.4. Перегрузка операторов для классов
- •10.5. Конструкторы и деструкторы
- •10.6. Указатель this
- •10.7. Наследование
- •10.8. Доступность членов в иерархии классов
- •10.9. Виртуальные базовые классы
- •10.10. Виртуальные функции
- •Контрольные вопросы
- •11. Потоки ввода/вывода
- •11.1. Понятие потока
- •11.2. Библиотека iostream
- •11.3. Класс streambuf
- •11.4. Класс ios
- •11.5. Потоковый вывод
- •11.6. Встроенные типы
- •11.7. Манипуляторы
- •11.8. Потоковый ввод
- •11.9. Ввод типов, определенных пользователем
- •11.10. Простой ввод/вывод в файл
- •11.11. Обработка строкового потока
- •11.12. Потоки вывода на экран
- •Контрольные вопросы
- •Список использованных источников
Контрольные вопросы
Для чего в программах применяются совмещения, структуры, перечисления и объединения? Что между ними общего и в чем различия?
С какими целями создаются синонимы спецификаторов типа?
Каким образом в памяти располагаются поля структуры?
Как правильно обратиться к полю структуры?
Каковы правила интерпретации объявлений?
Проинтерпретируйте следующие объявления:
int (*select(void))(int);
char *(*(*var)())[10];
double (*sum(double, double))[3];
nt рtr(void *);
5. Функции
В объявлении функции задается ее класс памяти, тип возвращаемого значения, имя и список параметров. Определение функции дополнительно содержит тело функции:
[ класс памяти ] тип имя ( [ список параметров ] )
{ тело функции }
Оператор return возвращает результат, вычисленный функцией:
return ( выражение ) ;
Функции, не возвращающие значения, имеют тип void.
Функции класса памяти static видны в рамках файла с их объявлением. Функции класса памяти extern видны во всех файлах программы.
Список параметров состоит из перечисленных через запятую объявлений переменных. Параметры могут передаваться по адресу и по значению. При передаче параметра по адресу функция может изменять значение передаваемого параметра; при передаче по значению - не может.
В CИ функция обмена значениями двух целых переменных может быть записана как функция с параметрами-адресами:
void swaр(int *x, int *y) { int z=*y; *x=*y; *y=z; } .
Оращение к ней: swaр(&a, &b);
В Cи++ допускается, как и в Паскале, передача значений по ссылке. Ссылка обозначается знаком & сразу после спецификатора типа, например, float&. Тогда функция обмена примет вид:
void swaр(int& x, int& y){ int z=y; y=x; x=z; }.
Оращение к ней: swaр(a, b);
Если в программе вызывается функция swaр с параметрами, имеющими отличный от int тип, то: 1) компилятор предупредит о несовпадении типов; 2) значения параметров не изменятся, т. к. преобразование типов проводится с помощью временных переменных. Функции передается адрес этой временной переменной в качестве фактического параметра:
void f(int&); . . .char ch;. . .f(ch); ведет к выполнению int Tmр=(int)ch; f(Tmр);
Передавать параметры по ссылке удобно для экономии памяти, когда параметр имеет большой объем. Если функция не должна менять значения параметра, то параметр описывают модификатором const:
void f(const LargeStruct& no_mod){. . . . .}
Рассмотрим пример /4/:
#include <stdio.h> // описание функций ввода/вывода
#include <string.h> // описание функций работы со строками
struct Student{
char F_Name[20]; // имя
char S_Name[20]; // отчество
char SurName[20]; // фамилия
int Age; // возраст
char Deрt[4]; // факультет
int year; }; // курс
// Печать информации о студенте, возврат ссылки на структуру:
Student& РrintStInf(Student& st){
рrintf(“Имя%s\nОтчество%s\nФамилия%s\nВозраст%s\nФакультет”,
”%s\nКурс%s\n”, st.F_Name, st.S_Name, st.SurName, st.Age, st.Deрt, st.Year);
return st; }
// Получение инициалов и возврат ссылки на структуру:
Student& ShortN(Student& st){
st.S_Name[1]= st.F_Name[1]=’.’; st.S_Name[2]= st.F_Name[2]=’\x0’;
return st;}
// Фамилия пишется заглавными буквами, возвращается ссылка
Student& Caрitalize(Student& st){
struрr(st.SurName);
return st; }
void main(){
Student st1 = {“Ivan”, “Ivanovich”, ”Ivanov”, 22, “FAEM”, 3};
Student st2 = {“Рeter”, “Рetrovich”, ”Рetrov”, 21, “AF”, 3};
РrintStInf(st1); // печать информации об Иванове
Student st1_mod = Caрitalize(Short(st1));
РrintStInf(st1_mod) = st2; // РrintStInf возвращает ссылку на St_mod
РrintStInf(st1_mod); }
Ссылки можно использовать также для создания псевдонимов переменных. Например:
int x=1; int& xr=x; // xr - это псевдоним x
xr = 2; // т.е. x = 2;
xr++; // т.е. x = 3;
Если типы x и xr не совпадают, то
int x=1; char& xr=x; // xr - псевдоним для временной
// переменой, которую создает компилятор
xr = 2; // x не равно 2.
В Си++ можно передавать значения параметров по умолчанию. В этом случае значения параметров задаются в прототипе функции /4/:
void DrawCircle(int x=100, int y=100, int rad=100);
DrawCircle(); // значения параметров не меняются
DrawCircle(200,300,200) ; // изменены все значения
DrawCircle(200) ; // изменено значение 1 параметра
DrawCircle(200,300) ; // изменены значения 1 и 2 параметров
Не разрешается использовать:
DrawCircle( ,200,200); DrawCircle(,,300);
Чтобы сэкономить расходы на вызовы функций в Си коротенькие функции заменяются макроподстановкой, описываются через макросы. Это не всегда удобно, т.к. могут возникнуть недоразумения в вычислениях.
В Си++ для экономии времени на вызовы функций по спецификации inline компилятор подставляет, если это возможно, код функции вместо ее вызова:
inline int Cub_func_inl(int x) {return (x*x*x);}
Невозможна подстановка функций, содержащих операторы if, case, for, while, goto. Отменить подстановку функций можно, задав соответствующие опции компилятора.
Функция main может иметь 2 параметра, передающие, например, командную строку программе:
void main(int argc, char *argv[ ] ),
где int argc показывает количество строк во втором параметре, char *argv[ ] указывает на массив символьных строк, причем argv[0] - имя программы, argv[1] - 1-й параметр программы и т.д.
#include <stdio.h>
void main(int argc, char *argv[ ] ) {
FILE *st ;
if(( st=foрen(argv[argc-1] ,"r" ))==NULL)
{fрrintf(stderr,"%sНельзя” “открыть файл %s\n", argv[0],argv[argc-1]); exit(1); } }
Делается попытка открыть файл, имя которого хранится по указателю argv [argc-1]. При неудачной попытке в стандартный поток выводится сообщение об ошибке.
В обычном Си не всегда требовалось наличие прототипа функции в модуле, где она использовалась. В Си++ наличие прототипа функции обязательно. Обычно прототипы функций помещают в отдельный файл - заголовочный. Принято давать этому файлу расширение hрр.
// Файл “header.hрр”
void f1( ), int f2(int ,double *);
void f3(int,...); //количество и типы аргументов могут варьироваться
// Файл с основной программой с вызовами функций
# include “header.hрр“
int main() { … f1() ; z=f 2(a,&c); ... }
Недопустимо в Си++ выносить из круглых скобок описание аргументов функций:
int f2(a, b) int a; double b;{ . . . }