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

Visual_Studio_2010

.pdf
Скачиваний:
109
Добавлен:
03.03.2016
Размер:
5.94 Mб
Скачать

i = 1;

while ( !feof(fid)) { // пока не конец файла

// Вывод на консоль

printf("\n %3d\t\t\t %-17s %0.2f", number, name, sum);

// Запись в файл data77.dat

fprintf(fid2," %3d) %3d\t\t\t %-17s %0.2f\r\n",i++,number,name, sum);

// Чтение из файла data7.dat

fscanf_s(fid, "%d%s%Lf", &number, name, MAX, &sum);

}

fclose(fid);

fclose(fid2);

printf("\n\n\n Result see the files, \"%s\" and \"%s\"\n", file, file2);

printf("\n Press any key: ");

_getch(); return 0;

}

В программе использована функция feof(), которая проверяет, достигнут ли конец файла, связанного с потоком (указателем на файл) fid.

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

Рис.12.11. Консольный вывод содержимого файла

Следует обратить внимание на прекращение ввода данных с клавиатуры с помощью комбинации клавиш Ctrl+Z.

Задание7

1. Вместо оператора цикла while примените оператор цикла for.

211

2.Отсортируйте записи владельцев ячеек по убыванию величины суммарной денежной суммы.

3.Подготовьте форматированный текстовый файл с именем compX, где Х – номер компьютера, на котором выполняется лабораторная работа. Затем информацию из файла выведите на консоль.

Пример 8. Написать программу пакетной записи в файл произвольного доступа массива данных и вывода этого пакета на консоль.

При решении примера применим функции fwrite() и fread() для бинарной записи и считывания информации.

Программный код решения примера

#include <stdio.h> #include <conio.h>

#define MAX 20

#define n 5 #define m 4

#define file "D:\\data8.txt"

int main(void)

{

//Матрица 5х4

int mass[MAX][MAX] = {

{1,2,3,4}, {5,6,7,8}, {9,10,11,12}, {13,14,15,16}, {17,18,19,20} };

int mass2[MAX][MAX]; // вспомогательная матрица int i, j;

// Массив из 5 указателей char *str[] = {

"Brian W. Kernighan",

"Dennis M. Ritchie", "Stephen Prata", "Herbert Shildt",

"The C Programming Language"

};

char *str2[n]; // вспомогательный массив указателей

FILE *fid;

if ( fopen_s(&fid, file, "wb") ) { fprintf(stdout, "\n\t File could not be opened\n"); printf("\n Error! Press any key: ");

_getch(); return -1; }

fwrite(str, sizeof(char), sizeof(str)/sizeof(char), fid); fwrite(mass, sizeof(int), sizeof(mass)/sizeof(int), fid);

fclose (fid);

212

if ( fopen_s(&fid, file, "rb") )

{

fprintf(stdout, "\n\t File could not be opened\n"); printf("\n Press any key: ");

_getch(); return -1;

}

fread(str2, sizeof(char), sizeof(str)/sizeof(char), fid); fread(mass2, sizeof(int), sizeof(mass2)/sizeof(int), fid);

// Чтение элементов из файла

printf("\n\t From a file \"%s\": \n\n", file); for (i = 0; i < n; ++i)

printf("\t %-15s\n", str2[i]);

printf("\n\t Matrix from a file \"%s\":\n", file); for (i = 0; i < n; ++i)

{

printf("\n\t");

for (j = 0; j < m; ++j) printf(" %3d", mass2[i][j]);

}

fclose(fid);

printf("\n\n\n Press any key: "); _getch();

return 0;

}

Функция fwrite()записывает в файл заданное количество байт из буфера памяти, адрес которого передан ей в качестве параметра. Это происходит с того места в файле, которое обозначено указателем позиции файла. Функция fread()считывает заданное количество байт, начиная с текущей позиции файла в буфер памяти, адрес которого передан ей в качестве параметра.

В программе пакетная запись информации – набора строк и матрицы целых чисел производится через двоичный поток с помощью функций fwrite(). Чтение информации из двоичного файла осуществляется функцией fread(). Форматы записи обеих функций одинаковы, так как в них требуется установить количество объектов с заданным размером байт, которые определяются функцией sizeof().

Результат выполнения программы представлен на рис.12.12 и 12.13.

213

Рис. 12.12. Результат чтения из файла бинарной информации

Рис.12.13. Результат записи в текстовый файл бинарной информации

Как видно из рис. 12.12 и 12.13, информация на консоли соответствует исходной информации, а в двоичном файле она не подлежит непосредственному восприятию.

П р и м е ч а н и е . Вид бинарной информации в текстовом файле зависит от установленных шрифтов.

Задание8

1.Запишите двоичную информацию в файлы с расширением .dat, .doc,

.bin. Проанализируйте файлы после их открытия.

2.Вместо массива указателей примените двухмерный символьный массив необходимой размерности.

3.Вместо массива указателей примените схему с двухуровневой адресацией.

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

5.Перезапишите информацию из двоичного файла в текстовый файл с именем compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.

214

Контрольные вопросы

1.Что может быть файлом в языке С?

2.Какие обязательные операции выполняются при нормальной работе с файлами? Какие библиотечные функции при этом используются?

3.Как определяется текстовый поток в стандарте языка С?

4.Как определяется двоичный поток в стандарте языка С?

5.Что представляет собой указатель файла?

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

7.Какая переменная стандартной библиотеки используется для определения стандартного потока вывода на дисплей?

8.Какая переменная стандартной библиотеки используется для определения стандартного потока чтения с дисплея?

9.Как в языке С кодируется признак конца файла?

10.Как в языке С кодируется признак конца строки?

11.Что такое файл произвольного доступа?

12.Как в языке С осуществляется пакетная запись данных в файл?

13.Как осуществляется запись бинарной информации в текстовый файл?

14.Как осуществляется чтение бинарной информации из текстового файла?

БИБЛИОГРАФИЧЕСКИЙ СПИСОК

1.Демидович Е. М. Основы алгоритмизации и программирования. Язык Си : учеб. пособие/Е. М. Демидович. – 2-е изд., испр. и доп. – СПб. : БХВ-

Петербург, 2008. – 440 с.

2.Шилдт Г. Полный справочник по С : пер. с англ./Г. Шилдт. – 4-е изд. –

М. : Вильямс, 2007. – 704 с.

3.Керниган Б. У. Язык программирования С : пер. с англ./Б. У. Керниган, Д. М. Ритчи. – 2-е изд. – М. : Вильямс, 2007. – 304 с.

4.Прата С. Язык программирования С. Лекции и упражнения : пер. с англ. / С. Прата. – 5-е изд. – М. : Вильямс, 2006. – 960 с.

215

Тема 13

СТРУКТУРЫ – ПРОИЗВОДНЫЕ ТИПЫ ДАННЫХ ЯЗЫКА С

Рассматриваются вопросы создания и использования структур в языке программирования С.

ТЕОРЕТИЧЕСКАЯ ЧАСТЬ

Структура – это совокупность нескольких переменных, часто различных типов [1], объединяемых под одним именем. Переменные, из которых состоит структура, называются ее членами, элементами или полями [2]. С помощью структур удобно размещать в смежных полях связанные между собой элементы информации. Здесь могут быть собраны различные объекты – переменные, массивы, указатели, другие структуры и т. д. Если в массиве представлены переменные одного типа (например, float), то в структуре могут наличествовать переменные различных типов. Объявление структуры подготавливает шаблон, который можно использовать для создания ее объектов (экземпляров этой структуры) [2]. При объявлении структуры определяется агрегатный тип данных, но не переменная.

Определение структуры состоит из двух шагов:

1)объявление шаблона структуры (задание нового типа данных);

2)определение переменных типа объявленного шаблона [3].

Имена шаблонов должны быть уникальными в пределах области их определения, для того чтобы компилятор мог различать их типы. Задание шаблона осуществляется с помощью ключевого слова struct, за которым следуют его имя и список элементов, заключенных в фигурные скобки [3]. Имена элементов в одном шаблоне также должны быть уникальными. Задание только шаблона не влечет резервирования памяти компилятором. Шаблон предоставляет компилятору необходимую информацию об элементах структурной переменной для выделения места в оперативной памяти и организации доступа к ней при определении структурной переменной и использовании ее отдельных элементов [3].

Рассмотрим шаблон структуры для определения имени и фамилии работника (служащего – employee), его возраста, почасовой оплаты:

struct employee {

 

char Name [21];

// имя

char Surname [21];

// фамилия

int age;

// возраст

double hourlysalary;

// почасовой оклад

};

 

Как видно, шаблон структуры struct employee состоит из символьных массивов типа char, целого числа типа int и числа с плавающей точкой двойной точности типа double. Описание элементов производится в фигурных скобках, после закрывающей скобки обязательна точка с запятой.

216

Определение структуры начинается с ключевого слова struct. Иденти-

фикатор employee является именем-этикеткой (tag name), дескриптором,

именует структуру и используется совместно с ключевым словом struct для объявления переменных структурного типа [4].

Переменные структуры объявляются так же, как и переменные других типов. На основе приведенного шаблона сделаем несколько объявлений новых структурных переменных:

struct employee new_ employee, * employeePtr, stack[120];

Здесь new_employee – переменная типа struct employee, *employeePtr – указатель на struct employee, stack[120] – массив из 120 элементов типа struct employee.

Переменные new_employee, *employeePtr, stack[102] могут быть объединены с определением структуры, а именно:

struct employee {

 

 

char Name [20+1];

// имя

char Surname [20+1];

// фамилия

int age;

//

возраст

double hourlysalary;

//

почасовой оклад

}new_employee, *employeePtr, stack[120];

Имя-этикетка не является для структуры обязательным. Если определение структуры не содержит его, то переменные для этой структуры могут быть объявлены только в ее определении, но не отдельно [1].

При создании структур часто используется ключевое слово typedef (оператор). Оно предоставляет программисту средство создания синонимов (или псевдонимов) для ранее определенных типов данных. К нему часто обращаются для того, чтобы дать укороченное имя структурному типу [4]. Например, оператор вида

typedef struct card Card;

определяет новый тип с именем Card как синоним типа struct card. Ключевое слово typedef может быть использовано в определении типа

структуры без имени-этикетки. Например,

typedef struct

{

char *Name;

// имя

char *Surname;

// фамилия

int age;

// возраст

double hourlysalary; // почасовой оклад

}Man;

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

Созданный тип Man можно использовать для объявления структурных переменных типа struct employee, например

Man stack[120];

П р и м е ч а н и е . Использование typedef помогает сделать программу более переносимой.

217

Синтаксис инициализации структур аналогичен инициализации массивов. Например, выполним инициализацию структуры:

struct employee {

 

char Name [20+1];

// имя

char Surname [20+1];

// фамилия

int age;

// возраст

double hourlysalary;

// почасовой оклад

}

new_employee;

 

Возможный вариант инициализации:

struct employee {

 

char Name [20];

// имя

char Surname [20];

// фамилия

int age;

// возраст

double hourlysalary;

// почасовой оклад

}new_employee = { "Peter", "Smith", 25, 6.78 };

При инициализации структуры ее элементы (инициализаторы) должны соответствовать заданному типу и отделяться друг от друга запятыми.

Доступ к элементам (компонентам, полям) структуры осуществляется двумя способами:

1)с помощью оператора связывающей точки (оператора точки) . при непосредственной работе со структурой;

2)с помощью стрелки –> при использовании указателей на структуры.

Общий формат доступа к элементам структуры имеет вид

имя_переменной_структуры . имя_поля;

имя_указателя_на_структуру –> имя_поля; (*имя_указателя_на_структуру) . имя_поля;

Например, для рассмотренной инициализации можно изменить почасовой оклад с помощью оператора точки и указателя на структуру:

new_employee.hourlysalary = 21.0; employeePtr –> hourlysalary = 21.0;

Следует обратить внимание на то, что new_employee – это имя всего объекта-структуры, а hourlysalary – имя элемента этой структуры. Аналогично и в случае использования указателя *employeePtr на структуру.

При изменении полей структуры следует обратить внимание на случай со строками, например:

strcpy(new_employee . name, "Stephen");

При этом должен быть предусмотрен заголовочный файл <string.h>. для функции strcpy().

Когда объявлен массив структур, например stack[120], это означает, что создано 120 наборов переменных, каждый из которых организован так, как определено в структуре с дескриптором employee. Чтобы получить доступ к определенной структуре stack[120], следует указать имя массива с индексом, который изменяется от 0 до 119. Например, для пятой структуры можно сделать изменения в почасовом окладе:

218

stack[4].hourlysalary = 121.5;

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

ется вложенной [2].

Рассмотрим пример:

struct X = { int A[7][8]; float b; char ch;

struct employee Emp2; } Y;

Инициализация элементов двухмерного массива А может быть такой:

Y.A[2][5] = 99;

Инициализация вложенной структуры может быть следующей:

Y.Emp2.hourlysalary = 12.75;

В соответствии со стандартом С89 структуры могут быть вложенными вплоть до 15-го уровня, стандарт С99 допускает уровень вложенности до 63-го включительно [2].

ПРАКТИЧЕСКАЯ ЧАСТЬ

Пример 1. Написать программу структурного описания каталога одной книги. Программный код решения примера

#include <stdio.h>

 

#include <conio.h>

 

#include <string.h>

 

#define

N 40

 

struct

book { // определение структуры

char title[N+1];

// название книги

char author[N+1];

// автор

int year;

// год издания

 

 

int page;

// количество страниц

float price;

// цена в у.е.

} Library;

 

 

 

 

int main (void)

{

// Инициализация полей структуры

Library.year = 2007;

Library.page = 496;

Library.price = 12.78F;

strcpy_s(Library.title, N, "Programming in C"); strcpy_s(Library.author, N, "Stephen G. Kochan");

219

// Вывод на консоль

printf("\n\t Title: %s\n", Library.title); printf("\t Author: %s\n", Library.author); printf("\t Year: %d\n", Library.year );

printf("\t Number of pages: %d p.\n", Library.page ); printf("\t Price: %1.2f y.e.\n", Library.price);

printf("\n\n Press any key: "); _getch();

return 0;

}

В программе использованы функции strcpy_s() вместо стандартных функций strcpy(), что позволило избавиться от предупреждений в системе

Visual Studio 2010.

Результат выполнения программы показан на рис.13.1.

Рис. 13.1. Пример инициализированных полей структуры

Задание1

1.Совместите объявление и инициализацию структуры. После инициализации структуры выполните изменение ее полей с последующим выводом на консоль.

2.Примените оператор typedef.

3.Поля структуры title и author определите с помощью указателей.

4.Произведите инициализацию структуры после ввода значений полей с клавиатуры.

5.Выполните вывод полей структуры в текстовый файл compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.

Пример 2. Написать программу анализа средней успеваемости четырех студентов по четырем предметам за сессию на основе структурного типа данных.

Программный код решения примера

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

#define N 4 // число студентов

#define CH 30 // число символов для фамилии или имени

220

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