рефераты конспекты курсовые дипломные лекции шпоры

Реферат Курсовая Конспект

Алгоритмические языки и основы

Алгоритмические языки и основы - раздел Философия, Министерство Образования И Науки Российской Федерации...

Министерство образования и науки Российской федерации

Федеральное государственное бюджетное образовательное учреждение высшего профессионального образования

Алгоритмические языки и основы

Программирования

Язык Си

МЕТОДИЧЕСКИЕ УКАЗАНИЯ, ЗАДАНИЯ И ПРИМЕРЫ ВЫПОЛНЕНИЯ ЛАБОРАТОРНЫХ РАБОТ № 1 – 8

ДЛЯ СТУДЕНТОВ НАПРАВЛЕНИЯ 23040062 «Информационные системы и технологии»

 

 

Ульяновск

ЯЗЫК СИ

Тема №1. Функции стандартного ввода–вывода, вычисление математических функций

 

Задание: составить программу для проведения математических вычислений по индивидуальным вариантам заданий, которые представлены далее по тексту; все исходные данные, необходимые для вычислений, вводить с клавиатуры.

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

Краткая теоретическая справка и рекомендации по выполнению

Для каждой функции обратите внимание на тип обрабатываемых данных, например, результатом функции abs(–3.7) будет число 3.0, а не 3.7 как ожидалось,…   Перечень математических функций для изучения (в тригонометрических функциях углы измеряются в радианах):

Пример выполнения задания по теме № 1

/* Блок директив препроцессору */

#include <math.h>

#include <stdio.h>

#define g 9.81

/* Объявление глобальной переменной */

float H;

/* Блок главной функции программы */

int main()

{

/* Объявление локальной переменной */

float V;

 

printf("nЛабораторная работа N1 вариант N12");

printf("nnВыполнила студентка гр.Пд-11 Петрова Н.В.");

printf("nВертикально вверх бросают камень со скоростью V.");

printf("nОпределите максимальную высоту подъема камня.");

printf("nВведите начальную скорость в м/c (от 0 до 100) V=");

 

scanf("%f",&V);

H=pow(V,2);

H=H/(2*g);

printf("nМаксимальная высота подъема камня H=%5.2f м",H);

return 0;

}

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

Найдите описание функций, которые относятся к используемым в программе библиотекам: математической (math), библиотеке стандартного ввода-вывода (stdio). Более пристального внимания требуют функции форматного ввода-вывода (scanf и printf), особенно вопросы задания формата вводимых и выводимых данных, так как в Паскале выбор формата выводимых данных определял компилятор по типу переменной, а здесь выбор (как и многое другое) определяет программист. Не забудьте, что функция scanf требует адреса переменной.

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

- лишняя точка с запятой после объявления функции main(),

- объявление локальной переменной до фигурной скобки,

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

Формулы для решения задач

Площадь треугольника: где а – основание, h – высота треугольника. Формула Герона для вычисления площади треугольника:

Варианты заданий

1. По значению сторон треугольника определить все его высоты.

2. По координатам вершин квадрата вычислить площадь, вписанного в него круга.

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

4. По сторонам треугольника вычислить биссектрисы всех его углов.

5. По сторонам треугольника вычислить площадь вписанного в него круга.

6. По сторонам и основаниям трапеции вычислить её диагонали.

7. По сторонам треугольника вычислить его площадь и углы.

8. По координатам вершин квадрата вычислить площадь описанного круга.

9. По сторонам треугольника вычислить его медианы.

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

11. По сторонам прямоугольника вычислить площадь описанного вокруг него круга.

12. По координатам трех точек на плоскости вычислить радиус окружности, проходящей через эти точки.

13. По радиусу окружности и хорде вычислить площадь равнобедренного треугольника, вписанного в эту окружность (основание треугольника - хорда).

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

15. По сторонам треугольника определить площадь описанного вокруг него круга.

16. По стороне правильного шестиугольника вычислить его площадь.

17. По сторонам прямоугольника вычислить площадь вписанного в него эллипса.

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

 

1. Как загрузить и сохранить текст программы?

2. Как запустить программу на исполнение?

3. Как откомпилировать программу?

4. Как задать формат вывода чисел в функции printf?

5. Дайте общую характеристику библиотечных математических функций.

6. Где находится результат компиляции программы?

7. Что означает директива препроцессору #include?

 


Тема №2. Ветвление программы (использование операторов ветвления и переключателя switch)

Задание: используя операторы ветвления (if и if … else), составить программу для вычисления составной (сложной) функции, имеющей различный вид на разных участках аргумента. С помощью переключателя (switch) указать на каком отрезке находится введенное с клавиатуры значение аргумента, и вывести значение функции в данной точке.

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

Варианты заданий

Таблица 1

№ варианта Функция Участки аргумента
y1=x3 –2<=x1<0
y2=x2 0<=x2<1
y3=4*ln(x) 1<=x3<1.5
y4=-10*(x-1.6)2 1.5<=x4<=2
y1=1/ïxï –1<=x1< – 0.05
y2=19*e(-x) –0.05<=x2<1
y3=sin(10x)+7.6 1<=x3<2.05
y4=13+5*(x-3)3 2.05<=x4<=3
y1=0.5*Ö(1+x4) –3<=x1<–2
y2=cos(3x)+1 –2<=x2<2
y3=ln10x+1.3 2<=x3<3
y4=2.2+5*sin(x-3) 3<=x4<= 4
y1=e(-5*x)+x3 – 5<=x1< – 0.3
y2=-4*arcsin(3x) – 0.3<=x2<0.25
y3=(x-2.5)/(x+0.4) 0.25<=x3<2.05
y4=5*(x-3)3+4 2.05<=x4<=3
y1=20*x –1<=x1<– 0.5
y2=-160*x4 – 0.5<=x2<0.5
y3=-20*sin(5(x-0.5))-10 0.5<=x3<1.5
y4=(x-1.75)2*190-3 1.5<=x4<=2
y1=Ö(1+x2) –2<=x1<0
y2=Ö(2-Ö(sin(1+x))) 0<=x2<1
y3=cos(4*(1+x)+1.1) 1<=x3<1.5
y4=-4*(x-1.5)+0.2 1.5<=x4<=2
y1=(-x)3+sin(x) –1<=x1<– 0.05
y2=(x2+ex)-1 0.05<=x2<2
y3=13-ln(x)*4 2<=x3<3
y4=8+10*sin(x-3) 3<=x4<=4
Продолжение таблицы 1
№ варианта Функция Участки аргумента
y1=arcsin(x) – 1<=x1<1
y2=2*cos(10x)+p 1<=x2<2
y3=-x3+x2+8 2<=x3<2.5
y4=(x-4)4-6.4 2.5<=x4<=3
y1= cos(x) +tg(x) – 1<=x1<– 0.5
y2=2*arcsin(x)+1.4 – 0.5<=x2<0.5
y3=-x6*ln(1+x)+2.45 0.5<=x3<1
y4=-3*(x-1.6)2+2.8 1<=x4<=2
y1=ex+x – 4<=x1<– 3
y2=e-x*sin(x) – 3<=x2<0
y3=0 0<=x3<1.5
y4=-4*(x-1.5) 1.5<=x4<=2
y1=3*cos(2*x)+4*sin(10*x) – 1<=x1<– 0.05
y2=ex – 0.05<=x2<1
y3=ln(x)+xe+1.7 1<=x3<2.05
y4=13.8+5*(x-3)3 2.05<=x4<=3
y1= 7sin(x) – 1<=x1<– 0.5
y2=(x+1)*(x2+1)-1 – 0.5<=x2<0.5
y3=1.2sin(2x) 0.5<=x3<1
y4=-(x-0.6)2+1.25 1<=x4<=2
y1=arcsin(x)*ln(x+2) – 4<=x1<– 3
y2=2*cos(10*x)+3 – 3<=x2<0
y3=30*(x-2.25)2+2.25 0<=x3<1.5
y4=15*(x-2.5)+4 1.5<=x4<=2

 

Пример выполнения лабораторного задания № 2

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

Обратите внимание на отступы вправо, принятые при записи программ.

Условный оператор специально используется в двух форматах: с применением и отсутствием альтернативной части (else).

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

int main()

{ /* задание переменной перечисляемого типа */

enum {def,o1,o2,o3,o4} otr; /* номер отрезка, def – выбор по умолчанию */

float x,y;

 

printf(" Лабораторная работа N 2 вариант 27 n");

printf("Тема: Ветвление программы n");

printf(" Задание: Используя оператор if, составить программу n");

printf("для вычисления составной функции вида: n");

printf("1> sqr(x) при x от -2.0 до 1.0n");

printf("2> sqrt(x) при x от 1.0 до 2.0n");

printf("3> y=sqrt(x-2)+sqrt(2) при x от 2.0 до 3.0n");

printf("4> y=1+sqrt(x-1) при x от 3.0 до 4.0n");

printf("указать отрезок, где находится введенный с клавиатуры n");

printf("аргумент и вывести значение функции в данной точке. n");

printf(" Автор: Путилов Александр Петрович, гр. Пд-11 n");

 

printf("Введите x=");

scanf("%f",&x); printf("n");

 

/* Выбор отрезка */

otr=def;

if ((x>=-2.0) && (x<1.0)) otr=o1;

else if ((x>=1.0) && (x<2.0)) otr=o2;

if ((x>=2.0) && (x<3.0)) otr=o3;

if ((x>=3.0) && (x<=4.0)) otr=o4;

 

/* Вычисление значения функции */

switch (otr)

{

case o1: y=pow(x,2); break;

case o2: y=sqrt(x); break;

case o3: y=sqrt(x-2)+sqrt(2); break;

case o4: y=1+sqrt(x-1); break;

default: printf("Число вне диапазона."); getch(); exit(1);

}

printf ("Промежуток %d: y= %3.2f; ",otr,y);

return 0;

}

 

Обратите внимание, что в примере использована еще одна библиотека stdlib. Часть функций этой библиотеки уже известна по математической библиотеке, а другие функции надо будет изучать по мере необходимости.

Новым является использование перечисляемого типа данных (enum). Объявление перечисления задает тип переменной перечисления и определяет список именованных констант, называемый списком перечисления. Значением каждого имени списка является некоторое целое число. Переменная типа перечисления может принимать значения одной из именованных констант списка. Именованные константы списка имеют тип int. Поэтому переменной перечисляемого типа можно присвоить любое значение типа int. Фатальной ошибки при этом не будет, только предупреждение (Assign int to enum) о том, что переменной перечисляемого типа присвоено целое значение. Допускаете ли вы такую вольность или нет, решайте сами, так как последствия могут быть неожиданными.

При использовании операторов ветвления программы (if, else), несколько существенных особенностей, отличающих синтаксис языков Паскаль и Си и дающих наибольшее число ошибок:

- в языке Си результатом логической операции служит целое число, любое целое число, не равное 0, интерпретируется как истина;

- поразрядные (битовые) логические операторы: & , | , ^ , ~ ;

- логические операторы: && , || , ! ;

- логическое выражение после слова if обязательно должно быть в круглых скобках;

- выражение перед альтернативной частью (else) должно заканчиваться точкой с запятой;

- оператор проверки на равенство обозначается двойным знаком «равно», а проверка на неравенство – «восклицательный знак равно».

 

Для того чтобы начертить блок-схему алгоритма вычисления составной функции и прочих алгоритмов в курсе АЯиОП, познакомьтесь с ГОСТ 19.003-80.doc «СХЕМЫ АЛГОРИТМОВ И ПРОГРАММ. ОБОЗНАЧЕНИЕ УСЛОВНЫЕ ГРАФИЧЕСКИЕ»

 

   
 
 

 


Блок-схема алгоритма вычисления составной функции

 

Блок-схема выбора функции

 

Контрольные вопросы к лабораторной работе № 2

1. Как используются операторы логических операций (и, или, исключающее или) в условных выражениях?

2. Начертите таблицы истинности логических операций.

3. Укажите тип переменной оператора switch, по значению которой выполняется переключение.

4. Какое действие может быть выполнено в операторе switch по умолчанию?

5. Какой синтаксис записи метки в операторе switch?

6. Как использовать окно Watch?

7. Как выполнить программу по шагам (Step over и Trace into)?

8. Как средствами встроенного редактора производится копирование и вклейка фрагмента текста?


Тема №3. Циклы, символьный (литерный) тип данных

2). Написать программу при помощи оператора цикла while . 3). Написать программу при помощи оператора цикла do…while . 4). Начертить блок-схемы к программам.

Примеры выполнения задания по теме №3.

Распечатать на экране монитора таблицу символов, используя только циклы (без использования массивов и строк)

 

A C E G I
I A C E G
G I A C E
E G I A C
C E G I A

 

Используя замеченные закономерности можно предложить следующий алгоритм решения:

§ надо организовать счет по строкам от первой до пятой (цикл по счетчику i), при каждом повторении этого цикла, т.е. внутри него будет выполняться три действия, объединенные в составном операторе:

I) распечатка строки символов (сначала A C E G I, а потом и других),

II) переход на следующую строку,

III) вычисление значения первого символа в следующей строке;

§ в каждой строке необходимо организовать счет (переменная j) по символам (с 1-ого до 5-ого); при каждом повторении цикла будет выполняться три действия (опять нужен составной оператор):

1) будет проверяться значение печатаемого символа (переменная C), и если окажется, что оно больше ‘I’, тогда переменной C присваивается значение ‘A’,

2) значение переменной C выводится на экран монитора,

3) переменной C присваивается новое значение (следующее за следующим, т.е. символы следуют через один).

Как при описании алгоритма, так и по тексту программы, действия внешнего цикла обозначены римскими цифрами, а внутреннего – арабскими. Решение записано в двух вариантах: подробном и сокращенном для демонстрации возможностей цикла for.

#include <conio.h>

#include <stdio.h>

int main() // ПОДРОБНЫЙ ВАРИАНТ ЗАПИСИ ПРОГРАММЫ

{

int i,j; /* Счетчики */

char c='A'; /* Переменная для хранения значения первого символа

в строке */

// Цикл по строкам

for (i=1; i<=5; i++)

{ /* Начало действий внутри цикла по строкам */

/**** I) Печать строки символов */

for (j=1; j<=5; j++)

{ /* Начало тела цикла печати строки */

if (c>'I') c='A'; /*** 1) Проверка значения символа */

printf ("%2c",c); /*** 2) Вывод символа на экран */

c++; c++; /*** 3) Новое значение символа */

} /* Конец тела цикла печати строки */

/**** II) Переход на следующую строку */

printf ("n");

/**** III) Подготовка первого символа следующей строки */

c--;

c--;

} /* Конец действий внутри цикла по строкам */

getch();

return 0;

}

 

После подробно описанного алгоритма работы, особенностей, на которые можно было бы обратить внимание в первой программе, совсем немного. Это инициализация переменной C во время объявления и изменение значения литерной переменной C оператором декремента («минус-минус»), хотя С – переменная литерного типа.

Вторая программа (сокращенный вариант записи программы) также содержит особенности свойственные языку Си:

1) переменные i и j - литерного типа, но потом будут использованы как целочисленные;

2) в циклах for использован оператор запятая, позволяющий сделать программу более компактной.

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

#include <conio.h>

#include <stdio.h>

int main() // СОКРАЩЕННЫЙ ВАРИАНТ ЗАПИСИ ПРОГРАММЫ

{

char i, j, c;

for (i=1,c='A'; i<=5; printf ("n"),c-=2,i++)

{

for (j=1; j<=5; c+=2,j++)

{

if (c>'I') c='A';

printf ("%2c",c);

}

}

return 0;

}

 


Блок-схема к программе

 

Вторая программа рисует ту же таблицу, но используется цикл whileи другой алгоритм:

#include <stdio.h>

#include <conio.h>

char First; /* Первый символ в строке */

char C; /* Текущий символ в строке */

int main()

{

First='K'; /* Первый символ в первой строке */

while (First>='C')

{

/* Печать первой части строки символов */

C=First;

while (C<='I')

{

printf("%2c",C); // Печать очередного символа

C+=2; // Вычисление следующего значения

}

/* Печать второй части строки символов */

C='A';

while (C<First)

{

printf("%2c",C); // Печать символа

C+=2; // Вычисление следующего значения

}

/* Переход на другую строку */

printf("n");

/* Вычисление значения первого символа */

First-=2;

}

getch();

return 0;

}


Варианты заданий

1.         2.         3.           4.            
                                                     
A D G J M   A B C D E   A B C D E F   A              
M D G J M   B C D E     B C D E F G   B C            
M J G J M   C D E       C D E F G H   D E F          
M J G J M   D E         D E F G H I   - - - -        
M J G D M   E           E F G H I J   F E D          
M J G D A               F G H I J K   C B            
                                      A              
                                                     
5.                 6.         7.         8.      
                                                     
A B C D E F G H I   A B C D E   A E D C B   A B C D E
  B C D E F G H     E A C D E     B E D C   A A B C D
    C D E F G       E D A D E       C E D   B A A B C
      D E F         E D C A E         D E   C B A A B
        E           E D C B A           E   D C B A A
                                            E D C B A
                                                     
9.         10.             11.         12.          
                                                     
I                 A         + + O + +   F            
I G             B A B       + O O O +   E F          
I G E         C B A B C     O O O O O   D E F        
I G E C     D C B A B C D   + O O O +   C D E F      
I G E C A     C B A B C     + + O + +   B C D E F    
                B A B                   A B C D E F  
                  A                                  
                                                     
13.         14.         15.         16.              
                                                     
A           A D B E C   A E D C B   A C E G I        
B C         C A D B E   B A E D C   B D F H J        
D E F       E C A D B   C B A E D   C E G I K        
G H I J     B E C A D   D C B A E   D F H J L        
K L M N O   D B E C A   E D C B A   E G I K M        
                                                     
17.         18.         19.         20.                
                                                       
A B C D E   A D G J M   E           A B C D E F        
Z B C D E   B E H K N   D E         B C D E F          
Y Z C D E   C F I L O   C D E       C D E F            
X Y Z D E   D G J M P   B C D E     D E F              
W X Y Z E   E H K N Q   A B C D E   E F                
                                    F                  
                                                       
21.         22.         23.         24.                
                                                       
I H G F E   N M L K J         A           A            
H G F E     M L K J         B C         A * B          
G F E       L K J         D E F       A * B * C        
F E         K J         G H I J     A * B * C * D      
E           J         K L M N O   A * B * C * D * E    
                                                       

Контрольные вопросы к теме № 3

1. Как использовать цикл for в языке Си?

2. Что означают операторы «++», «– –», «+=» и т.д.?

3. Назначение оператора break в языке Си?

4. К какому типу относится цикл for (с пред- или пост- условием)?

5. Как использовать цикл while?

6. Как использовать цикл do…while?

7. Чем отличаются циклы с пред-и пост-условиями?


Тема №4. Функции в языке Си

Задание: реализуйте задачу по теме №3 с использованием функций.

Пример решения задачи по теме №3 с использованием функций.

Для иллюстрации решения рассмотрим алгоритм, представленный для языка Паскаль. Сделаем «перевод» с языка Паскаля на язык Си, указав отличия.

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

Во-вторых, напомним, что в языке Си нет понятия «процедура», но есть функция, которая не возвращает никакого значения.

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

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

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

Шестое – локальные переменные пишутся внутри операторных скобок, определяющих тело функции.

#include <stdio.h>

#include <conio.h>

//Описание функции печати части строки

void Part(char First, char Last)

{ char C;

C = First;

Last --;

while (C <= Last)

{

printf("%2c",C);

C+=2;

}

}

//Основная часть программы

int main()

{

const int F1= 'K';

const int F2='A';

char First1 =F1, First2 =F2;

while (First1>='C')

{

Part(First1,F1); // Печать первой части строки

Part(First2,First1); // Печать второй части строки

printf("n");

First1 -=2;

}

return 0;

}

}

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

1. Что такое глобальные переменные?

2. Для чего нужны параметры в функции?

3. Назначение функций?

4. Что такое локальные переменные?

5. Что такое параметры-переменные?

6. Что такое параметры-значения?

7. Что такое рекурсия?

8. Что такое условие выхода из рекурсии?

9. Что такое формальные параметры?

10. Что такое фактические параметры?


Тема №5. Обработка одномерных массивов

Задание:

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

Краткая теоретическая справка и рекомендации по выполнению

Самый безобидный вариант некорректного использования индексов приведен в следующем коротком фрагменте программы: int x; int y[2]; int z; void main()

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

 

// 1. Инициализация генератора случайных чисел

void Randomize()

{

srand(time(0));

}

Функция инициализации генератора случайных чисел использует библиотечные функции srand, в которую в качестве параметра передается текущее время time(0). Прототип функции time находится в заголовочном файле <time.h>.

//2. Генератор случайного числа в диапазоне от 0 до range

int Random(int range)

{

return (rand() % range);

}

Функция генератора случайных чисел использует библиотечную функцию rand (прототип в файле stdlib.h). Функция rand вычисляет псевдослучайное число в диапазоне от 0 до 65535. Для задания числа в заданном диапазоне используется остаток от целочисленного деления генерируемого числа на диапазон range.

// 3. Проверка повторения случайного числа

// c - указатель начала массива, n - индекс нового элемента

int Test_Repetition(int *c, int n)

{ int x, j;

x = 0; // Считаем, что значение новое

// Цикл сравнения со всеми предыдущими

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

if (*(c+n)==*(c+j))

{

x = 1; // Элементы совпали

break;

}

return x;

}

 

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

// 4. Добавить новый элемент

// с - указатель начала массива, n - номер нового элемента

// range1, range2 – левая и правая границы диапазона

void New_Item(int *c, int n, int range1, int range2)

{ int x = 0; // Элементы массива разные

do

{

c[n] = Random(range2 - range1) + range1; // Новое значение

x =Test_Repetition(c,n); // Проверка на повторение

}

while (x==1); // Повторять, когда элементы совпали

}

В этой функции, если проверка на «неповторимость» элемента не требуется, достаточно использовать только строку присваивания в переменную c[n] результата работы функции Random.

// 5. Заполнение одномерного массива

// c - массив, n - количество элементов

void Filling (int *c, int n, int range1, int range2)

{ int i;

c[0]=Random (range2 - range1) + range1; // Элемент с индексом 0.

// Цикл заполнения массива

for (i=1;i<n; i++) // Цикл заполнения элементов значениями

New_Item(c, i, range1, range2);

}

Для реализации заполнения неповторяющимися числами, в функции заполнения массива приходится первое значение (с индексом 0) задавать отдельно, а не в цикле.

// 6. Распечатка одномерного массива

void Print(int *c, int n)

{ int i;

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

printf("%4d",c[i]);

puts(""); // Переход на новую строку

}

// 7. Поиск минимального значения

// с – указатель на начало одномерного массива,

// n - количество элементов массива,

// index – указатель на индекс минимума

int Min(int *c, int n, int *index)

{ int i, min;

min = c[0]; // Начальное значение минимума

(*index) = 0; // Начальное значение индекса минимума

for ( i=1; i<n; i++ )

if (c[i]<min)

{

min = c[i];

(*index) = i;

}

return min;

}

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

// 8. Создание дубликата массива в динамической памяти

int * Copy (int *c, int n)

{ int *m, i;

// Резервирование памяти под дубликат массива

m = (int*)malloc(sizeof(int)*n);

// Копирование массива

for ( i = 0; i<n; i++ ) m[i] = c[i];

// Функция возвращает адрес нового массива

return m;

}

Обратите внимание, что количество резервируемой памяти определяется типом данных одного элемента и количеством элементов в массиве ((sizeof(int)*n)). Так как библиотечная функция для резервирования памяти (malloc) возвращает нетипированный указатель, то требуется преобразование к типу. В данном примере – это преобразование к типу указателя на целое число (int *).

// 9. Обмен элементов местами в массиве

void Exchange (int *c, int n, int k)

{ int tmp; //Переменная для временного хранения данных

tmp = c[n];

c[n] = c[k];

c[k] = tmp;

}

// 10 .Сортировка методом прямого поиска

void SearchSort ( int *c, int n )

{ int i, min, indexMin; int *p;

for ( i=0; i<n-1; i++) // Определить массив с индексами от i до n

{ p = (c+i); // Задать адрес начала массива

min = Min (p, n-i, &indexMin); // Найти минимум в массиве

// Обменять местами минимальный элемент с первым

Exchange ( p, 0, indexMin ); }

}

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

#include <stdio.h>

#include <stdlib.h>

#include <locale.h>

#include <time.h>

#define N 15

void Randomize();

int Random(int range);

int Test_Repetition(int *c, int n);

void New_Item(int *c, int n, int range1, int range2);

void Filling (int *c, int n, int range1, int range2);

void Print(int *c, int n);

int Min(int *c, int n, int *index);

int * Copy (int *c, int n);

void Exchange (int *c, int n, int k);

void SearchSort ( int *c, int n );

// Главная функция

int main()

{

int m[N];

int min, IndexMin;

int *Duplicate;

Rus();

Randomize();

Title();

puts("nЗаполнение массива");

Filling(m,N,-30,70);

puts("nРаспечатка массиваn");

Print (m,N);

puts("nМинимальное значение массиваn");

min = Min(m,N,&IndexMin);

printf("min = %d его индекс = %d n", min, IndexMin);

puts("nСоздание дубликата массиваn");

Duplicate = Copy(m,N);

puts("nРаспечатка дубликата массиваn");

Print (Duplicate,N);

puts("nСортировка дубликата методом прямого поиска");

SearchSort(Duplicate,N);

puts("nРаспечатка дубликата массива после сортировкиn");

Print (Duplicate,N);

puts("nУдаление дубликата");

free(Duplicate);

return 0;

}

Варианты заданий

1. Заполнить два массива, размером 20 и 30 элементов, соответственно, случайными целыми числами в диапазоне от -50 до 50. Из полученных двух массивов выделить в два массива отдельно отрицательные и положительные числа. Произвести сортировку полученных массивов и исходного массива по возрастанию. Для контроля результата сделать распечатку массивов, в том числе исходного.

2. Заполнить два массива размером 20 и 30 элементов случайным образом буквами латинского алфавита. Заполнить третий массив теми буквами, которые входят и в первый и во второй массив, четвертый массив – оставшимися буквами из первого и второго. Произвести сортировку полученных массивов. Для контроля результата также сделать распечатку массивов, в том числе исходного.

3. Из исходного массива символов, заполненного случайным образом символами с кодами в диапазоне от 21 до 254, выделить в отдельные массивы буквы латинского алфавита, как заглавные, так и прописные. Произвести сортировку полученных массивов. Для контроля результата сделать распечатку массивов, в том числе исходного.

4. В исходном массиве символов, заполненном случайным образом символами с кодами в диапазоне от 21 до 254, выделить в отдельные массивы заглавные гласные и заглавные согласные буквы латинского алфавита. Произвести сортировку полученных массивов. Для контроля результата сделать распечатку массивов, в том числе исходного.

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

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

7. Заполните случайным образом массив (100 элементов) поочередно буквами латинского алфавита от A до H и символами цифр от 1 до 8. Проверьте, есть ли в данном массиве записи, сходные с записью ходов коня по шахматной доске, и, если есть заполните ими второй массив. Выполните сортировку полученных массивов. Для контроля результата сделайте распечатку массивов, в том числе исходного.

8. В исходном массиве символов, заполненном случайным образом символами с кодами в диапазоне от 21 до 254, выделить в отдельные массивы строчные гласные и строчные согласные буквы латинского алфавита. Произвести сортировку полученных массивов. Для контроля результата сделать распечатку массивов, в том числе исходного.

9. В виде массива символов дан текст (ввод с клавиатуры). Случайным образом заполните второй массив из 26 элементов символами, отличными от букв латинского алфавита и друг от друга, причем каждый символ должен встречаться один раз. Будем считать, что первый элемент второго массива соответствует букве «а», второй букве «b» и т.д. Требуется зашифровать текст из первого массива, заменяя буквы первого массива символами из второго. Произведите сортировку массивов. Для контроля результата сделать распечатку массивов, в том числе исходного.

10. В массив символов вводится текст на русском языке, состоящий из нескольких слов. Учитывая, что строчные буквы русского алфавита в операционной системе MSDOS расположены не подряд, а разбиты на два диапазона (от «а» до «п» и от «р» до «я»), слова, состоящие только из букв одного из диапазонов поместите в один массив, а другие во второй. Проведите сортировку полученных массивов. Для контроля результата сделайте распечатку массивов, в том числе исходного.

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

12. Дан массив содержащий текст. Среди литер текста особую роль играет знак # , появление которого означает отмену стоящей перед ним буквы, несколько знаков # означает отмену соответствующего числа букв. Создать массив заполненный текстом из первого массива с учетом роли этого знака. (например, ХЭ#E##НЕLO#LO = HELLO). Произвести сортировку полученных массивов. Для контроля результата сделать распечатку массивов, в том числе исходного.

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

14. Заполнить два массива, размером 40 и 30 элементов, соответственно, случайными целыми числами в диапазоне от -50 до 50. Из полученных двух массивов создать два массива отдельно, один из которых содержит числа от -10 до 10, а другой – от 20 до 50. Произвести сортировку полученных массивов по возрастанию. Для контроля результата сделать распечатку массивов, в том числе исходного.

15. Заполните случайным образом массив (100 элементов) поочередно буквами латинского алфавита от A до H и символами цифр от 1 до 8. Проверьте, есть ли в данном массиве записи, сходные с записью ходов ладьи по шахматной доске, и, если есть, заполните ими второй массив. Выполните сортировку массивов. Для контроля результата сделайте распечатку массивов, в том числе исходного.

16. Заполните случайным образом массив (100 элементов) поочередно буквами латинского алфавита от A до H и символами цифр от 1 до 8. Проверьте, есть ли в данном массиве записи, сходные с записью ходов ферзя по шахматной доске, и, если есть, заполните ими второй массив. Выполните сортировку массивов. Для контроля результата сделайте распечатку массивов, в том числе исходного.

 

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

1. Какого типа могут быть индексы массивов?

2. Что такое размерность массивов?

3. Для чего нужен «барьер» в сортировке методом прямого включения?

4. Каков алгоритм поиска минимума или максимума в одномерном массиве?

5. Как найти индекс элемента в одномерном массиве по его значению?

6. Алгоритм поиска минимума или максимума в двумерном массиве.

7. Назначение функций random и randomize?

8. Сортировка элементов двумерного массива.

9. Как обратиться к элементу массива по указателю?

 


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

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

Индивидуальные задания на лабораторную работу даны в конце описания к теме № 6. Длина вводимого предложения не более 80 символов (ширина экрана). При выполнении задания необходимо во всех случаях, где это можно, использовать функции для работы со строками. Все задания подразумевают необходимость применения не менее трех разных функций.

Краткая теоретическая справка и рекомендации по выполнению

Объявление переменной типа строка в языке Си возможно тремя способами, два из которых инициализируют строку во время объявления. Первый способ ничем… char s[40+1]; Второй способ предусматривает присваивание строковой переменной начального значения (при этом длину строки компилятор…

Пример выполнения лабораторного задания № 6

Индивидуальное задание: Слова исходного предложения расположить в обратном порядке. Расположение знаков препинания не менять.

Решение предусматривает выполнение нескольких действий:

1. Вывод информации о назначении программы (заголовок программы).

2. Ввод исходного предложения.

3. Выделение из предложения слов.

4. Выделение из предложения разделительных знаков.

5. Сборка нового предложения из слов и знаков поочередно.

6. Распечатка результата.

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

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

Функция Title() – без параметров, так как только лишь выводит на экран набор строк.

Функция ввода предложения InpPredl (char predl[]) имеет один параметр – предложение, которое надо заполнить. В записи этого параметра есть сразу два момента, на которые надо обратить внимание: во-первых, в качестве параметра передается одномерный массив символов, то есть указатель (параметр переменная), во-вторых, в записи массива не указана размерность массива, а только открывающие и закрывающие квадратные скобки, так как достаточно передать только адрес начала строки.

Выделение из предложения слов и разделительных знаков реализуется одним алгоритмом, поэтому могут выполняться одной и той же функцией выделения Select(const char *predl, char m[][N],char *sel, int *n). Функция имеет четыре параметра:

1) predl – предложение, из которого идет выделение,

2) m – массив слов результата (под каждое слово предусмотрен размер в N символов),

3) sel – адрес символов, располагаемых между выделяемыми элементами,

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

Функция сборки нового предложения Constructor(char slova[][N], char razd[][N], int sl, int rz) – это действительно функция, так как возвращает указатель на первый символ полученного предложения. Назначение параметров понятно по названиям: массив слов, массив разделителей, количество слов, количество разделителей.

Вывод предложения функцией OutPredl(char *s1, char *s2) использует два параметра: исходное предложение и результат.

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

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

Теперь можете проанализировать весь текст программы:

#include <string.h>

#include <stdio.h>

#include <stdlib.h>

#include <locale.h>

#define N 20

 

// ПРЕДВАРИТЕЛЬНОЕ ОБЪЯВЛЕНИЕ ФУНКЦИЙ

// Заголовок программы

void Title();

// Ввод предложения

void InpPredl (char predl[]);

// Выделение из предложения

void Select(const char *predl, char m[][N],char *sel, int *n);

// Сборка предложения

char *Constructor(char slova[][N], char razd[][N], int sl, int rz);

// Вывод результата

void OutPredl(char *s1, char *s2);

 

inline void rus() // Русификация вывода в консольное окно

{

setlocale( LC_CTYPE, ".1251" );

setlocale( LC_MONETARY, ".1251" );

}

 

// ОСНОВНАЯ ФУНКЦИЯ

int main()

{

// ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ

char predl[80]; // Введенное предложение

char *res; // Результирующее предложение

char slova[N][N]; // Массив слов в предложении

char razd [N][N]; // Массив разделителей в предложении

int sl=-1, rz=-1; // Счетчики слов и разделителей

char buk[80]; // все буквы алфавита

char *bs="йцукенгшщзхъфывапролджэячсмитьбю";// Буквы строчные

char *bz ="ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ";/* заглавные */

char *r="`!;:,.?- _"; // Разделительные знаки

//ВЫЗОВ ФУНКЦИЙ НА ИСПОЛНЕНИЕ

rus();

// Заголовок программы

Title ();

// Ввод предложения

InpPredl (predl);

// Выделение из предложения слов

Select (predl, slova, r, &sl);

// Выделение из предложения разделителей

strcpy(buk,"");

strcat (buk, bs);

strcat (buk, bz);

Select (predl, razd, buk, &rz);

// Сборка предложения

res = Constructor(slova, razd, sl, rz);

// Вывод результата

OutPredl (predl, res);

free (res);

return 0;

}

 

 

// ОПИСАНИЕ ИСПОЛЬЗУЕМЫХ ФУНКЦИЙ

// Заголовок программы

void Title()

{

puts (" Лабораторное задание по теме № 6n");

puts (" Во введенном предложении расположите слова");

puts (" в обратной последовательности.");

puts(" Порядок следования знаков препинания не менять.");

puts(" В предложении используются русские буквы и знаки. n");

}

// Ввод предложения

void InpPredl(char *s)

{

puts("Введите предложение n");

strcpy (s,"Верите ли вы, что задача решена?");

// gets (s);

}

// Вывод результата

void OutPredl (char *s1, char *s2)

{

puts ("Исходное предложение");

puts (s1);

puts (" Результат ");

puts (s2);

}

// Выделение из предложения

void Select(const char *predl, char m[][N], char *sel, int *n)

{

char *p, *s;

 

s=strdup (predl); // Сделать копию исходного предложения

// так как передается константа, strtok требует

// внесения изменений при своей работе

p = strtok (s, sel);

while (p)

{

(*n)++;

strcpy (m[*n],p);

p = strtok (NULL, sel);

}

free (s);

}

// Сборка предложения

char *Constructor(char slova[][N], char razd[][N], int sl, int rz)

{

int i, j;

char res[80];

char *s;

*res=0; // Начальное значение результата

i = sl;

j=-1;

while ((i>=0)||(j<=rz))

{

if ((i>=0)) strcat (res, slova[i]); // Добавление слова

i--;

j++;

if ((j<=rz)) strcat (res, razd[j]); // Добавление знаков

}

s = strdup (res);

return s;

}

 

 

Варианты заданий

1. В двух предложениях найти и распечатать совпадающие слова.

2. В предложении найти слово, состоящее из наибольшего количества гласных букв.

3. Распечатать слова, из которых состоит предложение, в порядке возрастания длины слова.

4. В предложении найти все однокоренные слова. Корень слова также задан с клавиатуры.

5. Удалить в предложении все повторные вхождения слов и распечатать получившееся предложение.

6. Найти в предложении слово, состоящее из наибольшего количества разных букв.

7. Выделить из предложения слова, содержащие две или более одинаковые буквы.

8. Напечатать слова, входящие в предложение, в алфавитном порядке.

9. Удалить из предложения все предлоги. Список предлогов задан во втором предложении.

10. Все буквы каждого слова в предложении записать в обратном порядке и распечатать получившееся предложение.

11. Во всех словах предложения удалить гласные буквы и распечатать получившееся предложение.

12. Дополнить каждое слово предложения пробелами так, чтобы его длина была равна длине самого длинного слова. Распечатать получившееся предложение.

13. Исходное предложение, состоящее из четырех слов, каждое из которых состоит из четырех букв, например, "Было утро, рано петь." распечатать в виде: Бурп ытае, лрнт оооь. Первое слово состоит из первых букв слов, второе - из вторых, и так далее.

14. С клавиатуры ввести две строки. Одна строка - предложение на русском языке, а вторая (под ней) состоит из пробелов и знаков "минус" или "равно" (будем считать это подчеркиванием). Выделить и распечатать подчеркнутые слова. Например, надо выделить слова «мест» и «слагаемых» в предложении:

От перемены мест слагаемых сумма не меняется.

----- ========

15. Проверьте на совпадение два предложения. Количеством пробелов между словами пренебрегать. Знаки препинания - учитывать.

16. Удалить в предложении все слова, имеющие символы цифр и распечатать получившееся предложение.

17. Предложение состоит из записи символов цифр, например:

123434 53423 2344 6564.

Распечатать слова в порядке возрастания.

 

Контрольные вопросы к теме № 6

1. Представление строк в языке Си.

2. Примеры инициализации строк в теле программы.

3. Библиотечные функции языка Си для обработки строк.

4. Библиотечные функции ввода-вывода строк.


Тема №7. Двумерные массивы. Файловый (бинарный) ввод-вывод

Задание:

Задание состоит из нескольких пунктов:

1. Заполнить двумерный массив (каждая строка массива заполняется в соответствии с заданием по теме №5).

2. Распечатать содержимое массива в виде прямоугольной матрицы.

3. Сохранить двумерный массив в бинарный файл.

4. Считать содержимое бинарного файла в другой двумерный массив.

5. Распечатать содержимое нового массива в виде прямоугольной матрицы.

6. Выполнить над каждой строкой нового двумерного массива действия, предусмотренные по теме №5.

7. Распечатать преобразованный двумерный массив.

Краткая теоретическая справка

int x[5][7]; // Двумерный массив целых чисел (5 строк по 7 элементов) Для использования одного элемента двумерного массива необходимо указать оба… x[2][4] = 5; // Четвертому элементу второй строки присваивается 5

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

Примеры функций рассмотрим в двух частях: в первой части будем использовать «традиционную» форму обращения к элементу двумерного массива (используя квадратные скобки), а во второй части – «комбинированную» (обращение через адреса и традиционно).

Часть первая («традиционная» форма использования обращения к элементу двумерного массива).

Двумерный массив декларируем в виде

int x[R][C];

где константами R и C обозначим количество строк и столбцов массива, соответственно.

// 1. Заполнение двумерного массива

// m – адрес начала двумерного массива,

// Nr - количество строк в двумерном массиве

void Filling_2 ( int m[][C], int Nr, int range1, int range2)

{ int i;

for ( i = 0; i<Nr; i++ ) //Для каждой строки массива…

{ //… заполняем одномерный массив

Filling(m[i], C, range1, range2);

}

}

Обратите внимание на то, что при передаче в качестве параметра массива m количество строк не указано. Но при этом обязательным будет указание размера одно строки ([C]). Другая особенность данного примера состоит в том, что при вызове на исполнение функции заполнения одномерного массива, в нее в качестве параметра передается одна строка двумерного массива (m[i]).

// 2. Распечатка двумерного массива

// m - адрес начала двумерного массива,

//Nr - окличество строк

void Print_2 ( int m[][C], int Nr)

{ int i;

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

{

Print (m[i],С);

printf("n");

}

}

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

// 3. Сохранение массива в файл

// m - адрес начала двумерного массива,

// Nr - окличество строк

// Name - имя файла

void Save( int m[][C], int Nr, char Name[])

{ FILE *out; int i;

// Открыть файл для записи.

out = fopen(Name,"wb");

// Проверить: файл открыт?

if (out != NULL)

{ // Для каждой строки двуменого массива...

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

// ... записать строку массива в файл.

fwrite ( m[i], 1, C*sizeof(int), out );

// Закрыть файл.

fclose(out);

}

else puts("nОшибка открытия файла для записи");

}

Для сохранения массива в файл потребуется файловая переменная out, являющаяся указателем на библиотечную структуру FILE.

Файл открывается для записи функцией fopen, в которую в качестве параметров передаются две строки: первая – имя файла, вторая – режим доступа к файлу. В строке режима доступа к файлу две буквы: w – означает запись (write), b – тип файла (бинарный, то есть двоичный – binary). Функция fopen возвращает указатель на структуру типа FILE, если открытие файла прошло успешно, или NULL, если произошла ошибка.

Запись в файл проводится функцией fwrite. Эта функция принимает четыре параметра: первый – нетипированный указатель на блок данных (в качестве фактического параметра может быть указатель любого типа, в данном примере – это адрес начала одномерного массива), второй параметр – количество блоков данных для записи, третий – размер одного блока данных (в примере вычисляется по размеру одномерного массива), четвертый – файловая переменная.

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

// 4. Загрузка массива из файла

// m - адрес начала двумерного массива,

// Nr - окличество строк

// Name - имя файла

void Load( int m[][C], int Nr, char Name[])

{ FILE *in; int i;

// Открыть файл для записи.

in = fopen(Name,"rb");

// Проверить: файл открыт?

if (in!=NULL)

{ // Для каждой строки двуменого массива...

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

// ... записать строку массива в файл.

fread(m[i], 1, C*sizeof(int), in);

// Закрыть файл.

fclose(in);

}

else puts("nОшибка открытия файла для чтения");

}

При чтении данных из файла меняется режим доступа к файлу (rb) и используется функция чтения из файла fread, параметры которой полностью совпадают с параметрами функции fwrite.

Для проверки работоспособности приведенных функций была использована приведенная ниже программа. Не забудьте после главной функции добавить представленные ранее функции Filling_2, Print_2, Save и Load.

#include <stdio.h>

#include <stdlib.h>

#include <locale.h>

#include "5.h"

#define R 5

#define C 7

// Предварительное описание функций

void Filling_2(int m[][C], int Nr, int range1, int range2);

void Print_2(int m[][C], int Nr);

void Save( int m[][C], int Nr, char Name[]);

void Load( int m[][C], int Nr, char Name[]);

// Главная функция

int main()

{

int m[R][C], x[R][C];

Randomize();

Title();

puts("nЗаполнение двумерного массива");

Filling_2(m,R,-30,70);

puts("nРаспечатка двумерного массиваn");

Print_2 (m,R);

puts("nСохранить содержимое массива в файлn");

Save(m, R, "7.dat");

puts("nЗагрузить данные из файла в новый массивn");

Load(x, R, "7.dat");

puts("nРаспечатка нового двумерного массиваn");

Print_2 (x,R);

return 0;

}

Обратите внимание на то, что функции Filling_2, Print_2, Save и Load могут быть использованы для двумерных массивов с произвольным количеством строк, но каждая строка должна быть строго определенной длины. В этом состоит основной недостаток «традиционной» формы обращения к двумерному массиву.

Часть вторая (обращение к двумерному массиву через указатели).

Двумерный массив декларируем как указатель на указатель

int **x;

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

// 1. Инициализация массива

// Nr - количество строк, Nc - количество столбцов

int ** Init(int Nr, int Nc)

{ int i; int **x;

// Задать массив указателей на строки

x = (int**)calloc ( Nr, sizeof(int*));

// Задать указатели на элементы в строке

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

x[i]=(int *)calloc(Nc,sizeof(int));

return x;

}

Инициализация проводится функцией calloc, в которой первым параметром указывается количество элементов, а вторым – размер одного элемента. Как видно из текста программы, сначала задается массив указателей на строки, а потом в каждый из указателей помещаются адреса элементов массива.

// 2. Заполнение массива

// Nr - количество строк, Nc - количество столбцов

void Fill(int **x, int Nr, int Nc)

{ int i,j; static int k=1;

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

{

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

x[i][j]=k++;

}

}

Заполнение массива проводим целыми числами, начиная с единицы. Обратите внимание на то, что для переменной k выбран статический класс памяти (инициализация значением 1 будет сделана только при первом вызове функции на исполнение), а также на то, что к элементам массива, на который указывает x, можно обращаться «традиционным» способом.

Ниже приведены функции для распечатки двумерного массива и работы с бинарным файлом. Распечатка проводится циклом в цикле, а сохранение и загрузка данных при работе с файлом – построчно.

// 3. Распечатка массива

// Nr - количество строк, Nc - количество столбцов

void Print (int **x, int Nr, int Nc)

{ int i,j;

printf("n");

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

{

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

printf("%4d",x[i][j]);

printf("n");

printf("n");

}

printf("n");

}

// 4. Сохранение массива в файл

// Nr - количество строк, Nc - количество столбцов

// Name - имя файла

void Save( int **x, int Nr, int Nc, char Name[])

{ FILE *out; int i;

out = fopen(Name,"wb");

if (out != NULL)

{

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

fwrite (x[i], 1, Nc*sizeof(int), out);

fclose(out);

}

else puts("nОшибка открытия файла для записи");

}

// 5. Загрузка массива из файла

// Nr - количество строк, Nc - количество столбцов

// Name - имя файла

void Load( int **x, int Nr, int Nc, char Name[])

{ FILE *in; int i;

in = fopen (Name,"rb");

if (in != NULL)

{

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

fread ( x[i], 1, Nc*sizeof(int), in);

fclose(in);

}

else puts("nОшибка открытия файла для чтения");

}

Проверка работоспособности функций проводилась приведенной ниже программой. Можете заметить, что функции применимы как для массива размером 4х5 (массивы x и x1), так и для массива размером 2х3 (массивы y и y1).

#include <stdio.h>

#include <stdlib.h>

#include <locale.h>

int ** Init(int Nr, int Nc);

void Fill(int **x, int Nr, int Nc);

void Print (int **x, int Nr, int Nc);

void Save( int **x, int Nr, int Nc, char Name[]);

void Load( int **x, int Nr, int Nc, char Name[]);

inline void Rus() // Русификация вывода в консольное окно

{ setlocale( LC_CTYPE, ".1251" ); }

int main()

{ int **x,**y,**x1,**y1;

Rus();

puts("nИнициализация массива xn");

x = Init (4, 5);

puts("nЗаполнение массива xn");

Fill(x,4,5);

puts("nРаспечатка массива xn");

Print(x,4,5);

puts("nИнициализация массива yn");

y = Init (2, 3);

puts("nЗаполнение массива yn");

Fill(y,2,3);

puts("nРаспечатка массива yn");

Print(y,2,3);

puts("Сохранение массива x в файл");

Save(x,4,5,"x.dat");

puts("nИнициализация массива x1n");

x1 = Init (4, 5);

puts("Загрузка массива x1 из файла");

Load(x1,4,5,"x.dat");

puts("nРаспечатка массива x1n");

Print(x1,4,5);

puts("Сохранение массива y в файл");

Save(y,2,3,"y.dat");

puts("nИнициализация массива y1n");

y1 = Init (2, 3);

puts("Загрузка массива y1 из файла");

Load(y1,2,3,"y.dat");

puts("nРаспечатка массива y1n");

Print(y1,2,3);

return 0;

}

Естественно, что при использовании приведенных функций нельзя путать размерность массивов. То есть, если массив x был инициализирован размером 4х5, то в нем нельзя использовать количество строк более 4 и столбцов более 5.

Чтобы было меньше ошибок можно ввести свой тип данных, содержащий в одной структуре не только указатель на указатель, например, такой

typedef struct {int **x; int Nr; int Nc;} TArray;

В этой записи слово typedef зарезервировано для обозначения того, что после его будет описание тип. Введенный тип данных представляет собой структуру (обозначено зарезервированным словом struct), а в фигурных скобках указано, что структура содержит три поля x – указатель на указатель на данные типа int, Nr и Nc – поля целого типа, для хранения информации о количестве строк и столбцов двумерного массива соответственно. TArray – имя типа данных.

Теперь, если задать переменную типа TArray, например,

TArray m;

то можно обратиться отдельно к каждому из полей (x,Nr,Nc) структуры типа TArray, записывая после имени переменной (в данном примере m) знак точка, а потом идентификатор поля (x,Nr,Nc), напрмер,

m.Nr = 4;

m.Nc = 5;

m.x = (int**) calloc ( m.Nr, sizeof(int*) );

Теперь функции для работы с двумерным массивом можно переписать к следующему виду:

// 1. Инициализация массива

// r - количество строк, c - количество столбцов

void Init ( TArray *m, int r, int c)

{ int i;

// Определить размеры массива

(*m).Nr = r; (*m).Nc = c;

// Задать массив указателей на строки

(*m).x = (int**)calloc ( r, sizeof(int*));

// Задать указатели на элементы в строке

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

(*m).x[i]=(int *)calloc ( c, sizeof(int));

}

Обратите внимание на то, что параметр m типа (TArray *) – это параметр –переменная (передается в функцию адресом). Поэтому при обращении к полям структуры используется разыменование, например, (*m).Nr = r. Аналогично используется параметр-переменная при заполнении массива и загрузке массива из файла. При распечатке и сохранении массива в файл можно использовать параметр-значение.

// 2. Заполнение массива

// Nr - количество строк, Nc - количество столбцов

void Fill ( TArray *m)

{ int i, j; static int k=1;

for ( i=0; i<(*m).Nr; i++)

{

for ( j=0; j<(*m).Nc; j++)

(*m).x[i][j] = k++;

}

}

// 3. Распечатка массива

// Nr - количество строк, Nc - количество столбцов

void Print (TArray m)

{ int i, j;

printf("n");

for ( i=0; i<m.Nr; i++)

{

for ( j=0; j<m.Nc; j++)

printf("%4d",m.x[i][j]);

printf("n");

printf("n");

}

printf("n");

}

// 4. Сохранение массива в файл

// Nr - количество строк, Nc - количество столбцов

// Name - имя файла

void Save( TArray m, char Name[])

{ FILE *out; int i;

out = fopen(Name,"wb");

if (out != NULL)

{

for ( i=0; i<m.Nr; i++)

fwrite (m.x[i], 1, m.Nc*sizeof(int), out);

fclose(out);

}

else puts("nОшибка открытия файла для записи");

}

// 5. Загрузка массива из файла

// Nr - количество строк, Nc - количество столбцов

// Name - имя файла

void Load( TArray *m, char Name[])

{ FILE *in; int i;

in = fopen (Name,"rb");

if (in != NULL)

{

for ( i=0; i<(*m).Nr; i++)

fread ( (*m).x[i], 1, (*m).Nc*sizeof(int), in);

fclose(in);

}

else puts("nОшибка открытия файла для чтения");

}

В главной части программы размер двумерного массива задается только при инициализации. Не забудьте также в функции Init, Fill и Load передавать в качестве фактического параметра адрес размещения переменной в оперативной памяти.

#include <stdio.h>

#include <stdlib.h>

#include <locale.h>

typedef struct {int **x; int Nr; int Nc;} TArray;

void Init(TArray *m, int r, int c);

void Fill(TArray *m);

void Print (TArray m);

void Save( TArray m, char Name[]);

void Load( TArray *m, char Name[]);

inline void Rus() // Русификация вывода в консольное окно

{ setlocale( LC_CTYPE, ".1251" ); }

int main()

{ TArray x, y, x1, y1;

Rus();

puts("nИнициализация массива xn");

Init (&x,4, 5);

puts("nЗаполнение массива xn");

Fill(&x);

puts("nРаспечатка массива xn");

Print(x);

puts("nИнициализация массива yn");

Init (&y,2, 3);

puts("nЗаполнение массива yn");

Fill(&y);

puts("nРаспечатка массива yn");

Print(y);

puts("Сохранение массива x в файл");

Save(x,"x.dat");

puts("nИнициализация массива x1n");

Init (&x1,4, 5);

puts("Загрузка массива x1 из файла");

Load(&x1,"x.dat");

puts("nРаспечатка массива x1n");

Print(x1);

puts("Сохранение массива y в файл");

Save(y,"y.dat");

puts("nИнициализация массива y1n");

Init (&y1,2, 3);

puts("Загрузка массива y1 из файла");

Load(&y1,"y.dat");

puts("nРаспечатка массива y1n");

Print(y1);

return 0;

}


Тема №8. Односвязные списки. Файловый (текстовый) ввод-вывод

Задание:

1. Замените в работе по теме №6 (строки) одномерные массивы на односвязные списки.

2. Ввод исходного предложения проведите из файла, а результаты работы программы сохраните в файл.

Краткая теоретическая справка и пример решения задачи

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

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

Для описания данной структуры в языке Си обычно используют два варианта записи. В первом варианте, представленном ниже, вводится только тип структуры без определения типа данных «указатель на структуру» (пример в проекте 8_1).

typedef struct TList { // структура типа TList

char D[80]; // информационное поле структуры (данные)

struct TList *P; // адресное поле структуры (адрес)

} TList;

Обычно только первый элемент списка определяется статической переменной, а все остальные элементы создаются динамически. Например, такими переменными в главной функции будут переменные под именем slova и razd.

struct TList *slova = NULL; // Первый элемент списка слов

struct TList *razd = NULL; // Первый элемент списка разделителей

 

Для добавления элемента списка в начало списка введем функцию AddFirst.

// 1. Функция добавления элемента в начало списка

struct TList * AddFirst(struct TList* First, char *s)

{ struct TList *tmp; // временная переменная

tmp = (struct TList*)malloc(sizeof(struct TList));

strcpy(tmp->D, s); // заполнить поле данных

tmp->P = First; // поставить перед первым

return tmp; // вернуть значение

}

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

Теперь можно изменить функцию выделения из предложения слов или разделительных знаков (обратите внимание на список передаваемых в функцию параметров).

// 2. Выделение из предложения (слов или разделителей)

struct TList* Select(const char *predl, struct TList *First, char *sel)

{ char *p, *s;

s=strdup (predl); // Сделать копию исходного предложения

p = strtok (s, sel);

while (p)

{

First = AddFirst(First,p); // добавить элемент в список

p = strtok (NULL, sel);

}

free (s);

return First;

}

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

// 3. Распечатать список

void Print (struct TList *First)

{

while (First != NULL)

{

puts(First->D); // вывод данных

First = First->P; //перевод указателя на следующий элемент

}

}

Распечатав односвязный список, можете заметить, что элементы в нем располагается в порядке, обратном вводимым данным. Если требуется восстановить исходный порядок, достаточно воспользоваться функцией Reverse, которая создает новый список, элементы которого будут добавляться в новый список также функцией AddFirst, то есть в обратной последовательности. Обратите внимание на использование статической переменной

// 4. Сделать список в обратной последовательности

struct TList * Reverse(struct TList * First)

{ static struct TList * tmp = NULL;

while (First!=NULL)

{

tmp = AddFirst(tmp,First->D);

First = First->P;

}

return tmp;

}

Аналогично тому, что делалось в примере к работе по теме №6, надо собрать результирующее предложение таким образом, чтобы слова следовали в обратной последовательности, а разделительные знаки – в прямой.

// 5. Сборка предложения

char *Constructor(struct TList * slova, struct TList * razd)

{

char res[80];

char *s;

*res=0; // Начальное значение результата пустое

while ((slova!=NULL)&&(razd!=NULL)) // пока есть слова и разделители

{

if (slova!=NULL)

{

strcat (res, slova->D); // Добавление слова

slova = slova->P;

}

if (razd!=NULL)

{

strcat (res, razd->D); // Добавление знаков

razd = razd->P;

}

}

s = strdup (res);

return s;

}

 

По завершении работы со списками надо их удалить. Удаление проводится поочередно, начиная с головы списка (с первого элемента).

// 6. Удаление всего списка

struct TList* FreeList(struct TList *First)

{ struct TList * tmp;

while (First != NULL)

{

tmp = First; // запомнить указатель на первый элемент

First = First->P; // переметить укзатель на следующий элемент

free(tmp); // удалить элемент

}

return NULL;

}

 

 

Оглавление

Тема №1. Функции стандартного ввода–вывода, вычисление математических функций. 2

Пример выполнения задания по теме № 1. 3

Формулы для решения задач. 4

Варианты заданий. 6

Контрольные вопросы по теме № 1. 6

Тема №2. Ветвление программы (использование операторов ветвления и переключателя switch) 8

Варианты заданий. 8

Пример выполнения лабораторного задания № 2. 9

Контрольные вопросы к лабораторной работе № 2. 13

Тема №3. Циклы, символьный (литерный) тип данных. 15

Примеры выполнения задания по теме №3. 15

Варианты заданий. 20

Контрольные вопросы к теме № 3. 21

Тема №4. Функции в языке Си. 22

Контрольные вопросы по теме №4. 23

Тема №5. Обработка одномерных массивов. 24

Задание: 24

Краткая теоретическая справка и рекомендации по выполнению.. 24

Примеры функций для работы с одномерными массивами. 25

Варианты заданий. 29

Контрольные вопросы по теме № 5. 32

Тема №6. Строки и использование библиотечных функций для их обработки. 33

Краткая теоретическая справка и рекомендации по выполнению.. 33

Пример выполнения лабораторного задания № 6. 37

Варианты заданий. 41

Контрольные вопросы к теме № 6. 42

Тема №7. Двумерные массивы. Файловый (бинарный) ввод-вывод. 43

Задание: 43

Краткая теоретическая справка. 43

Примеры функций для работы с двумерным массивом.. 48

Тема №8. Односвязные списки. Файловый (текстовый) ввод-вывод. 59

Задание: 59

Краткая теоретическая справка и пример решения задачи. 59

 

– Конец работы –

Используемые теги: алгоритмические, Языки, основы0.065

Если Вам нужно дополнительный материал на эту тему, или Вы не нашли то, что искали, рекомендуем воспользоваться поиском по нашей базе работ: Алгоритмические языки и основы

Что будем делать с полученным материалом:

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

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

Конспект лекций по курсу Алгоритмические языки и программирование Основы языка С++
Пермский Государственный технический университет... Кафедра информационных технологий и автоматизированных... Викентьева О Л...

Основы планирования. Теоретические основы управления проектами. Основы планирования. Планирование проекта в MS Project 7
Использованная литература В В Богданов Управление проектами в Microsoft Project Учебный курс Санкт Петербург Питер г...

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

Два объекта истории русского языка: живой язык диалектный и литературный язык
Новые общественные функции приобретает русский язык по мере сложения новой исторической общности советского народа он становится межнациональным... Современный период... Горшкова Хабургаев ИГРЯ...

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

Есть только одна раса — раса человечества, Есть только один язык — язык сердца, Есть только одна религия — религия любви
Мое отношение к религии или Что я вижу в мире Бога... Есть только одна раса раса человечества Есть только один язык язык... Есть только один Бог и Он вездесущ...

Экономические основы технологического развития тема “ Основы технологического и экономического развития”
Особенностью современного развития технологий является переход к целостным технолого-экономическим системам высокой эффективности, охватывающим… В практической деятельности экономиста и финансиста технология является… Именно за счет прибыли, полученной от своевременно и разумно вложенных в технологию средств, и достигается…

Лекция 1. Морфология – центр языкового пространства, и для того, чтобы узнать язык, надо прежде всего понять его морфологию
Введение в морфологию... Морфология центр языкового пространства и для того чтобы узнать язык надо прежде всего понять его...

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

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

0.031
Хотите получать на электронную почту самые свежие новости?
Education Insider Sample
Подпишитесь на Нашу рассылку
Наша политика приватности обеспечивает 100% безопасность и анонимность Ваших E-Mail
Реклама
Соответствующий теме материал
  • Похожее
  • По категориям
  • По работам