Основы программирования
Пример обработки строки в виде массива
Пример обработки строки в виде массива
Пример обработки строки в виде указателей
Пример обработки строки в виде указателей
Пример обработки строки в виде указателей
Массивы указателей
Структуры, объединения и перечисления
Структуры, объединения и перечисления
Структуры, объединения и перечисления
Структуры, объединения и перечисления
Структуры, объединения и перечисления
Инициализация структур
Анонимные структуры
Структуры и функции
Структуры и функции
Структуры и функции
Структуры и функции
Структуры и функции
Структуры и функции
Структуры и функции
Структуры и функции
Структуры и функции
Структуры и функции
Объединения
Объединения
Объединения
Объединения
The end
1.74M
Категория: ПрограммированиеПрограммирование

Основы программирования. Лекция № 6

1. Основы программирования

Лекция № 6
Ст. преп.
каф. ПОВТ
Масленников
Алексей
Александрович
Строки, структуры

2. Пример обработки строки в виде массива

В следующей программе строки представлены массивами. Копирование
строки-источника в строку-приемник выполняется посимвольно через указатели
с инкрементированием указателей. Условием останова является достижение
конца строки-источника (копирование символа '\0').

3. Пример обработки строки в виде массива

#define MAXLEN 200
void strcpy_(char* s, char* t) {
while(*s++ = *t++);
}
void swaps(char* a, char *b) {
char c[MAXLEN];
strcpy_(c, a); strcpy_(a, b); strcpy_(b, c);
}
int main() {
char s1[MAXLEN] = "first";
char s2[MAXLEN] = "second";
printf("%s, %s\n", s1, s2);
swaps(s1, s2);
printf("%s, %s\n", s1, s2);
return 0;
}

4. Пример обработки строки в виде указателей

В следующей программе строки представлены указателями:
#define MAXLEN 200
void strcpy_(char* s, char* t) {
while(*s++ = *t++);
}
void swaps(char* a, char *b) {
char c[MAXLEN];
strcpy_(c, a); strcpy_(a, b); strcpy_(b, c);
}
int main() {
char* s1 = "first";
char* s2 = "second";
printf("%s, %s\n", s1, s2);
swaps(s1, s2);
printf("%s, %s\n", s1, s2);
return 0;
}

5. Пример обработки строки в виде указателей

В результате выполнения этой программы возникнет ошибка.
Основная причина этой ошибки – попытка изменить символы в строковой
константе, которая имеет свойство «только для чтения». Однако в этом случае
есть более лёгкое решение – строки оставить на месте, а поменять значения
указателей:

6. Пример обработки строки в виде указателей

В следующей программе строки представлены указателями:
void swaps(char** a, char** b) {
char *c = *a;
*a = *b; *b = c;
}
int main() {
char* s1 = "first";
char* s2 = "second";
printf("%s, %s\n", s1, s2);
swaps(&s1, &s2);
printf("%s, %s\n", s1, s2);
return 0;
}

7. Массивы указателей

Так как указатели являются обычными переменными, их можно хранить в массиве.
Создадим объект arrs типа «массив строк», проинициализируем его и выполним
перестановку некоторых элементов этого массива:
void swaps(char** a, char** b) {
char *c = *a;
*a = *b; *b = c;
}
int main() {
char* arrs[] = {"first", "second", "third",
"fourth", "fifth"};
int i, n = sizeof(arrs)/sizeof(*arrs);
for(i=0; i<n; i++) printf("%d: %s\n", i+1, arrs[i]);
swaps(&arrs[0], &arrs[2]);
swaps(&arrs[1], &arrs[4]);
printf("--------\n");
for(i=0; i<n; i++) printf("%d: %s\n", i+1, arrs[i]);
return 0;
}

8. Структуры, объединения и перечисления

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

9. Структуры, объединения и перечисления

Пример. Объявление структуры и доступ к членам структуры.
struct {int x; int y;} pt1, pt2;
pt1.x = 3; pt1.y = 6;
pt2 = pt1;
Синтаксис языка С позволяет отделить описание «внутреннего устройства» структуры от
определения конкретных переменных, имеющих это внутреннее устройство:
struct point {int x; int y;};
struct point pt1, pt2;
Такой подход позволяет рассматривать первое объявление как новый, структурный тип
данных, а второе – как определение переменных этого типа. Допускается совмещать
объявление структурного типа и объявление переменных этого типа.

10. Структуры, объединения и перечисления

Элементы структуры могут иметь произвольный тип, в том числе, они сами могут быть
структурами. Например, можно объявить структуру rect (прямоугольник), используя ранее
объявленную структуру point (точка):
struct rect { struct point p1, p2; };

11. Структуры, объединения и перечисления

Указатели на структуры и массивы структур
Структурные типы данных так же, как и обычные типы данных, могут использоваться для
конструирования указателей и массивов.
Пусть struct T – структурный тип данных, тогда:
struct T x – описывает переменную типа struct T, или просто структуру x,
struct T *p – описывает указатель на структуру типа struct T,
struct T m[5] – описывает массив из пяти структур типа struct T,
struct T *pm[] – описывает массив неопределенного размера из указателей на
структуры типа struct T,
struct T (*pm)[] – описывает указатель на массив неопределенного размера из
структур типа struct T и т.д.

12. Структуры, объединения и перечисления

Указатели на структуры особенно полезны при передаче аргументов-структур в функции,
т.к. приводят к экономии памяти при передаче громоздких структур.
При использовании указателей на структуры язык С имеет специальный синтаксис для
обращения к членам структуры через указатель на структуру. Пусть объявлен структурный
тип point, конкретная структура pt этого типа и указатель pp:
struct point { int x, y;};
struct point pt, *pp = &pt;
Обычный синтаксис доступа к членам структуры pt через указатель pp выглядит так
(скобки нужны потому, что приоритет операции . выше, чем у операции *):
(*pp).x = 3; (*pp).y = 5;
С использованием специального синтаксиса (операции «стрелка») эти же операторы
можно записать более наглядно:
pp->x = 3; pp->y = 5;

13. Инициализация структур

При объявлении структуры ее поля могут быть инициализированы с использованием
списка инициализации. Порядок размещения значений в таком списке и их типы должны
соответствовать порядку расположения и типам полей в структуре.
Пример. Программа проверяет принадлежность точки прямоугольнику с использованием
функции pt_in_rect.
struct point { int x, y; };
struct rect {
struct point pt1, pt2;
};
int pt_in_rect(struct point p, struct rect r) {
if(p.x < r.pt1.x || p.x > r.pt2.x) return 0;
if(p.y < r.pt1.y || p.y > r.pt2.y) return 0;
return 1;
}
int main() {
struct point z = {2, 2};
struct rect rc = {{1, 1}, {4, 5}};
printf("%s\n",
pt_in_rect(z, rc) ? "inside" : "outside");
return 0;
}
Допускается инициализация членов
структуры по их именам (а не по порядку):
struct rect rc = {.pt2={4, 5}, .pt1={1, 1}};

14. Анонимные структуры

Последние версии языка С позволяют создавать анонимные (безымянные) структуры.
Эта возможность используется для случаев, когда членом структуры является структура и
создавать для нее специальный структурный тип нецелесообразно.
Пример. Программа демонстрирует использование анонимной структуры и
инициализацию членов структуры по именам.
struct person {
int id;
struct {char first[20]; char last[20];};
};
int main() {
struct person man = {.last = "Никитин", .id = 3452,
.first = "Афанасий"};
printf("%s\n", man.first);
printf("%s\n", man.last);
return 0;
}

15. Структуры и функции

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

16. Структуры и функции

struct point { int x, y; };
struct rect { struct point pt1, pt2; };
struct rect max_rect(struct rect *r, int n) {
struct rect rm = *r++;
for(int i = 1; i < n; i++, r++) {
if(r->pt1.x < rm.pt1.x) rm.pt1.x = r->pt1.x;
if(r->pt1.y < rm.pt1.y) rm.pt1.y = r->pt1.y;
if(r->pt2.x > rm.pt2.x) rm.pt2.x = r->pt2.x;
if(r->pt2.y > rm.pt2.y) rm.pt2.y = r->pt2.y;
}
return rm;
}
int main() {
struct rect rc[] = {{{1, 1}, {4, 5}},
{{2, 0}, {6, 6}},
{{3, 2}, {7, 4}}};
int n = sizeof(rc) / sizeof (*rc);
struct rect rcm = max_rect(rc, n);
printf("x1=%d, y1=%d, x2=%d, y2=%d\n",
rcm.pt1.x, rcm.pt1.y, rcm.pt2.x, rcm.pt2.y);
return 0;
}

17. Структуры и функции

Текст приведенной выше программы можно немного сократить и сделать более
«прозрачным», если воспользоваться возможностью создания синонимов для
«громоздких» типов с помощью оператора typedef (type definition). Приведем несколько
примеров применения typedef:

18. Структуры и функции

typedef struct {
structПример.
{int x, y;}
pt1, pt2; с синонимом типа.
Программа
} Rect;
Rect max_rect(Rect* r, int n) {
Rect rm = *r++;
for(int i = 1; i < n; i++, r++) {
if(r->pt1.x < rm.pt1.x) rm.pt1.x = r->pt1.x;
if(r->pt1.y < rm.pt1.y) rm.pt1.y = r->pt1.y;
if(r->pt2.x > rm.pt2.x) rm.pt2.x = r->pt2.x;
if(r->pt2.y > rm.pt2.y) rm.pt2.y = r->pt2.y;
} return rm;
}
int main() {
Rect rc[] = {{{1, 1}, {4, 5}},
{{2, 0}, {6, 6}},
{{3, 2}, {7, 4}}};
int n = sizeof(rc) / sizeof (*rc);
Rect rcm = max_rect(rc, n);
printf("x1=%d, y1=%d, x2=%d, y2=%d\n",
rcm.pt1.x, rcm.pt1.y, rcm.pt2.x, rcm.pt2.y);
return 0;
}

19. Структуры и функции

Пример. Программа вычисляет разницу между двумя временными периодами.
Определим сначала структуру и заголовок функции
#include <stdio.h>
struct TIME
{
int seconds;
int minutes;
int hours;
};
void differenceBetweenTimePeriod(struct TIME t1, struct TIME t2, struct TIME
*diff);

20. Структуры и функции

Пример. Программа вычисляет разницу между двумя временными периодами.
Опишем функцию
void differenceBetweenTimePeriod(struct TIME start, struct TIME stop, struct TIME
*diff)
{
if(stop.seconds > start.seconds){
--start.minutes;
start.seconds += 60;
}
diff->seconds = start.seconds - stop.seconds;
if(stop.minutes > start.minutes){
--start.hours;
start.minutes += 60;
}
diff->minutes = start.minutes - stop.minutes;
diff->hours = start.hours - stop.hours;
}

21. Структуры и функции

Пример. Программа вычисляет разницу между двумя временными периодами. Итог:
int main()
{
struct TIME startTime, stopTime, diff;
printf("Enter start time: \n");
printf("Enter hours, minutes and seconds respectively: ");
scanf("%d %d %d", &startTime.hours, &startTime.minutes, &startTime.seconds);
printf("Enter stop time: \n");
printf("Enter hours, minutes and seconds respectively: ");
scanf("%d %d %d", &stopTime.hours, &stopTime.minutes, &stopTime.seconds);
// Calculate the difference between the start and stop time period.
differenceBetweenTimePeriod(startTime, stopTime, &diff);
printf("\nTIME DIFFERENCE: %d:%d:%d - ", startTime.hours, startTime.minutes,
startTime.seconds);
printf("%d:%d:%d ", stopTime.hours, stopTime.minutes, stopTime.seconds);
printf("= %d:%d:%d\n", diff.hours, diff.minutes, diff.seconds);
return 0;
}

22. Структуры и функции

В результате выполнения полeчим:
Enter start time:
Enter hours, minutes and seconds respectively: 12
34
55
Enter stop time:
Enter hours, minutes and seconds respectively:8
12
15
TIME DIFFERENCE: 12:34:55 - 8:12:15 = 4:22:40

23. Структуры и функции

Пример. Хранение данных об оценках по определенным предметам:
#include <stdio.h>
#include<stdlib.h>
struct course
{
int marks;
char subject[30];
};

24. Структуры и функции

Продолжение
int main()
{
struct course *ptr;
int i, noOfRecords;
printf("Enter number of records: ");
scanf("%d", &noOfRecords);
// Allocates the memory for noOfRecords structures with pointer ptr pointing to
the base address.
ptr = (struct course*) malloc (noOfRecords * sizeof(struct course));
for(i = 0; i < noOfRecords; ++i)
{
printf("Enter name of the subject and marks respectively:\n");
scanf("%s %d", &(ptr+i)->subject, &(ptr+i)->marks);
}
printf("Displaying Information:\n");
for(i = 0; i < noOfRecords ; ++i)
printf("%s\t%d\n", (ptr+i)->subject, (ptr+i)->marks);
return 0;
}

25. Объединения

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

26. Объединения

Пример. Размер объединения u равен размеру его самого большого поля ldval.
int main() {
union {
int ival;
long double ldval;
char *sval;
} u;
printf("Size of u = %d \n", sizeof(u));
return 0;
}

27. Объединения

Пример. Размер объединения p больше размера его самого большого поля c[5] из-за
необходимости выравнивания на границу, кратную размеру поля f типа float:
int main() {
union {
char c[5]; // 5 байт
float f; // 4 байта
} p = {.f = 1.23};
printf("Размер объединения p = %zu\n", sizeof p);
return 0;
}

28. Объединения

Пример. Размер объединения p больше размера его самого большого поля c[5] из-за
необходимости выравнивания на границу, кратную размеру поля f типа float:
int main() {
union {
char c[5]; // 5 байт
float f; // 4 байта
} p = {.f = 1.23};
printf("Размер объединения p = %zu\n", sizeof p);
return 0;
}

29. The end

Спасибо за внимание !
English     Русский Правила