Основы C++

Основы алгоритмизации, компиляторы и интерпретаторы. Основные понятия языка программирования Си и структура программы. Базовые конструкции структурного программирования. Символьная информация и строки и динамическое выделение памяти. Работа с файлами.

Рубрика Программирование, компьютеры и кибернетика
Вид лабораторная работа
Язык русский
Дата добавления 11.02.2015
Размер файла 189,9 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

// из 100 элементов

delete b; //освободили в памяти место из-под массива b

4.6 Многомерные массивы

Многомерный массив - это массив, элементами которого служат массивы. Например, массив с описанием int a[4][5] - это массив из 4 указателей типа int*, которые содержат адреса одномерных массивов из 5 целых элементов.

int **a;

Инициализация многомерных массивов выполняется аналогично одномерным массивам. Примеры:

int a[3][4] = {{11,22,33,44},{55,66,77,88},{99,110,120,130}};

//проинициализированы все элементы массива

int b[3][4] = {{1},{2},{3}};

//проинициализированы первые элементы каждой строки

int c[3][2]={1,2,3,4,5,6};

//проинициализированы все элементы массива

Доступ к элементам многомерных массивов возможен и с помощью индексированных переменных и с помощью указателей:

a[1][1] - доступ с помощью индексированных переменных,

*(*(a+1)+1) - доступ к этому же элементу с помощью указателей.

Лабораторная работа 2.

Одномерные массивы

Вариант 1

1. Дана последовательность чисел а1, а2, ... а10. Вычислить, сколько чисел в этой последовательности стоит после 2-го нуля.

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

Вариант 2

1. Дана последовательность чисел а1, а2, ... а10. Вычислить, сколько в этой последовательности стоит чисел до 3-го нуля.

2. Задать произвольную последовательность целых чисел. Вычислить сумму всех отрицательных чисел.

Вариант 3

1. Дана последовательность чисел а1, а2, ... а10. Вычислить, сколько в этой последовательности стоит чисел между 1-м и 3-м нулями.

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

Вариант 4

1. Дана последовательность чисел а1, а2, ... а10. Вычислить, сколько в этой последовательности чисел стоит после 3-го нуля.

2. Задать произвольную последовательность целых чисел. Вычислить, сколько в этой последовательности положительных чисел, имеющих значение < +10.

Вариант 5

1. Дана последовательность чисел а1, а2, ... а10. Вычислить, сколько в этой последовательности чисел стоит между 2-м и 3-м нулями.

2. Задать произвольную последовательность целых чисел. Вычислить сумму всех положительных чисел.

Вариант 6

1. Дана последовательность чисел а1, а2, ... а10. Вычислить, сколько положительных чисел в этой последовательности стоит после 1-го нуля.

2. Задать произвольную последовательность целых чисел. Вычислить сумму всех положительных чисел.

Вариант 7

1. Дана последовательность чисел а1, а2, ... а10. Вычислить, сколько отрицательных чисел в этой последовательности стоит после 2-го нуля.

2. Задать произвольную последовательность целых чисел. Вычислить, сколько в этой последовательности положительных чисел, имеющих значение, меньшее +5.

Вариант 8

1. Дана последовательность чисел а1, а2, ... а10. Вычислить, сколько в этой последовательности стоит положительных чисел между 1-м и 3-м нулями.

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

Пример

1. Дана последовательность чисел а1, а2, ... а10. Вычислить, сколько чисел в этой последовательности стоит после 1-го нуля.

# include <iostream.h>

# include <conio.h>

void main(void)

{ float a[10];

int i=0, j;

clrscr();

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

{cout<<"a["<<j<<"]=";

cin>>a[j];}

while ((a[i]!=0) && (i<9)) i++;

if (a[i]==0) cout<<9-i;

else cout<<"в последовательности нет нулей";

getche();

}

2. Задать произвольную последовательность целых чисел. Вычислить, сколько чисел в этой последовательности имеют значения от -10 до +10.

# include <iostream.h>

# include <conio.h>

void main(void)

{ int *p, size, i, s=0;

clrscr();

cout<<"Введите размер массива: ";

cin>>size;

p=new int[size];

if (!p) cout<<"Недостаточно памяти";

else

{for (i=0; i<size; i++)

{cout<<"p["<<i<<"]=";

cin>>p[i];

if ((p[i]>=-10) && (p[i]<=10)) s++;}

cout<<s;}

getche();}

Лабораторная работа 3.

Двумерные массивы

Вариант 1

1. Заполнить матрицу произведениями соответствующих порядковых номеров ее элементов.

2. Найти разность между суммами элементов, лежащих на главной и побочной диагоналях матрицы М (3x3).

Вариант 2

1. Из матрицы Q (4x3) сформировать одномерный массив отрицательных чисел (просмотр по строкам).

2. Дана матрица А (4x4). Расставить строки таким образом, чтобы элементы в первом столбце были упорядочены по убыванию.

Вариант 3

1. Дан целочисленный массив В (3x5). Определить, сколько в нем пар соседних одинаковых элементов. Элементы считаются соседними, если их индексы в столбцах и/или в строках различаются не более, чем на единицу.

2. Определить среднее арифметическое значение элементов матрицы А (3x3), лежащих на главной диагонали.

Вариант 4

1. Дана вещественная матрица М (5x4). Преобразовать матрицу: поэлементно вычесть последнюю строку из всех строк, кроме последней.

2. Дана целочисленная матрица В (5x3). Найти номера столбцов, элементы каждого из которых образуют возрастающую последовательность

Вариант 5

1. Дана вещественная матрица А (4x3). Преобразовать матрицу: поэлементно вычесть последнюю строку из всех столбцов, кроме последнего.

2. В данной целочисленной квадратной матрице размера n х n(n - некоторая константа) указать индексы всех элементов, имеющих наибольшее значение.

Вариант 6

1. Транспонированием квадратной матрицы называется такое ее преобразование, при котором строки и столбцы меняются ролями. Дана квадратная матрица размера n х n. Получить транспонированную матрицу.

2. Вычислить сумму элементов матрицы М (5x5), лежащих справа от побочной диагонали.

Вариант 7

1. Определить, является ли данная квадратная матрица симметричной относительно своей главной диагонали.

2. Последний отрицательный элемент каждого столбца матрицы заменить нулем.

Вариант 8

1. Найти количество элементов в каждой строке матрицы А (4х5), больших среднего арифметического элементов данной строки.

2. В каждом столбце матрицы В (5х4) сменить знак максимального по модулю элемента на противоположный.

Пример

1. Вычислить сумму элементов матрицы М (3x3), лежащих справа от главной диагонали.

# include <iostream.h>

# include <conio.h>

void main(void)

{ float a[3][3];

int i,j;

float s=0;

clrscr();

for (i=0; i<=2; i++)

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

{cout<<"a["<<i<<"]["<<j<<"]=";

cin>>a[i][j];

if (j>i) s+=a[i][j];}

cout<<s;

getche();

}

2. Подсчитать число элементов матрицы Q (3x4), кратных трем.

# include <iostream.h>

# include <conio.h>

void main(void)

{ int a[3][4];

int i,j;

int s=0;

clrscr();

for (i=0; i<=2; i++)

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

{cout<<"a["<<i<<"]["<<j<<"]=";

cin>>a[i][j];

if ((a[i][j]%3)==0) s++;}

cout<<s;

getche(); }

Лабораторная работа 4. Строки

1. Задан массив строк, содержащих фамилию, имя и отчество через пробел. Создать три массива, содержащих отдельно фамилию, имя и отчество.

2. Задана строка. Определить, каких букв больше, гласных или согласных.

3. Заданы массив строк, содержащих фамилии студентов, и массив полученных ими оценок. Определить, какие студенты имеют оценку больше среднего балла, и сколько их.

4. Заданы массив строк, содержащих фамилии студентов, и массив полученных ими оценок. Отсортировать студентов от самого успевающего к самому неуспевающему.

5. Определить, является ли слово палиндромом (читается ли оно слева направо и справа налево одинаково. Например, слово "шалаш" - палиндром).

6. Задан массив строк. Записать каждую строку наоборот.

7. Задан массив строк. Проверить, все ли строки начинаются с согласных букв.

8. Задан массив строк. Проверить, все ли строки заканчиваются гласными буквами.

Пример

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

# include <iostream.h>

# include <conio.h>

# include <string.h>

# include <stdio.h>

void main(void)

{ char str[80], lat[]="qwertyuiopasdfghjklzxcvbnm";

int i, j, s[26];

for (i=0; i<=25; i++)

s[i]=0;

clrscr();

cout<<"Введите строку\n";

gets(str);

for (i=0; i<=25; i++)

for (j=0; j<=strlen(str)-1; j++)

if (lat[i]==str[j]) s[i]++;

for (i=0; i<=25; i++)

cout<<lat[i]<<": "<<float (s[i])/strlen(str)<<"\n";

getche(); }

Лабораторная работа 5. Указатели

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

Пример

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

# include <iostream.h>

# include <conio.h>

# include <string.h>

# include <stdio.h>

void main(void)

{ char *str, lat[]="qwertyuiopasdfghjklzxcvbnm", *str1;

int i, s[26];

for (i=0; i<=25; i++)

s[i]=0;

clrscr();

cout<<"Введите строку\n";

gets(str);

str1=str;

for (i=0; i<=25; i++)

{while (*str1)

{if (lat[i]==*str1) s[i]++;

str1++;}

str1=str;}

for (i=0; i<=25; i++)

cout<<lat[i]<<": "<<float (s[i])/strlen(str)<<"\n";

getche(); }

5. ФУНКЦИИ В СИ

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

5.1 Объявление и определение функций

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

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

Определение функции содержит, кроме объявления, тело функции, которое представляет собой последовательность описаний и операторов.

тип имя_функции([список_формальных_параметров])

{тело_функции}

Тело_функции - это блок или составной оператор. Внутри функции нельзя определить другую функцию.

В теле функции должен быть оператор, который возвращает полученное значение функции в точку вызова. Он может иметь две формы:

1) return выражение;

2) return;

Первая форма используется для возврата результата, поэтому выражение должно иметь тот же тип, что и тип функции в определении. Вторая форма используется, если функция не возвращает значения, т.е. имеет тип void. Программист может не использовать этот оператор в теле функции явно, компилятор добавит его автоматически в конец функции перед }.

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

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

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

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

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

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

Заданы координаты сторон треугольника. Если такой треугольник существует, то найти его площадь.

1. Математическая модель:

1) l=sqrt(pow(x1-x2,2)+pow(y1-y2,2)); //длина стороны треугольника

2) p=(a+b+c)/2;

s=sqrt(p*(p-a)*(p-b)*(p-c)); //площадь треугольника

3) проверка существования треугольника

(a+b>c&&a+c>b&&c+b>a)

2. Алгоритм:

1) Ввести координаты сторон треугольника (х1,у1),(х2,у2),(х3,у3);

2) Вычислить длины сторон ab, bc, ca;

3) Проверить существует ли треугольник с такими сторонами. Если

да, то вычислить площадь и вывести результат.

4) Если нет, то вывести сообщение.

5) Если все координаты равны 0, то конец, иначе возврат на п.1.

#include <iostream.h>

#include <math.h>

double line(double x1, double y1, double x2, double y2)

{

//функция возвращает длину отрезка, заданного координатами

// x1,y1 и x2,y2

return sqrt(pow(x1-x2,2)+pow(y1-y2,2));

}

double square(double a, double b, double c)

{

//функция возвращает площадь треугольника,

//заданного длинами сторон а,b,c

double s, p=(a+b+c)/2;

return s=sqrt(p*(p-a)*(p-b)*(p-c));

}

int triangle(double a, double b, double c)

{

//возвращает 1, если треугольник существует, иначе 0

return (a+b>c&&a+c>b&&c+b>a);

}

void main()

{

double x1, y1, x2, y2, x3, y3;

double point1_2, point1_3, point2_3;

do

{

cout<<"\nEnter koordinats of triangle:";

cin>>x1>>y1>>x2>>y2>>x3>>y3;

point1_2=line(x1, y1, x2, y2);

point1_3=line(x1, y1, x3, y3);

point2_3=line(x2, y2, x3, y3);

if (triangle(point1_2, point1_3, point2_3))

cout<<"S="<<square(point1_2, point2_3, point1_3)<<"\n";

else cout<<"\nTriagle doesn't exist";

}

while(!(x1==0&&y1==0&&x2==0&&y2==0&&x3==0&&y3==0)); }

5.2 Прототип функции

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

double line(double x1,double y1,double x2,double y2);

double square(double a, double b, double c);

bool triangle(double a, double b, double c);

double line(double ,double ,double ,double);

double square(double , double , double );

bool triangle(double , double , double );

Это прототипы функций, описанных выше.

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

#include <имя файла>

Имя_файла определяет заголовочный файл, содержащий прототипы группы стандартных для данного компилятора функций. Например, почти во всех программах мы использовали команду #include <iostream.h> для описания объектов потокового ввода-вывода и соответствующие им операции.

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

#include ”имя_файла”

5.3 Параметры функции

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

При передаче по значению выполняются следующие действия:

- вычисляются значения выражений, стоящие на месте фактических параметров;

- в стеке выделяется память под формальные параметры функции;

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

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

Пример:

#include <iostream.h>

void Change(int a, int b) //передача по значению

{int r=a; a=b; b=r;}

void main(void)

{

int x=1, y=5;

Change(x, y);

cout<<”x=”<<x<<”y=”<<y;

}

выведется: x=1y=5

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

Пример:

#include <iostream.h>

void Change(int *a, int *b) //передача по адресу

{int r=*a; *a=*b; *b=r;}

void main(void)

{int x=1, y=5;

Change(&x, &y);

cout<<”x=”<<x<<”y=”<<y; }

выведется: x=5y=1

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

Пример:

#include <iostream.h>

void Change(int &a, int &b)

{int r=a; a=b; b=r;}

void main(void)

{

int x=1, y=5;

Change(x, y);

cout<<”x=”<<x<<”y=”<<y; }

выведется: x=5y=1

Использование ссылок вместо указателей улучшает читаемость программы, так как не надо применять операцию разыменовывания. Использование ссылок вместо передачи по значению также более эффективно, т.к. не требует копирования параметров. Если требуется запретить изменение параметра внутри функции, используется модификатор const. Рекомендуется ставить const перед всеми параметрами, изменение которых в функции не предусмотрено (по заголовку будет понятно, какие параметры в ней будут изменяться, а какие нет).

5.4 Рекурсия

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

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

printd (int n) //print n in decimal

{

char s[10];

int i;

if (n < 0)

{

putchar('-');

n = -n;}

i = 0;

do {

s[i++] = n % 10 + '0';// get next char

} while ((n /= 10) > 0); // discard it

while (--i >= 0)

putchar(s[i]);

}

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

printd(int n) // print n in decimal (recursive)

{

int i;

if (n < 0) {

putchar('-');

n = -n;

}

if ((i = n / 10) != 0)

printd(i);

putchar(n % 10 + '0');

}

Когда функция вызывает себя рекурсивно, при каждом обращении образуется новый набор всех автоматических переменных, совершенно не зависящий от предыдущего набора. Таким образом, в printd(123) первая функция printd имеет n = 123. Она передает 12 второй printd, а когда та возвращает управление ей, печатает 3. Точно так же вторая printd передает 1 третьей (которая эту единицу печатает), а затем печатает 2.

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

Лабораторная работа 6.

Использование функций для вычисления сумм и произведений

Вычислить последний член ряда ( или ).

1. ; ;

2. ; ;

3. ; ;

4. ; ;

5. ; ;

6. ; ;

7. ; ;

8. ; ;

Пример

; ;

# include <conio.h>

# include <iostream.h>

float x(int n, float a, int b);

float x(int n, float a, int b, int c)

{float s=0;

for (int j=b; j<=n; j++)

s+=a/(j+c);

return s;

}

void main(void)

{int n; float x1, x2, x3;

clrscr();

cout<<"n=";

cin>>n;

x1=x(n, 4, 0, 3);

x2=x(n, x1, 1, -5);

x3=x(n, x2, 3, 6);

cout<<"x3="<<x3;

getche(); }

Лабораторная работа 7.

Решение уравнений с использованием рекурсии

Решить заданное уравнение методом последовательного перебора на интервале с точностью и шагом .

1. ,

2. ,

3. ,

4. ,

5. ,

6. ,

7. ,

8. ,

Пример

,

# include <iostream.h>

# include <conio.h>

# include <math.h>

const double a=1, b=1.5, e=0.1, d=0.01;

double y(double x);

double y(double x)

{double f;

f=fabs(log(fabs(x))+2*tan(x)-3*x-0.5);

while ((f>e) && (x<b))

{x+=d; return y(x);}

if (f<=e) cout<<"x="<<x;

else cout<<"нет решений"; }

void main(void)

{

clrscr();

y(a);

getche();

}

6. РАБОТА С ФАЙЛАМИ

6.1 Доступ к файлам

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

В языке Си существует два типа потоков: текстовый (text) и двоичный (binary).

Текстовый поток - это последовательность символов. Однако может не быть взаимооднозначного соответствия между символами, которые передаются в потоке и выводятся на экран (например, символы возврата каретки или табуляции). Двоичный поток - это последовательность байтов, которые взаимооднозначно соответствуют тому, что находится на внешнем устройстве.

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

fp = fopen (name, mode);

Первым аргументом функции fopen является имя файла, которое задается в виде символьной строки. Второй аргумент mode (режим) также является символьной строкой, которая указывает, как этот файл будет использоваться. Допустимыми режимами являются: чтение ("r"), запись ("w") и добавление ("a").

Связующим звеном между файлом и потоком в системе ввода/вывода языка Си является указатель на файл (fp в примере). Указатель файла определяет имя файла на диске и его использование в потоке, ассоциированном с ним. Указатель файла - это указатель на структуру типа FILE, которая определена в файле stdio.h.

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

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

c = getc(fp)

помещает в переменную "с" следующий символ из файла, указанного посредством fp, или EOF, если достигнут конец файла.

Функция putc,

putc(c, fp)

являющаяся обратной к функции getc, помещает символ из переменной "с" в файл fp. Если операция была успешной, то возвращается записанный символ, иначе - EOF.

При запуске программы автоматически открываются три файла, которые снабжены определенными указателями файлов. Этими файлами являются стандартный ввод, стандартный вывод и стандартный вывод ошибок; соответствующие указатели файлов называются stdin, stdout и stderr. В обычной ситуации они связаны с консолью, однако могут быть перенаправлены на другой поток. Указатели файлов stdin, stdout и stderr могут располагаться в любом месте, где можно использовать объект типа FILE*. Использование потоков stdin и stdout будет показано в следующем примере.

Рассмотрим программу для конкатенации файлов. Используемая здесь основная схема оказывается удобной во многих программах: если имеются аргументы в командной строке, то они обрабатываются последовательно. Если такие аргументы отсутствуют, то обрабатывается стандартный ввод. Это позволяет использовать программу как самостоятельно, так и как часть большей задачи.

#include <stdio.h>

filecopy(fp)

// copy file fp to standard output

FILE *fp;

{

int c;

while ((c=getc(fp))!=EOF)

putc(c, stdout);

}

main(argc, argv)

// cat: concatenate files

int argc;

char *argv[ ];

{

FILE *fp;

if(argc==1) // no args; copy standard input

filecopy(stdin);

else

while (--argc > 0)

if ((fp = fopen(*++argv, "r")) == NULL)

{ printf("cat: can't open %s", *argv);

break; }

else { filecopy(fp);

fclose(fp); }

}

Функция fclose является обратной по отношению к fopen; она разрывает связь между указателем файла и внешним именем, установленную функцией fopen. После этого указателю может быть назначен другой файл.

6.2 Ввод и вывод строк

Стандартная библиотека содержит функцию fgets. В результате обращения

fgets(line, maxline, fp)

следующая строка ввода (включая символ новой строки) считывается из файла fp в символьный массив line; самое большое maxline-1 символ будет прочитан. Результирующая строка заканчивается символом `\0'. Нормально функция fgets возвращает line; в конце файла она возвращает NULL.

Предназначенная для вывода функция fputs записывает строку (которая не обязана содержать символ новой строки) в файл:

fputs(line, fp)

6.3 Обработка ошибок - stderr и exit

Обработка ошибок в саt неидеальна. Неудобство заключается в том, что если один из файлов по некоторой причине оказывается недоступным, диагностическое сообщение об этом печатается в конце объединенного вывода. Это приемлемо, если вывод поступает на терминал, но не годится, если вывод поступает в некоторый файл или через поточный (pipeline) механизм в другую программу.

Чтобы лучше обрабатывать такую ситуацию, к программе точно таким же образом, как stdin и stdout, присоединяется второй выходной файл, называемый stderr. Если это вообще возможно, вывод, записанный в файле stderr, появляется на терминале пользователя, даже если стандартный вывод направляется в другое место.

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

#include <stdio.h>

#include <string.h>

#include <process.h>

filecopy(fp)

// copy file fp to standard output

FILE *fp;

{

int c;

while ((c=getc(fp))!=EOF)

putc(c, stdout);

}

main(argc, argv)

// cat: concatenate files

int argc;

char *argv[ ];

{

FILE *fp;

if(argc==1) // no args; copy standard input

filecopy(stdin);

else

while (--argc > 0)

if ((fp=fopen(*++argv,"r"))==NULL)

{ fputs(strcat("cat: can't open ", *argv), stderr);

exit(1); }

else { filecopy(fp);

fclose(fp); }

exit(0);

}

Программа сообщает об ошибках двумя способами. Диагностическое сообщение, формируемое функцией strcat из стандартной библиотеки string.h, с помощью функции fputs поступает в stderr и, таким образом, оказывается на терминале пользователя, а не исчезает в потоке или в выходном файле.

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

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

Лабораторная работа 8. Файлы

1. Создать текстовый файл "a.txt". Подсчитать количество содержащихся в нем букв "а".

2. Создать текстовый файл "a.txt". Определить, каких в нем букв больше, гласных или согласных.

3. Предложить пользователю ввести с клавиатуры 5 строк. Создать текстовый файл "a.txt" и занести в него строки, длина которых меньше 10 символов.

4. Создать текстовый файл "a.txt". Изменить его таким образом, чтобы каждая строка была записана в обратном порядке.

5. Создать текстовый файл "a.txt". Исключить из него все цифры.

6. Предложить пользователю ввести с клавиатуры 5 строк. Создать текстовый файл "a.txt" и занести в него строки, заканчивающиеся на согласные буквы.

7. Создать текстовые файлы "a.txt" и "b.txt", записав в них равное количество строк. Создать третий файл "c.txt" таким образом, чтобы в нем чередовались строки файлов "a.txt" и "b.txt".

8. Создать текстовый файл "a.txt". Изменить его таким образом, чтобы строки были записаны в обратной последовательности, т.е. первая строка должна стать пятой, а пятая - первой, и т.д.

Пример

Предложить пользователю ввести с клавиатуры 5 строк. Создать текстовый файл "a.txt" и занести в него строки, не содержащие букв латинского алфавита.

# include <iostream.h>

# include <conio.h>

# include <string.h>

# include <stdio.h>

char str[80], lat[]={"qwertyuioplkjhgfdsazxcvbnm"};

int Test(void);

int Test(void)

{char *str1;

int j, flag;

flag=0;

str1=str;

while (*str1)

{for (j=0; j<=25; j++)

if (*str1==lat[j]) flag=1;

str1++;}

return flag;

}

void main(void)

{FILE *fp;

int i;

clrscr();

fp=fopen("a.txt","w");

for (i=0; i<=4; i++)

{ cout<<"Введите строку "<<i<<"\n";

gets(str);

if (!Test(void))

fputs(strcat(str,"\n"), fp);

}

fclose(fp);

}

7. ОСНОВЫ АВТОМАТНОГО ПРОГРАММИРОВАНИЯ

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

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

- вся логика программы строится на основе селектора (switch в языке Си);

- вспомогательно используется оператор условия if;

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

Представим универсальный автоматный алгоритм в общем виде (рис. 1).

Рис. 1

Рамка имитирует цикловую природу реализации автомата. Вверху явно указан оператор “while(cycle)”, где “cycle” - признак продолжения цикла, который перед передачей управления оператору while должен быть установлен в ненулевое значение.

Автоматная программа имеет несколько состояний Y. Обязательно наличие начального состояния Y=0.

Переходы между состояниями обозначаются стрелками и помечаются дробью: входное событие Х / выходное событие Z (действие на соответствующем переходе).

Пусть мы находимся в состоянии Y=i. Тогда при наступлении входного события Хij, за которым скрыто соответствующее логическое выражение, выполняется некоторая последовательность операторов Zij, подготавливающая функционирование автоматной программы в новом состоянии, и осуществляется переход в новое состояние (Y=j).

Разумеется, не обязательно должен быть возможен переход из любой вершины в любую. При его невозможности соответствующий Х равен нулю, и дуга отсутствует.

Входному событию взаимно однозначно соответствует переход из текущего состояния в другое. Если ни одно из вычисляемых в данном состоянии событий не наступило, то сохраняется текущее состояние, и этому соответствует логическое условие, отрицающее любое из входных событий - условий переходов в другие состояния (см. “петли” - дуги, исходящие и заходящие в одну и ту же вершину).

Отдельно, через запятую, указаны операторы вида “cycle = 0”, что означает конец циклической обработки. При этом направление перехода всегда к начальной вершине, она же является и заключительной для обеспечения корректного повторного использования данной подпрограммы.

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

int X01, ..., ХN(N-1), Z01, ..., ZN(N-1), Y=0, cycle=1;

while(cycle)

{

switch(Y)

{

case 0:

if (X01) {Z01; Y=1;}

else

...

if (X0i) {Z0i; Y=i;}

else

...

if (X0N) {Z0N; Y=N;}

else Z00;

break;

case 1:

if (X10) {Z10; Y=0; cycle=0;}

else

...

if (X1i) {Z1i; Y=i;}

else

...

if (X1N) {Z1N; Y=N;}

else Z11;

break;

...

case i:

if (Xi0) {Zi0; Y=0; cycle=0;}

else

...

if (Xi(i-1)) {Zi(i-1); Y=i-1;}

else

if (Xi(i+1)) {Zi(i+1); Y=i+1;}

else

...

if (XiN) {ZiN; Y=N;}

else Zii;

break;

...

case N:

if (XN0) {ZN0; Y=0; cycle=0;}

else

...

if (XNi) {ZNi; Y=i;}

else

...

if (XN(N-1)) {ZN(N-1); Y=N-1;}

else ZNN;

break;

}

}

Рассмотрим пример реализации алгоритма управления и контроля трехпозиционным клапаном (Кл) с памятью с помощью трех кнопок без памяти. Наличие памяти в исполнительных механизмах объекта управления (клапана) позволяет снимать с них управляющие сигналы после того, как клапан откроется или закроется, сохраняя это положение.

Приведем словесное описание алгоритма управления клапаном [Шалыто А.А. SWITCH-технология. Алгоритмизация и программирование задач логического управления. СПб.: Наука, 1998].

1. При нажатии кнопки “Откр.” (Х1) клапан начинает открываться.

2. После его открытия срабатывает сигнализатор открытого положения, зажигается лампа ”Откр.” (Х4) и снимается управляющий сигнал с клапана (Z2).

3. При нажатии кнопки “Закр.” (X2) клапан начинает закрываться.

4. После его закрытия срабатывает сигнализатор закрытого положения, зажигается лампа ”Закр.” (X3) и снимается управляющий сигнал с клапана (Z1).

5. Если в течение трех секунд (T=3) клапан не откроется или не закроется, то управляющий сигнал с клапана снимается и зажигается лампа контроля “Неисправность” (Z3).

6. Сброс сигнала контроля осуществляется нажатием кнопки “Разблок.” (Х5), после чего клапан принудительно закрывается.

7. Для фиксации события одновременного нажатия двух управляющих кнопок Х1 и Х2 включена лампа сигнализации «Ошибка» (Z4). Сброс сигнализации также осуществляется кнопкой Х5.

На рис. 2 приведена схема связей «источник информации - управляющий автомат - исполнительные механизмы», содержащая интерфейс автомата, краткие комментарии, поясняющие смысл используемых переменных и свойства органов управления, исполнительных механизмов и собственно объекта управления.

Рис. 2

По словесному описанию и приведенной схеме связей построим граф переходов автомата (рис. 3) в соответствии с концепцией, изложенной выше. Подробно методика разработки графа переходов излагается в курсе «Основы логического управления».

Рис. 3

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

Реализуем граф переходов с помощью программы, написанной на Си++.

# include <iostream.h>

# include <conio.h>

# include <dos.h>

void main(void)

{int X1, X2, X3, X4, X5, Z1=0, Z2=0, Z3=0, Z4=0, Y=0, cycle=1;

clrscr();

while (cycle)

{switch (Y)

{case 0:

cout<<"Закрыт \n";

cout<<"input X1X2 ";

cin>>X1>>X2;

if (X1&!X2) {Y=1;}

if (X1&X2) {Y=5; Z4=1;}

break;

case 1:

cout<<"Открывается...\n";

delay(3000);

cout<<"input X4 "; cin>>X4;

if (X4) {Y=2; Z2=1;}

else {Y=4; Z3=1;}

break;

case 2:

cout<<"Открыт \n";

cout<<"input X1X2 ";

cin>>X1>>X2;

if (!X1&X2) {Y=3;}

if (X1&X2) {Y=5; Z4=1;}

break;

case 3:

cout<<"Закрывается...\n";

delay(3000);

cout<<"input X3 "; cin>>X3;

if (X3) {Y=0; Z1=1; cycle=0;}

else {Y=4; Z3=1;}

break;

case 4:

cout<<"Неисправность! \n";

cout<<"input X5 ";cin>>X5;

if (X5) {Y=0; cycle=0;}

break;

case 5:

cout<<"Ошибка! \n";

cout<<"input X5 "; cin>>X5;

if (X5) {Y=0; cycle=0;}

break;

}

}

}

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

Размещено на Allbest.ru

...

Подобные документы

  • Базовый синтаксис языка программирования С#. Объявление переменных и присваивание им значений. Управление порядком выполнения программы. Выполнение преобразований с помощью команд преобразования. Определение классов, конструктора, работа с файлами.

    курс лекций [692,5 K], добавлен 23.11.2009

  • Возможности языков программирования С и С++. Разработка и реализация информационно-поискового справочника "Блок питания", листинг программы. Функции и структура данных в программе. Динамическое распределение памяти, работа с файлами, несложные сортировки.

    курсовая работа [38,7 K], добавлен 10.01.2011

  • История развития языка программирования Pascal, его основные концепции. Вычисления в математических задачах. Изменение порядка выполнения инструкций программы. Выполнение оператора цикла. Логические выражения, линейные алгоритмы, условные операторы.

    методичка [847,6 K], добавлен 10.01.2013

  • Строгая типизация и наличие средств структурного (процедурного) программирования императивного языка Pascal. Структура программы, выражения, строки. Правила и описание типов, процедур и функций, операторов ввода - вывода, модулей и подпрограмм.

    курсовая работа [37,3 K], добавлен 28.06.2008

  • Цели и задачи дисциплины "Технология программирования". Программные средства ПК. Состав системы программирования и элементы языка. Введение в систему программирования и операторы языка Си. Организация работы с файлами. Особенности программирования на С++.

    методичка [126,3 K], добавлен 07.12.2011

  • Структура, функции и организация деятельности Интерпола. Основные этапы проектирования базы данных картотеки. Назначение и виды запросов. Структура базы данных Интерпола по дисциплине "Основы алгоритмизации и программирования". Главная кнопочная форма.

    дипломная работа [2,6 M], добавлен 10.07.2015

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

    курсовая работа [738,1 K], добавлен 17.05.2010

  • Основы языка программирвоания C++. Элементы управления в Microsoft Visual C++. Алгоритмические конструкции языка программирования Visual C++ и базовые элементы управления. Глобальные константы и переменные. Управление программой с помощью клавиатуры.

    курсовая работа [1,7 M], добавлен 08.04.2015

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

    презентация [1,8 M], добавлен 05.11.2016

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

    презентация [308,3 K], добавлен 31.10.2016

  • Понятие базового и прикладного программного обеспечения. Информация, ее свойства и виды. Интерфейс ОС Windows. Программа управления файлами "Проводник". Windows-редакторы Paint и MS Word. MS Excel: расчет амортизации. Программа Internet Explorer.

    практическая работа [1,1 M], добавлен 16.01.2011

  • Понятие алгоритма. Цикл программы. Структурная схема алгоритма. Элементы языка Тurbo Рascal. Алфавит. Идентификаторы. Комментарии. Лексика языка С++. ESC-последовательности. Операции. Ключевые слова. Комментарии.

    контрольная работа [43,0 K], добавлен 24.04.2006

  • Классификация систем программирования. Специализированные редакторы, программы-компиляторы и исполнимый код. Разновидности Visual Basic. Версии Паскаля и его использование. Приложения на языке Java. Разработка программы для вычисления предельной ошибки.

    курсовая работа [34,0 K], добавлен 28.12.2009

  • История создания языка Java. Основные принципы объектно-ориентированного программирования. Структура, особенности синтаксиса и примеры прикладных возможностей использования языка Java, его преимущества. Перспективы работы программистом на языке Java.

    курсовая работа [795,9 K], добавлен 14.12.2012

  • Проектирование программного модуля в среде программирования Borland Delphi 7.0. Схемы алгоритмов решения задач по темам "Символьные переменные и строки", "Массивы", "Работа с файлами", "Создание анимации". Реализация программного модуля, код программы.

    отчет по практике [961,6 K], добавлен 21.04.2012

  • Базовые основы программы Prolog - языка и системы логического программирования. Работа с текстами и предложениями. Электронный казахско-русско-английский словарь. Дистанционный комплекс обучения государственному языку специалистов технического профиля.

    реферат [45,6 K], добавлен 15.09.2014

  • Характеристика структурированного языка программирования С, его основных структурных компонентов, области памяти, библиотеки. Методы поиска в массивах данных. Описание программы, функции сортировки и меню выбора, последовательного и бинарного поиска.

    курсовая работа [1,7 M], добавлен 19.05.2014

  • Рассмотрение особенностей среды программирования Delphi. Разработка программы для пересчета длины из фунтов в килограммы с использованием следующих объектов: Edit, Label, Button. Значения свойств поля ввода-редактирования и командной кнопки Перерасчет.

    практическая работа [177,2 K], добавлен 18.10.2012

  • Освоение технологии структурного программирования и применения стандартных методов работы с одномерными массивами при разработке и создании программы на языке Турбо Паскаль. Разработка программы методом пошаговой детализации с помощью псевдокода.

    реферат [276,9 K], добавлен 27.02.2008

  • Международный стандарт на язык программирования Паскаль. Приемы объектно-ориентированного программирования в Турбо Паскале. Символы языка, его алфавит. Этапы разработки программы. Понятие алгоритмов и алгоритмизации. Структура программ на Паскале.

    курсовая работа [29,8 K], добавлен 28.02.2010

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.