Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лаб. практикум

.pdf
Скачиваний:
89
Добавлен:
12.03.2015
Размер:
658.95 Кб
Скачать

81

несортированными. Внутренние таблицы (создаваемые в оперативной памяти) могут храниться в виде вектора или в виде списка.

Пример решения задачи

Задача. Входной файл st.txt содержит сведения о сдаче студентами группы экзаменационной сессии. Каждая запись файла содержит фамилию и инициалы студента (15 символов) и пять оценок (5 символов) и завершается символом ” перевод строки”. Количество записей не более 30. Вывести:

-фамилии всех студентов с указанием среднего балла каждого студента;

-информацию о заданном студенте.

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

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

-------------------------------------------------------

Выберите номер пункта меню: 1 - средние баллы студентов

2 - информация о заданном студенте

3 - выход

-------------------------------------------------------

При выборе пункта 3 выполнение программы завершается.

/* Программа 9.1 на языке С++ */

#include <stdio.h> #include <conio.h> #include <string.h> #define MAX 30

// тип записи файла struct STUDENT

 

 

 

82

{

char

fio[15];

// фамилии и.о.

};

char

oc[7];

// 5 оценок + '\n' + '\0'

// тип элемента таблицы

 

struct EL_TAB

 

{

char

fio[15];

// фамилия и.о.

 

int oc[5];

// оценки

};

float

srball;

// средний балл

 

 

 

// прототипы функций void PechTab (EL_TAB * tab, int n); void Stud (EL_TAB * tab, int n);

/*

----------------------------*/

/*

главная функция */

/*----------------------------

*/

void main()

 

 

 

{ FILE *f;

// указатель на входной файл

STUDENT tz;

// текущая запись файла

EL_TAB tab[MAX];

// таблица

int

n;

// длина таблицы

int

i;

 

 

 

float

s;

// сумма оценок

 

if ((f= fopen("st.txt","r")) == NULL) { puts ("Файл st.txt не найден");

return;

}

// создание таблицы n = 0;

while (fgets((char *)&tz, sizeof(struct STUDENT), f) != NULL)

{for (i=0,s=0; i<5; i++)

{int ocenka = tz.oc[i]-'0'; tab[n].oc[i] = ocenka;

s += ocenka;

}

tz.fio[14]='\0';

strcpy(tab[n].fio,tz.fio); tab[n++].srball = s/5;

}

fclose(f);

char nom; // номер пункта меню do

{clrscr();

puts ("------------------------------------------------------");

 

83

puts ("

Выберите номер пункта меню:");

puts ("1

- средние баллы студентов");

puts ("2

- информация о заданном студенте");

puts ("3

- выход");

puts ("-------------------------------------------------------

");

nom = getche(); switch (nom)

{case '1': PechTab(tab,n); break; case '2': Stud(tab,n); break; case '3': break;

default: puts ("\nНужно ввести номер от 1 до 3");

}

if (nom != '3')

{puts("\nДля продолжения нажмите любую клавишу"); getch();

}

}

while (nom != '3');

}

/*

-----------------------------------------------------------------*/

/*

Печать среднего балла каждого студента */

/*-----------------------------------------------------------------

*/

void PechTab (EL_TAB * tab, int n)

{int j;

puts ("\nФамилия и.о. Ср.балл");

puts ("------------------------------

");

for (j=0; j<n; j++)

 

{

 

printf("%s %.1f\n", tab[j].fio, tab[j].srball);

}

}

// заглушка для функции вывода информации о студенте void Stud (EL_TAB * tab, int n)

{

}

Контрольные вопросы и упражнения

1.Что такое таблица?

2.Какая таблица называется линейной или последовательной?

3.Какие операции над таблицами выполняются в программе 9.1?

84

4. Как описать таблицу, содержащую название месяца и количество дней в каждом из 12 месяцев года?

5.Опишите таблицу из n элементов ( n ≤ 50). Каждый элемент состоит из 4-х полей, описывающих анкетные данные спортсмена:

-фамилия, имя и отчество;

-год рождения;

-рост в метрах (например, 1.85);

-вес в кг.

6.Опишите таблицу из n элементов ( n <=100), каждый элемент которой содержит следующие поля:

-№ поезда (целое число);

-пункт назначения (строка из 30 символов);

-время отправления (строка из 6 символов).

Задания

5.Ознакомьтесь с теоретическим материалом и примером решения задачи. Ответьте на контрольные вопросы.

6.Введите и выполните программу 9.1. Создайте файл st.txt для проверки программы и снова запустите программу.

7.Вместо заглушки функции Stud напишите функцию, которая запрашивает фамилию студента, выполняет линейный поиск элемента с заданной фамилией в таблице и выводит значение найденного элемента или сообщение об ошибке, если такой фамилии нет в таблице.

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

9.Добавьте подпрограмму вывода:

а) отличников группы; б) студентов со средним баллом не ниже 4;

в) студентов, имеющих двойки.

85

Л а б о р а т о р н а я р а б о т а N 10

Организация списков с помощью указателей и структур

Список - это последовательность элементов, в

которой

каждый

элемент

содержит ссылку на

следующий элемент.

Последний

элемент

содержит

нулевую (пустую)

ссылку. Доступ к списку обеспечивается с

помощью

указателя списка,

ссылающегося на первый элемент списка.

Таким образом, каждый элемент списка состоит из двух полей - поля информации и поля ссылки (рис. 10.1).

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

/

 

 

/

 

\

...

/

 

Указатель

 

поле

поле

 

 

 

 

пустая

списка

информации

ссылки

 

 

 

ссылка

Рис. 10.1. Cписок

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

Рассмотрим организацию списков с помощью указателей и структур. Допустим, программа создает список идентификаторов. Тогда в программе следует описать тип элемента списка в виде структуры из двух полей и указатель списка. Указатель списка и поле ссылки на следующий элемент описываются как переменные типа указатель на структуру. Например:

/* описание списка идентификаторов */

struct

EL_SP

// тип элемента списка

{ char

id [9];

 

// идентификатор

struct EL_SP *sled;

// ссылка на следующий элемент

};

 

 

 

struct

EL_SP

*p;

// указатель списка

Обратите внимание: EL_SP - это не переменная, а имя типа структуры, память для элемента списка здесь не выделяется.

Чтобы выделить память для очередного элемента списка, нужно

86

вызвать функцию malloc(). Аргументом этой функции является размер памяти в байтах, а возвращает она адрес выделенного участка памяти (при использовании этой функции нужно включать файл stdlib.h). Например, оператор присваивания

p = (struct EL_SP *)malloc (sizeof(struct EL_SP));

выделяет память для первого элемента списка и устанавливает указатель p. Операция sizeof (srtuct EL_SP) определяет размер памяти в байтах для структуры типа EL_SP. Функция malloc() выделяет требуемый объем памяти и возвращает адрес этого блока памяти, который присваивается

указателю p.

 

 

 

 

 

Освобождение памяти

при

удалении

элемента

из списка

осуществляется функцией

free(), где аргументом должен быть указатель на

элемент списка, например,

free (p).

 

 

 

При программировании на языке С++ лучше использовать

специальные операторы распределения памяти new

и delete. Оператор new

выделяет память, а delete

освобождает. Например:

 

 

EL_SP * i;

// указатель на новый элемент списка

 

i = new EL_SP; // выделение памяти для нового элемента

 

 

 

 

 

 

 

delete i;

// освобождение памяти, занимаемой элементом списка

Доступ к отдельным

полям

структуры,

на которую

ссылается

указатель, осуществляется с помощью операции ->. Например, для приведенного выше списка идентификаторов

p -> id -

это поле

id (идентификатор)

1-го элемента списка,

p ->sled -

это поле

sled 1-го элемента

или адрес 2-го эл-та списка.

Пустая ссылка обозначается константой NULL. Например, оператор p = NULL;

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

87

Пример решения задачи

Задача. Дана последовательность из n идентификаторов. Длина каждого идентификатора не более 8 символов. Напечатать идентификаторы в лексикографическом порядке.

Пример теста:

n=7

Исх.посл-ть:

Результат:

SIMV

A

X

A1

A1

SIMV

SL

SL

Z20

TEXT

A

X

TEXT

Z20

Метод решения. Задачу можно решить, сцепляя идентификаторы

всписок в лексикографическом порядке по мере их ввода. В

приведенной

ниже

программе

после

чтения

очередного

идентификатора

сразу

происходит

добавление его

в список,

сформированный из предшествующих идентификаторов. На рис. 10.2 показано, как изменяется список в процессе включения в него очередных идентификаторов.

Еще несколько пояснений к программе. Идентификаторы поочередно вводятся в массив t_id с помощью функции gets(). Сравнение двух идентификаторов производится с помощью функции strcmp(), которая возвращает значение 0, если идентификаторы равны, и разность кодов двух соответствующих несовпавших символов, если идентификаторы не равны. Значит, значение функции будет < 0, если первый идентификатор в лексикографическом порядке должен следовать раньше второго, и значение будет > 0 в противном случае.

 

 

 

 

 

 

 

 

 

88

 

 

 

 

P

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SIMV

0

 

 

 

 

 

 

 

 

 

P

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SIMV

 

 

X

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

P

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A1

 

 

SIMV

 

 

X

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

P

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A1

 

 

 

SIMV

 

 

SL

 

 

X

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

. . .

P

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

A

 

 

A1

 

 

SIMV

 

 

SL

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

X

 

 

Z20

0

TEXT

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рис. 10.2. Пример процесса формирования списка идентификаторов

Функция strcpy() служит для копирования строк символов, имеет два аргумента: указатель на строку, куда копировать, и указатель на строку, откуда копировать.

/* Программа 10.1. (язык С) */

 

#include <stdio.h>

 

 

#include <stdlib.h>

 

 

#include <string.h>

 

 

#include <conio.h>

 

 

#define MAXDL 9

/* макс.длина ид-ра (строки символов с

 

признаком конца '\0' )

*/

struct EL_SP

/* тип элемента списка */

 

{ char id [MAXDL];

/* идентификатор */

 

struct EL_SP *sled;

/* ссылка на следующий элемент */

};

 

 

 

89

/*----------------------------------------------------------------------------------------

*/

/*

функция включения очередного идентификатора в список */

/*----------------------------------------------------------------------------------------

*/

void Vkl ( struct EL_SP **p, char t_id[] )

 

/* Вх. данные: *p

- указатель списка идентификаторов в

 

лексикографическом порядке,

t_id - включаемый в список (текущий) ид-р */

/* Вых. данные: *p

*/

 

{ struct EL_SP *pt,

/* указатель включаемого эл-та */

*k,*j;

/* указатели очередного и предыдущего

 

элементов списка

*/

/* выделение памяти для нового эл-та списка */ pt = (struct EL_SP *) malloc(sizeof(struct EL_SP)); strcpy(pt->id, t_id);

if (*p==NULL || strcmp(pt->id,(*p)->id) < 0) { /* включение ид-ра в начало списка */

pt->sled=*p; *p=pt;

}

else

{ /* поиск элемента списка, после которого нужно включить идентификатор */

k=*p;

while (k!=NULL && strcmp(pt->id,k->id)>=0) { j=k; k=k->sled;

}

/* включение эл-та *pt после элемента *j */ j->sled=pt; pt->sled=k;

}

}

 

 

/*-----------------------------------------------------------------

 

*/

/*

функция печати списка

*/

/*-----------------------------------------------------------------

 

*/

void PechSp ( struct EL_SP *p )

 

/*

Вх. данные: p - указатель начала списка

*/

{struct EL_SP *i; /* указатель текущего элемента списка */ printf ("\nРезультат:\n");

for ( i=p; i!=NULL; i=i->sled ) puts (i->id);

}

 

 

90

 

 

/*--------------------------------------------------------------

 

 

*/

 

/* О С Н О В Н А Я П Р О Г Р А М М А */

 

/*-------------------------------------------------------------

 

 

*/

 

main()

 

 

 

 

{ struct EL_SP *p;

/* указатель начала списка

*/

unsigned

n ;

/* количество идентификаторов */

unsigned

i ;

/* параметр цикла

*/

 

char t_id[MAXDL];

/* текущий идентификатор

*/

printf ("\nВведите число идентификаторов\n n=");

scanf ("%u",&n);

 

 

 

getchar();

/* пропуск символа "перевод строки" */

p=NULL;

/* список пока пуст */

 

 

printf ("Введите идентификаторы ");

 

 

printf ("(после каждого нажимайте клавишу <Enter> )\n"); for ( i=1; i<=n; i++ )

{ gets (t_id);

Vkl (&p,t_id);

/* включение ид-ра в список */

}

 

PechSp (p);

/* печать списка */

printf ("\n\nДля завершения нажмите любую клавишу\n"); getch();

}

Контрольные вопросы и упражнения

1.Приведите пример исходных данных для программы 10.1 и нарисуйте список, который сформирует программа.

2.Где в программе происходит формирование списка?

3.Почему функции Vkl() передается адрес указателя списка p, а

функции PechSp() – значение указателя p?

4. В функции Vkl() параметр p какого типа?

5.Как в функции Vkl() происходит обращение к указателю списка?

6.Изменится ли указатель списка p в главной программе, если функцию печати списка изменить следующим образом:

void PechSp ( struct EL_SP *p )

{

printf ("\nРезультат:\n");

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]