Главная страница

Ответы на ПНЯВУ. Указатель на структурную переменную. Указатели на структурные переменные Создается теми же способами, что и на обычные переменные пример кода struct test


Скачать 33.33 Kb.
НазваниеУказатель на структурную переменную. Указатели на структурные переменные Создается теми же способами, что и на обычные переменные пример кода struct test
Дата22.03.2019
Размер33.33 Kb.
Формат файлаdocx
Имя файлаОтветы на ПНЯВУ.docx
ТипУказатель
#71237



  1. Структурные типы данных и переменные этих типов.

Структурный тип данных - это тип, созданный на основе одного или нескольких базовых типов.

Синтаксис:

struct point {

int x;

int y;

};
Доступ к отдельному компоненту структурной переменной осуществляется посредством конструкции имя_переменной.компонент.

Основным отличием от класса является то, что по умолчанию в структуре модификатор доступа - public.

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

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

3. Указатели на структурные переменные

Создается теми же способами, что и на обычные переменные.
пример кода:

struct test {

int a;

};
int main(){
struct test x;

struct test* y = &x;

y->a=10;
printf("%d", y->a);
}

4. Массивы структурных переменных.

Создается так же, как и массив обычных переменных.

Пример кода:

struct test {

int a;

};
int main(){
struct test x[10];

x[1].a = 15;
printf("%d", x[1].a);
}
5. Объединения.

Объединение - это переменная, которая может в разные моменты времени содержать в себе объекты различных типов и размеров. Размер памяти, выделяемый под объединение, таков, чтобы хватило места под любой член объединения. Синтаксис доступа к членам объединения в точности такой же, как и при работе со структурными переменными.

Пример кода: Объединение внутри структуры.

struct {

char *name;

int flags;

int utype;

union {

int ival;

float fval;

char *sval;

} u;
} symtab [300];
Для ссылки на ival необходимо написать

symtab[i].u.ival,
а к первому элементу строки sval можно обратиться любым из двух следующих способов:

*symtab[i].u.sval,

symtab[i].u.sval[0].

Инициализировать объединение можно только значением, имеющим

тип его первого члена.

6. Поля битов. Средство typedef.

Поля битов - это некоторое множество битов, лежащих рядом внутри одного машинного слова. Длина машинного слова зависит от реализации. Синтаксис описания полей битов и доступа к ним также базируется на синтаксисе описания переменных:


struct {

unsigned int a:1;

unsigned int b:1;

unsigned int c:2;

} flags;
и обработки структурных

Тут описана переменная flags, которая содержит два однобитовых и одно двухбитовое поле. Числа, следующие за двоеточием, задают ширину поля. Поля, как правило, описываются как беззнаковые целые, но они могут быть и типа int.

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

Средство typedef позволяет переименовывать типы данных, при этом не меняя их сути. Пример кода:

typedef int length;

делает имя length синонимом int. С этого момента тип length можно применять при описании, в операторе приведения и т.д., точно так же, как тип int.

7. Понятие макроподстановки.

С помощью макроподстановки можно менять название команд и типов данных в языке C++. Пример кода:

#define инт int.
Также с помощью макроводстановки можно писать макросы, например

#define kvadrat(A) A*A

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

Разница в том, что оператор typedef добавляет новое имя к уже существующим. Директива #define - это команда препроцессора. typedef поддерживается на уровне языка.

8. Включение файлов.

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

Пример кода:

#include - подключение стандартной библиотеки.

#include ‘’Class.h’’ - подключение собственного файла.
9. Условная компиляция.

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

Существует следующая грамматика:
Сначала объявляется

#define DEBUG (DEBUG - название како-либо переменной).

Затем можно писать алгоритм.

#ifdef DEBUG

//выполнение этого кода

#endif
Также можно использовать условие.

#ifdef DEBUG

//выполнение этого кода

#else

//выполнение того кода

#endif
Существует также команда #ifndef (if NOT def) - работает обратно #ifdef.

Также переменной DEBUG можно присвоить значение и строить более сложные условия.

#define DEBUG 5
#if DEBUG > 4

//выполнение этого кода

#else

//выполнение этого кода

#endif

Пример кода:

#include

using namespace std;

#define DEBUG 5

int main()

{

#if DEBUG > 5

cout << "DEBUG bigger than 4" << endl;

#else

cout << "DEBUG smaller that 4" << endl;

#endif

}


10. Стандартные библиотеки math.h и string.h. Основные возможности.




math.h

Имя

Описание

abs, fabs

Возвращает абсолютную величину целого или вещественного числа

acos

арккосинус

asin

арксинус

atan

арктангенс

ceil

округление до ближайшего большего целого числа

cos

косинус

exp

вычисление экспоненты (e^x)

fabs

абсолютная величина (числа с плавающей точкой)

floor

округление до ближайшего меньшего целого числа

fmod

вычисление остатка от деления нацело для чисел с плавающей точкой

log

натуральный логарифм

log10

логарифм по основанию 10

modf(x,p)

извлекает целую и дробную части (с учетом знака) из числа с плавающей точкой

pow(x,y)

результат возведения x в степень y, xy

sin

синус

sqrt

квадратный корень

tan

тангенс



string.h

1)

Char *srrcpy (char *s, const *t)

char a[], b[], c[]

a=strcpy (b,c) - копирует строчку С в B.

2)

Char *strcat (char *s, const star *t) — присоединяет точку t к строчке  s. Возвращает S.

3)

char *strchr (const char *s, ‘c’) — возвращает указатель на первое вхождение символа C в строчку S. Или, если такого не оказалось, возвращает NULL.

Char a{} = «rama», t[];

Int b = ‘a’;

T = strchr (a, b);

Вернется ama.

4)

Char *strrchr (const char *s, ‘c’) — Возвращает указатель на последнее вхождение символа С в строчку S. Или. Если такого не оказалось, возвращает NULL.
5)

Int strlen (const char *s) — возвращает длину строки S.

11. Стандартные библиотеки ctype.h и stdlib.h. Основные возможности.
Функции проверки класса символов ctype.h.


  1. int isalpha (int c) — возвращает не ноль, т.е. Истину. Если c - буква. И ноль в противном случае.

  2. Int issupper (int c) — возвращает не ноль, если С - буква верхнего регистра и ноль в противном случае

  3. Int islower (int c) — возвращает не ноль, если С - буква нижнего регистра и ноль в противном случае.

  4. Int isdigit (int c) —  возвращает не ноль, если С - цифра.

  5. Int isalnum (int c) — возвращает не ноль, если С - цифра или буква.

  6. Int isspace (int c) — возвращает не ноль, если С - любая пробельная литера. (_. \t. \n. \v. \f. \r)

  7. Int ispunct (int c) — возвращает не ноль, если С - печатаемый символ, кроме пробельных символов, буквы или цифры.

  8. Int iscntrl (int c) — возвращает не ноль, если С - отправляющий символ.

  9. Int tolower (int c) — если С - буква верхнего регистра, то С переводится на нижний регистр. В противном случае С не меняется.

  10. Int toupper (int c) — Если С - буква нижнего регистра, то переводится на верхний, в противном случае С не меняется.



Функции общего назначения. .


  1. double atof(const char *s) - переводит строчку S в double. Рассматривает начальные символы до первого неподходящего символа. Начальные пробелы игнорируются. Вход : ___ -3.78abc48; Выход : -3.78.

  1. Int atoi (const char *s)

  2. Long int atol (const *s) — Переводит строчку S в длинное целое.

  3. Int rand(void) — возвращает целое псевдослучайное число в диапазоне от нуля, до максимального целого в данной реализации.


12. Обработка двоичных файлов. Последовательный и произвольный доступ.

Хранение информации в двоичном коде.

При помощи ранее изученных функций fscanf fprintf fgetc fputc и прочих можно организовать работу с текстовыми файлами. Наряду с текстовыми файлами можно использовать и двоичные. Расширение .dat. Хранение информации в двоичных файлах позволяет существенно ускорить время считывания и записи существует два способа доступа к элементам двоичных файлов. Последовательный и произвольный.

Первый последовательный способ используется как правило для перебора всех данных, хранящихся в файле. Заполнение пустых файлов так же возможно только в последовательном режиме. Для открытия и накрытия двоичных файлов используются известные функции fopen, fclose, но ко всем режимам доступ следует добавлять букву b.

Для записи в файл используется функция fwrite, чей прототи находится в файле stdio.h.

size_t write (const void *ptr, size_t size, size_t n, file *stream)

const void *ptr - указатель на исходные данные, записываемые в файл.

size_t size - размер в байтах одного элемента данных.

size_t n - число записываемых в файл элементов данных, размером с size байтов каждый.

file *stream - указатель на файловый поток, открытый в двоичном режиме.
#include

Void main (void);

{FILE *giena;

int mass[100];

Giena = fopen («ttt.dat», «wb»);

For (int I = 0; I < 100; i++)

{

Mass[i] = i*i;

}

Fwrite (mass, sizeof(int), 100, giena);

fclose (giena);
При чтении из файла используется функция fread в отличие от функции fwirte, её первым аргументом является адрес переменной, в которую нужно положить считываемые данные. Чтобы узнать размер считываемого файла используется функция filelenth, которая принимает в качестве аргумента дескриптор файла. Для получения дескриптора используется функция преобразования файлового потока в дескриптор fileno.

#include

Void main (void);

{FILE *giena;

Int desk;

float x, max;

giena = fopen («ttt.dat», «rb»);

desk = fileno(giena);

Fread = (& max; sizeof(float); 1; giena);

For (int I = 1; I < filelenth(desk); i++);

{fread (&x, sizeof(float); 1; giena);

}

If ( x > max)

{max = x

}

printf («max = «%f», max);

Fclose (giena);

getch();

}
Произвольный доступ.

Организация произвольного доступа к компонентам файла позволяет считывать значения из любой позиции файла, а так же записывать новую информацию в любое место в файле. Все компоненты файлов с произвольным доступом должны иметь одинаковую длину. Для изменения места файла, откуда будет производиться следующая операция чтения или записи служит функция fseek, её прототип содержится в файле stdio.h. А заголовок имеет вид:

int fseek (FILE *stream, long offset, int whence);

Функция возвращает 0 в случае успешного завершения. И не нулевое значение в противном случае.

FILE *stream - указатель на файловый поток.

long offset - число байтов, на которые нужно переместить файловый указатель.

int whence - указатель на положение точки отсчета, от которого будет происходить файлового указателя.

SEEK_SET - переместитель относительно начала файла.

SEEK_END -переместитель относительно конца файла.

SEEK_CUR - переместитель относительно файлового потока.
#include

Void main (void);

{FILE *giena;

Int x;

Giena = fopen («ttt.dat», «rb»);

Fseek (giena, 25*sizeof(in), SEEK_SET);

Fread (8x, sizeof(int), 1, giena);

Printf («Prochitano 26 chislo v faile = %d\n», x)’

getch();

}
Для определения конца файлового потока можно исользовать функцию feof, которая возвращает истину, если указатель файлового потока находится за последним байтом файла и 0 в противном случае. На вход функции подается указатель на открытый файловый поток.
Feof

While (!feof(giena))

13. Аргументы, используемые по умолчанию.

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

Если задан прототип

void ShowMsg (char *msg, int x=0, int y=0);

то корректными будут следующие вызовы:

ShowMsg("Error: Out of Memory");

ShowMsg("Error: Vseh doloy",25);

ShowMsg("Error: Domoy ohota",25,25);

А вызов ShowMsg("Error: Vse ravno",,25);

будет неверным.

14. Использование ссылок.

В С++ используется видоизмененная форма указателя, называемая ссылкой. Для ссылки не требуется дополнительного пространства в памяти, так как она является просто другим именем или псевдонимом переменной. Для определения ссылки используется унарный оператор &.

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

# include

int main() {

int j=10;

void aaa(int);

void bbb(int *);

void ccc(int &);

printf("j=%d\n",j); //j=10

aaa(j);

printf("j=%d\n",j); //j=10

bbb(&j);

printf("j=%d\n",j); //j=11

ccc(j);

printf("j=%d\n",j); //j=12

return 0; }

void aaa (int i)

{i++;}

void bbb (int *i)

{(*i)++;}

void ccc (int &i)

{i++;}


Главным преимуществом ссылок по сравнению с указателями

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

15. Встроенные функции.

С помощью команды inline, описанной перед описанием тела функции можно предписать компилятору помещать целиком код программы везде, где происходит обращение к ней вместо того, чтобы создавать код вызова. Компилятор может проигнорировать inline если в функции есть цикл, swith, goto, функции void и не содержащих return. Определение встроенной функции должно обязательно предшествовать её вызову.

Пример кода:

# include

inline int max2(int,int);

int max3(int,int,int);

int main(void)

{ int x=10, y=20, z=30, w=40;

x=max3(x,z,w);

z=max2(x,y); //расширения не будет printf("max(%d,%d)=%d\n",x,y,z); return 0;

}

inline int max2(int a, int b)

{ return a>b?a:b; }

int max3(int a, int b, int c)

{ b=max2(a,b); // будет расширение

return max2(c,b);

}
16. Операция разрешения видимости.

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

# include

int a=10;

int main(void) {

int a=100;

if(a>0)

{int a=1000;

printf("a=%d\n",a);

printf("a=%d\n",::a);

}

return 0; }

Выведется.

a=1000

a=10
17. Перегруженные функции.

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

void Showmes(int);

void Showmes(char*);

Тогда при вызове

Showmes(1)

будет подключаться функция

void Showmes(int nom)

{printf("Message:%s\n",spisok[nom]);

},

а при вызове Showmes("Ошибка") будет подключена функция

void Showmes(char* msg)

{printf("Message:%s\n",msg);

}

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

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

void fff(int i)

int fff(int i)

void fff(char i)

void fff(char * i)

@fff$qi

@fff$qi

@fff$qc

@fff$gpc.
18. Особенности описания переменных в программах на С++.

В отличии от языка С:

  1. Локальную переменную можно определять в любом месте программы.

  2. Модификатор const делает переменную настоящей константой и соотвественно такую переменную можно использовать в любом месте, где разрешено использовать только константу.

  3. При описании переменных структурных типов можно опускать ключевое struct.



19. Определение классов.

Класс определяется так же как и структура, за исключением того, что:

1) определение класса содержит одну или несколько спецификаций доступа, задаваемых с помощью ключевых слов public, protected или private;

2) наравне с ключевым словом struct могут применяться слова class или union;

3)наряду с элементами данных определение обычно включает в себя элементы-функции (методы);

4) обычно в нем имеются некоторые специальные функции такие, как конструктор (функция с тем же именем, что и класс) и деструктор (функция, именем которой является имя класса с приставкой - символом

).

Пример кода:

#include

using namespace std;

class example

{

public: int x;

example ()

{

x=10;

}

void get (int x)

{

this->x=x;

}void print()

{

cout << x << endl;

}

example()

{

cout << "proval" << endl;

};

private: float y;
protected: char*b;

};
int main()

{

example x;

x.print();

}

Вывод:

10

proval
20. Элементы класса.

Элементы класса делятся на две основные категории: данные, показывающие состояние объектов, и функции, реализующие поведение этих объектов.

Элементы-данные классов С++ похожи на элементы структур языка С с некоторыми дополнениями:

  • 􏰀  элементы-данные не могут объявляться как extern или register;



  • 􏰀  элементы-данные могут быть перечислениями, битовыми полями, а также представителями ранее объявленных классов;



  • 􏰀  элементом данных класса не может быть представитель самого этого класса;



  • 􏰀  элемент данных класса может быть указателем или ссылкой на сам класс.
    Элемент-функция является функцией, объявленной (описанной) внутри тела класса. Тело функции тоже может определяться внутри определения класса; такая функция будет являться встроенной функцией-элементом. Если функция определяется вне тела класса, то в заголовке перед именем функции помещается имя класса и



операция разрешения видимости. Функцию, определенную вне класса тоже можно сделать встроенной, указав в заголовке определения ключевое слово inline.

Пример кода со встроенными функциями:

#include

using namespace std;

class example

{

public: int x;

example ()

{

x=10;

}

void get (int x)

{

this->x=x;

}void print()

{

cout << x << endl;

};

private: float y;
protected: char*b;

};
int main()

{

example x;

x.print();

}
21. Правила обращения к элементам класса.

В С++ вводится понятие класса как области действия: имена всех элементов класса находятся в области класса - они могут использоваться функциями-элементами класса. Имена элементов класса могут использоваться в следующих случаях:

1) с существующим представителем класса, за которым следует операция доступа к элементу (.);
2) с указателем на существующий представитель класса, за которым следует операция косвенного доступа к элементу (- >);

3) с именем класса, за которым следует операция разрешения видимости.

4) Прямой доступ используется для обращения к элементам-данным и к элементам функциям. Внутри функций этого же класса

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

Пример кода:

#include

using namespace std;

class ttt

{ int x,y;

public:

void Setxy (int xx, int yy)

{x=xx;y=yy;}

void Getxy (int &xx, int &yy)

{xx=x;yy=y;}

};

int main(void)

{ ttt o1;

ttt *o2=&o1;

o1.Setxy(10,10);

int st1,st2;

o2->Getxy(st1,st2);

}
22. Конструктор и деструктор.

C помощью конструктора можно инициализировать переменные класса при его создании или же передавать значение переменных класса при создании классовой переменной. Конструктор должен называться так же, как называется класс и должен был описан в public. Может быть создано несколько конструкторов с разными принимаемыми параметрами. Это будет называться перегрузкой конструктора. Пример кода.

class example

{

public: int x;

example (int n, int h)

{

y=n;

x = h;

}

example()

{

x=12;

}

}

Деструктор нужен для освобождения памяти. Он полезен, когда в объекте выделяется динамическая память и так как она может находиться в поле private до нее нельзя добраться извне. А конструктор добраться может. Конструктор срабатывает, когда классовая переменная уходит из области видимости. В деструкторе можно писать некоторые команды, например вывод информации о том, что конструктор сработал. Или более полезное delete[ ] ‘имя переменной’; Деструктор в классе может быть только один. Конструктор не может принимать никаких значений. Конструктор уничтожает переменные в обратном конструктору порядке. Пример кода.

example()

{

cout << "proval" << endl;

};
23. Перегрузка операций.

С помощью перегрузки операций в языке С++ можно определить сценарий выполнения стандартных операций (+ - и др) для работы с классовыми переменными.

Синтаксис таков:
operator операция (операнды)

Для перегрузки постфикного инкремента (декремента) используется такой синтакисис.

Operator ++(int)

Для унарных операций скобки всегда остаются пустыми. Для бинарных операций второй операнд должен быть описан в скобках.

Пример кода:

#include

using namespace std;

class example

{

public: int x;

example (int n)

{

x=n;

}

int operator + (example m)

{

return x+m.x;

};

};
int main()

{

example y(5);

example x(10);

int sum;

sum = x + y;

cout << sum << endl;

}

Также перегрузку операций можно выносить за пределы класса. Для этого нужно в классе оставить прототип, а за пределами класса написать тело с операцией разрешения видимости.

#include

using namespace std;

class example

{

public: int x;

example (int n)

{

x=n;

}

int operator + (example m);

};

int example :: operator + (example m)

{

return x+m.x;

};

int main()

{

example y(5);

example x(10);

int sum;

sum = x + y;

cout << sum << endl;

}

24. Обработка исключительных ситуаций.

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

Деление на ноль. Обращение к несуществующему элемента массива. Переполнение памяти. Попытка открыть несуществующий файл. Неправильное приведение типов. И другие.

#include

using namespace std;
int main (void)

{float a, b, c;

cin >> a >> b;

try {

if ((a == 0) || (b == 0)) { //Здесь описываются случаи, когда программа может работать некорректно.

throw 567; // Создание исключительной ситуации.

}

}

catch (int i)

{

cout << "Деление на ноль" << endl << "Ошибка № " << i << endl; //Здесь описывается алгоритм действий в случае исключительной ситуации.

}

try

{

if ((a > 4294967296) || (b > 4294967296))

{

throw 228;

}

}

catch(int p)

{

cout << "Выход за пределы максимальной величины" << endl << "Ошибка № "<< p << endl;

}

}



написать администратору сайта