Учебное пособие по трём языкам C


Учебное пособие по языкам C~.

Вам проще будет найти нужное обратившись к Оглавлению.

Введение.

В 1804 году французский изобретатель Жозеф Мари Жаккар создал

"программно-управляемый" ткацкий станок. Для управления станком

использовались перфокарты, соединенные друг с другом в виде ленты.

Деревянные шпильки "читающего устройства" станка по расположению отверстий

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

получения нужного узора.

В 1890 году в США изобретателем Германом Холлеритом разработана

электромеханическая счетная машина - табулятор, управляемая перфокартами,

была использована для составления таблиц с результатами переписи населения

США. Основанная Холлеритом фирма по производству табуляторов впоследствии

превратилась в корпорацию International Business Machines (IBM).

В 1936 году двадцатипятилетний студент Кембриджского университета

англичанин Алан Тьюринг опубликовал статью "О вычислимых числах", в

которой рассматривалось гипотетическое устройство ("машина Тьюринга"),

пригодное для решения любой разрешимой математической или логической

задачи, - прообраз программируемого компьютера.

В1941 году немецкий инженер Конрад Цузе построил действующий

компьютер Z3, в котором использовалась двоичная система счисления.

Программы записывались на перфоленте.

В 1945 году в высшем техническом училище Пенсильванского университета

(США) физик Джон Мочли и инженер Проспер Экерт построили полностью

электронную машину "Эниак". Для задания программы было необходимо

вручную установить тысячи переключателей и воткнуть сотни штекеров в гнезда

контактной панели.

1 июня 1945 года был разослан отчет американского математика венгерского

происхождения Джона фон Неймана "Предварительный отчет о машине Эдвак",

содержащий концепцию хранения команд компьютера в его собственной

внутренней памяти.

21 июня 1948 года в Манчестерском университете (Великобритания) на

машине "Марк-1" выполнена первая в мире хранимая в памяти машины

программа - поиск наибольшего сомножителя заданного числа.

В 1949 году под руководством Мориса Уилкса создан компьютер "Эдсак".

Проектировщики "Эдсака" ввели систему мнемонических обозначений, где

каждая машинная команда представлялась одной заглавной буквой, и

автоматизировали настройку подпрограмм на определенное место в памяти.

Морис Уилкс назвал мнемоническую схему и библиотеку подпрограмм

собирающей системой (assembly system) - отсюда слово "ассемблер".

В 1949 году в Филадельфии (США) под руководством Джона Мочли создан

"Краткий код" - первый примитивный интерпретатор языка программирования.

В 1951 году в фирме Remington Rand американская программистка Грейс

Хоппер разработала первую транслирующую программу. Хоппер назвала ее

компилятором (compiler - компоновщик).

В 1957 году на 20-м этаже штаб-квартиры фирмы IBM на Мэдисон-авеню в

Нью-Йорке родился язык Фортран (FORmula TRANslation - трансляция формул).

Группой разработчиков руководил 30-летний математик Джон Бэкус. Фортран -

первый из "настоящих" языков высокого уровня.

В 1972 году 31-летний специалист по системному программированию из

фирмы Bell Labs Деннис Ритчи разработал язык программирования Си.

В 1984 году французский математик и саксофонист Филип Кан основывает

фирму Borland International.

Далее появился диалект языка Си фирмы Borland.

Первоначально Си был разработан как язык для программирования в

операционной системе Unix.

Вскоре он стал распространяться для программистов-практиков. В конце 70-х

были разработаны трансляторы Си для МикроЭВМ для операционной системой

РЎР /M.

После появления IBM PC стали появляться и компиляторы Си (для этого

компьютера их сейчас более 20).

Р’ 1983 Рі. Американский Рнститут Стандартов (ANSI) сформировал

Технический Комитет X3J11, для создания стандарта языка Си. Появившийся на

рынке язык Си++ корпорации Borland подчиняется большинству требований

стандарта.

По сути своей Си является языком функций. Программирование на Си,

осуществляется путем написания функций и обращения к библиотечным

функциям. Большинство функций возвращают некоторые значения, которые

могут использоваться в других операторах.

Среди множества достоинств языка Си нужно отметить основные:

- универсальность (используется почти на всех существующих ЭВМ);

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

- быстрота выполнения программ;

- гибкость языка;

- высокую структурированность.

Глава 1. Основы языка Си.

1.1. Алфавит.

Алфавит языка состоит из следующих символов:

Заглавные и строчные латинские буквы A-Z, a-z и символ подчеркивания.

Цифр от 0 до 9. Специальных символов + - * / = >

Символы пробел, табуляция, перевод строки, возврат каретки называются

пробельными.

Программа на Cи++ представляет собой последовательность ACSII-

символов, представляющих собой ее исходный текст.

1.2. Основные конструкции Си.

Рассмотрим простую программу печати на экране фразы "Привет от ЭВМ"

#include

Main()

// программа

{

Printf("Привет от ЭВМ\n");

}

Рассмотрим структуру программы

Cи– программа

# Директивы препроцессора

Main

Операторы

Функция 1( )

Операторы

Функция n ( )

Операторы

Описания

Присваивания

Функции

Управления

Пустые

Команда #include подключает файл stdio.h к нашей программе. В файле

содержится сведения о функциях ввода-вывода.

Файл с именем stdio.h содержит информацию о вводе-выводе.

Символ # указывает, что прежде чем транслировать программу необходимо

включить в нее функции из файла stdio.h - это так называемая препроцессорная

обработка, которая осуществляет некоторую предварительную обработку текста

программы перед началом компиляции.

Строка main() содержит название функции, с которой всегда начинается

программа. Пустые скобки обозначают, что эта функции, но она без параметров.

После символов // стоят комментарии (для одной строки), (комментариями

также называются символы, стоящие между /* и */).

Фигурные скобки {} отмечают начало и конец тела программы или функции.

Они также применяются для объединения нескольких операторов программы в

блок.

В строке printf ("Привет от ЭВМ\n") содержится стандартная функция печати

Си. Строка символов, заключенная в скобки (аргумент), является информацией,

передаваемой функции printf() из нашей главной функции main(). Когда

выполнение функции будет завершено, управление вернется обратно в исходную

программу. Символ \n - обозначает перевод строки на новую строку после печати.

Рассмотрим следующий пример - написать программу перевода метров в

сантиметры.

#include

#include

Main()

{

Int I;

Int J;

Int C;

Printf("M? \n");

Scanf("%d",&I);

J=100*I;

Printf(" В %d М содержится %d cm\n", I,J);

C=getch();

}

В данной программе определены две целочисленные переменные I и J.

Введена функция scanf("%d",&I); которая позволяет вводить десятичное

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

J=100*I; идет вычисление4.

Следующая строка printf(" В %d М содержится %d cm\n", I,J); печатает фразу.

На место первого %d (d- целая переменная) ставится значение I, на место второго

%d ставится значение J.

Функция getch() позволяет задержать изображение на экране и требует

любого символа, чтобы закончить работу.

Рассмотрим еще пример. Напишем функцию и вызовем ее из нашей

программы.

#include

#include

Supervisor()

{

Printf("Вы меня вызывали?\n");

}

Main()

{

Char C;

Printf("Я вызываю функцию supervisor.\n");

Supervisor();

Printf("Да. Посмотрите, кто из студентов спит и разбудите их.\n");

C=getch();

}

Вначале описываем функцию supervisor(), а затем обращаемся к ней в

основной программе по команде supervisor();. В результате получаем диалог:

- Я вызываю функцию supervisor.

- Вы меня вызывали?

- Да. Посмотрите, кто из студентов спит, и разбудите их.

1.3. Ввод-вывод.

Для решения задачи в какой-либо проблемной области необходимо написать

программу, в которой должны быть команды, позволяющие:

- выделять место для хранения данных;

- вводить исходные данных;

- обрабатывать исходные данные по алгоритму;

- выводить выходные данные.

Си содержит функции, необходимые для выполнения этих действий. Все

функции будем рассматривать на примерах и начнем с функций ввода-вывода.

1.3.1. Вывод.

Вывод осуществляется на экран, принтер, винчестер (гибкие диски), порт.

Рассмотрим функции вывода на экран.

Функция printf предназначена для этой цели. Формат:

Printf([,аргумент1],...).

Формат - это строка в двойных кавычках, которая выводится на экран.

Перед выводом printf заменяет все объекты в строке в соответствии со

спецификациями аргумента. Например, printf(" В %d М содержится %d cm\n",

I,J); %d в строке формата - это спецификация аргумента.

Спецификации аргумента начинаются с символа процента (%) и одной

буквой, обозначающей тип данных.

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

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

- %d целое число;

- %u целое число без знака;

- %ld длинное целое число;

- %p значение указателя;

- %f число с плавающей точкой;

- %e число с плавающей точкой в экспоненциальной форме;

- %c cРёРјРІРѕР»;

- %s строка;

- %x целое в шестнадцатеричном формате.

Можно задать ширину поля, например %6d -поле шириной 6.

Значение будет напечатано сдвинутым вправо (впереди пробелы), так что

общая ширина поля равна 6.

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

%8.4f - поле шириной 8, десятичная часть 4.

В конце форматной строки можно поставить знаки:

\n перевод строки;.

\f (перевод формата или очистка экрана)

\t (табуляция)

\b (забой .

Формат вывода на экран:cout0)? t*10: t-10; /* if t>0 y=t*10 else y=t-10;*/

Printf("OK %d\n",y);

}

В данном варианте вид оператора показан в комментариях.

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

анализировать переменную и в зависимости от ее значения производить те или

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

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

#include

Char A;

Main()

{

Printf("? ");

Scanf("%c",&A);

Switch (A) {

Case 'c': printf(" smoll %c\n",A); break; /* выход из блока */

Case 'F':

Case 'G': printf(" big %c\n",A);

Break;

Default: printf("Error %c\n",A);

}

}

В данном примере если введен символ с, то выполняется printf(" smoll

%c\n",A);, если вводится заглавные буквы F или G, то выполняется printf(" big

%c\n",A);, если не один из рассмотренных символов не вводится, то

выполняется printf("Error %c\n",A);.

Для повторения некоторого множества команд несколько раз можно

использовать оператор do... while. Рассмотрим пример.

#include

Main()

{

Int A;

Do {

Printf("Zifra? ");

Scanf("%d",&A);

Printf("Error %d\n",A);

} while (!(A == 9));

Printf("OK %d\n",A);

}

С клавиатуры вводится число. Выполняется оператор printf("Error %d\n",A);.

Далее идет анализ - равно число 9 или нет, если не равно, снова выполняется

тело цикла:

Printf("Zifra? ");

Scanf("%d",&A);

Printf("Error %d\n",A).

Если число равно 9, то выполняется оператор printf("OK %d\n",A); и

работа цикла заканчивается.

Главной особенностью оператора do... while является тот факт, что тело

цикла, заключенное между операторами do и while выполняется хотя бы один

раз, т.е. вначале выполняется тело цикла, а затем идет анализ условия.

Таким образом, смысл рассматриваемого оператора заключается в

следующем: "Выполняй тело цикла до тех пор, пока истинно условие".

Оператор while... в отличие от do... while вначале анализирует условие, а

затем выполняет тело цикла.

Пример.

#include

Main()

{

Int A;

A = 0;

While (A != 9)

{

Printf("Zifra? ");

Scanf("%d",&A);

Printf("Error %d\n",A);

}

Printf("OK %d\n",A);

}

В данном примере инициализирована переменная A:=0;. Это сделано,

потому что вначале идет анализ равна она 9 или нет. Если не равна, то

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

следующем:

«Пока истинно условие выполняй тело цикла».

Оператор for... используется когда известно сколько раз необходимо

выполнить тело цикла, но этот оператор горазда гибче по сравнению с Паскалем.

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

#include

Int A;

Main()

{

For (A = 1; A A;

If (A == 'y') break;

}

}

Для прерывания итерации цикла и перехода к следующей итерации

используется оператор Continue. Пример.

#include

#include

Char A;

Int I;

Main()

{

For (I = 1; I >A;

If (A == 'y') continue;

Printf("Работает %c\n",A);

}

}

Для прерывания программы также используются операторы return() и exit().

1.6. Препроцессор.

Препроцессор языка Си позволяет перед началом трансляции включать в

программу фрагменты программ, написанных отдельно от основной.

Директива #define.

Директива #define может появляться в любом месте программы, а даваемое

ею определение имеет силу от места до конца программы.

#include

#include

#define TRI 3

#define OTWET TRI*TRI

#define OT printf("ОТВЕТ равен %d.\n",OTWET)

#define jd cin >>C;

Main( )

{

Int C;

OT;

Jd;

}

После выполнения программы получится:

ОТВЕТ равен 9

В первой строке программы TRI - это макроопределение и оно равно 3, где 3 -

строка замещения.

Во второй строке макроопределение OTWET имеет строку замещения

TRI*TRI и т.д. Каждая строка состоит из трех частей. Первой стоит директива

#define, далее идет макроопределение. Макроопределение не должно содержать

внутри себя пробелы. Р, наконец, идет строка (называемая "строкой замещения"),

которую представляет макроопределение. Когда препроцессор находит в

программе одно из макроопределений, он заменяет его строкой замещения. Этот

процесс прохождения от макроопределения до заключительной строки замещения

называется "макрорасширением".

Директива #include.

Когда препроцессор "распознает" директиву #include, он ищет следующее за

ней имя файла и включает его в текущую программу. Директива бывает в двух

видах:

#include имя файла в угловых скобках

#include "my.h" имя файла в двойных кавычках

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

или нескольких стандартных системных каталогов. Кавычки говорят ему, что

сначала нужно смотреть в рабочем каталоге, а затем искать в "стандартных"

местах.

Директивы: #undef, #ifdef, #else, #endif

Эти директивы позволяют приостановить действие более ранних

определений.

Директива #undef отменяет самое последнее определение поименованного

макроопределения.

#define TRI 3

#define F 5

#undef TRI /* TRI теперь не определен */

#define F 10 /* F переопределен как 10 */

#undef F /* F снова равен 5 */

#undef F /* F теперь не определен */

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

#ifdef OTW

#include "otw.h" /* выполнится, если OTW определен */

#define ST 10

#else

#include "w.h" /* выполнится, если OTW не определен */

#define ST 20

#endif

Директива ifdef сообщает, что если последующий идентификатор OTW

определяется препроцессором, то выполняются все последующие директивы

вплоть до первого появления #else или #endif. Когда в программе есть #else, то

программа от #else до #endif будет выполняться, если идентификатор не

определен.

1.7. Программы. Функции.

Как мы рассматривали раньше, программа на Си имеет корневой сегмент,

начинающийся с директив препроцессора и ключевого слова main.

Далее идет собственно программа, начинающаяся с открывающейся

фигурной скобки { и заканчивающаяся закрывающейся фигурной скобкой }.

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

функция также начинается с директив препроцессора и имени и скобок { }.

Рассмотрим пример программы рисования лестницы.

#include

Main()

{

Printf("|----|\n");

Printf("|----|\n");

Printf("|----|\n");

}

А теперь напишем эту программу с использованием функции Lestniza.

#include

Lestniza(void)

{

Printf("|----|\n");

}

Main()

{

Lestniza();

Lestniza();

Lestniza();

}

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

Для преодоления этого недостатка переработаем программу и введем

формальные и фактические аргументы:

#include

Int C;

Lestniza(int B)/* B - формальный аргумент */

{

Int A;

For (A = 1; A elem определяет элемент, на

который выполняется ссылка. Рассмотрим предыдущий пример.

Struct Student { /* запись Student */

Char Fio[30]; /* поле записи Fio */

Int Gruppa; /* поле записи Gruppa */

}; /* конец записи */

Student *poin;

Сейчас к полям структуры мы можем обращаться несколькими способами.

Эквивалентные обращения:

Student.Gruppa=236;

Poin->Gruppa=236;

Отметим одну важную особенность указателей в Си. Транслятор

автоматически учитывает тип указателя в арифметических действиях над ним.

Например если i есть указатель на целую (т.е. двухбайтную) переменную, то

действие типа i++ означает, что указатель получает приращение не один, а два

байта, т.е. будет указывать на следующую переменную или элемент массива. По

этой причине указатель можно использовать вместо индексов массива. Например

если A - указатель на массив целого типа, то вместо A[i] можно писать *(A+i).

Более того, использование указателей вместо индексов позволяет компилятору

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

1.9. Указатели и функции.

Указатели также можно использовать в качестве формальных параметров

функции. Рассмотрим пример.

Функция swap (обмен) объявляет два формальных параметра x и y, как

указатели на данные типа int. Это означает, что функция swap работает с

адресами целых переменных (а не с их значениями). Поэтому будут обработаны

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

Функция main(), вызывает swap.

#include

Swap(int *x, int *y)

{

Int wr;

Wr = *x; *x = *y; *y =wr;

}

Main()

{

Int i,j;

I = 100;

J = 200;

Printf("Было: i=%d, j=%d\n",i,j);

Swap(&i,&j);

Printf("Стало: i =%d, j=%d\n",i,j);

}

После выполнения программы значения i и j поменяются местами.

Необходимо отметить, что хотя указатели и экономят память, но они

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

Таким образом рассмотрены основные элементы языка Си.

1.10. Файлы.

Файл - это совокупность данных, записанных на каком-либо носителе. Файл

можно создать, записать в него данные, стереть данный, обновить данные,

дополнить данными. Ввод-вывод в файл осуществляется с помощью методов

прямого или последовательного доступа.

Расмотрим сперва режим последовательного доступа.

Ввод-вывода буферизован. Это означает, что программа пишет и читает в

буфер; обмен данными между буфером и файлом происходит в случае, если

буфер полон, или произошло закрытие файла, или перед выходом из программы.

Рассмотрим пример: считать данные из одного файла и переписать в другой.

#include

Main()

{

FILE *in, *out;

Char n1[8], n2[8];

Printf("Рсходный файл\n");

Gets(n1);

Printf("Выходной файл\n");

Gets(n2);

If ((in = fopen(n1, "rt"))== NULL)

{

Printf("Не могу открыть исходный файл\n"); return 1;

}

If ((out = fopen(n2, "wt"))== NULL)

{

Printf("Не могу открыть выходной файл\n"); return 1;

}

While (!feof(in))

Fputc(fgetc(in), out);

Fclose(in);

Fclose(out);

}

Строка FILE *in, *out; определяет указатель РЅР° РґРІР° файла. РРјСЏ файла Рј.Р±.

любым- в нашем случае in - исходный файл, out - выходной.

В следующей строке char n1[8], n2[8]; определяем две переменные n1 и n2

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

входного и выходного файла и присвоить эти имена переменным n1 и n2. Прежде

чем начать работать с файлом он должен быть открыт. Для этого существует

функция fopen() в которой первый параметр содержит имя файла, а второй - вид

работы, например "rt"– читать файл.

Команда in = fopen(n1, "rt" вызовет открытие файла, запомненного в

переменной n1 на чтение, и в программе будет возвращен указатель in на этот

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

файла. Если файл не существует, то значение fp будет NULL, произойдет

выполнение fprintf(stderr, "Не могу открыть выходной файл\n"); return 1; и

программа завершит работу.

Аналогично работает функция out = fopen(n2, "wt", только теперь out -

выходной файл, а вид работы "wt" -запись в файл).

По этой команде создается файл под именем, записанным в переменной n2.

Чтение из файла осуществляется вызовом fgetc(in). Читается один символ из

файла, связанного с указателем in.

По команде fputc(fgetc(in), out); считанный символ записывается в файл out.

Для чтения информации из всего файла используется конструкция while

(!feof(in))

Fputc(fgetc(in), out);.

Функция feof(in) возвращает величину, отличную от нуля, если находится в

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

из исходного файла читаются и записываются в выходной.

Закрытие файла происходит при вызове функции fclose(). Если при этом файл

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

файлом. Связь между указателем и файлом разрывается.

Аналогично функция fgetc(string,n,fp) читает из файла, связанного с fp, строку

и помещает ее в string. Символы читаются, пока не будет получен символ '\n', или

пока не исчерпается файл, или пока не будет прочитано (n-1) символов.

Режим прямого доступа более гибок, т.к. позволяет обращаться напрямую к

любой записи файла. Минимальной записью для файла прямого доступа является

байт. Ниже будет рассмотрен случай файла прямого доступа с записью равной

байту. Такие файлы называются двоичными. Файлы прямого доступа незаменимы

при написании программ, которые должны работать с большими объемами

информации, хранящимися на внешних устройствах. В основе обработке СУБД

лежат файлы прямого доступа.

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

1). Каждая запись в файле прямого доступа имеет свой номер. Записи

нумерются от 0 до N-1, где N - количество записей в файле. Для двоичного файла

N совпадает с длиной файла в байтах. Для открытого файла одна из записей

является текущей - говорят, что указатель установлен на данную запись.

Перемещать указатель можно при помощи функции lseek.

2). При открытии (или создания файла) указатель автоматически помещается

на начало (запись 0). При выполнении операций чтения или записи указатель

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

запись.

3). Рзменить размер файла (увеличить или урезать) можно РїСЂРё помощи

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

заполненные кодами 0.

Ниже представлена программа, демонстрирующая работу с файлами.

#include

#include

#include

#include

#include

Void main()

{

Int h; /*дескриптор создаваемого файла*/

Char * s="Эта строка будет помещена в файл";

Char buf[7]; /*буфер для чтения из файла*/

_fmode=O_BINARY; /*работаем с двоичными файлами*/

If((h=creat("proba.txt",S_IREAD |S_IWRITE))==-1) /*создать файл*/

{

Printf("Не удалось открыть файл!\n");

Exit(1);

}

Write(h,s,strlen(s)); /*записать в файл строку s*/

Lseek(h,4,SEEK_SET); /*четвертый байт от начала файла*/

Read(h,buf,6); /*читать слово 'строка' (6 байт) из файла*/

Buf[6]=0; /*отмечаем конец строки*/

Close(h); /*закрыть файл*/

Printf("%s\n",buf); /*печать считанной строки*/

}

Наша программа достаточно полно прокоментирована, поэтому мы приводим

достаточно краткие пояснения. Программа создает файл прямого доступа и

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

обращение к подстроке этой строки непосредственно в файле. При разборе текста

программы обратим читателей на некоторые моменты:

1. Обработка ошибки создания файла. Действительно, открытие файла может

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

ситуации.

2. При удачном открытии файла ему отводится дескриптор (уникальное

число), по которому затем можно к файлу обращаться.

3. Наконец не забывайте, что строка только тогда станет строкой, когда в

конце стоит код \0.

В заключении нашего рассмотрения файлов отметим, что наше изложение

касалось работы с файлами в среде MS DOS. Работа с файлами в ОС Windows

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

специальных функций API (о программировании в Windows см. ниже).

1.11. Дополнительные функции Си.

1.11.1. Функции преобразования.

Рмеется переменная РЎ:

ФУНКЦРРЇ ПРОВЕРЯЕТ, ЯВЛЯЕТСЯ ЛРC

Isalpha(c) Р±СѓРєРІРѕР№

Isdigit(c) цифрой

Islower(c) строчной буквой

Isspace(c) пустым символом (пробел, табуляция или новая строка)

Isupper(c) РїСЂРѕРїРёСЃРЅРѕР№ Р±СѓРєРІРѕР№

Isalnum(c) алфавитноцифровым (буква или цифра)

Isascii(c) РєРѕРґРѕРј ASCII (0-127)

Iscntrl(c) управляющим символом

Ispunct(c) знаком пунктуации

Toupper(c) преобразует c в прописную букву

Tolower(c) преобразует c в строчную букву

Пример: преобразует букву A из прописной в строчную a.

#include

#include

Main()

{

Char Z,Y='A';

Printf("Было %c\n ",Y);

Z=tolower(Y);

Printf("Стало %c\n ",Z);

}

1.11.2. Преобразования символьных строк: atoi(), atof().

При вводе информации иногда целесообразнее ввести строку символов, а

затем преобразовать в соответствующее число.

Для этого используются функции atoi() и atof(). Первая преобразует

строку в целое, вторая - в число с плавающей точкой. Пример:

#include

#include

Main()

{

Char ch[10];

Int integ;

Puts("Введите, пожалуйста, целое");

Gets(ch);

Integ=atoi(ch);

Printf("Число было %d.\n", integ);

}

1.11.3. Функции, работающие со строками.

Strlen()- находит длину строки;

Strcat()- объединяет две строки;

Strcmp()- сравнивает содержимое строк;

Strcpy()- копирует строки.

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

#include

#include

Main()

{

Char k[60]="Есть в дожде откровенье";

Char l[20]="Потаенная нежность";

Printf("Длина 1 строки= %d\n ",strlen(k));

Strcat(k,l);

Puts(k);

}

В результате выполнения программы получится: Длина 1 строки= 24. Есть в

дожде откровенье, Потаенная нежность.

В данном примере функция strlen(k) определяет длину строки k.

Функция strcat(k,l) присоединяет к концу строки k строку l.

1.12. Особенности программирования на языке Си.

1.12.1. Модули. Многомодульное программирование.

Можулем будем называть часть программы помещенная в отдельный файл и

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

подключаемая при помощи препроцессорной команды include, согласно нашему

определению, модулем являтся не будет. Напомним читателю некоторые

стандартные положения трансляции программ:

1. Стандартный процесс трансляции состоит из двух этапов: собственно

трансляции и редактирования связей.

2. На первой стадии трансляции текстовый файл, содержащий фрагмент

программы преобразуется к объектному виду.

3. На второй стадии трансляции все объектные модули (в том числе модули,

содержащиеся в стандартных и других библиотеках) объединяются в

один исполняемый модуль. На этой стадии происходит согласование

используемых внешних переменных и внешних функций.

Ниже схематически представлен процесс трансляции.

2-й этап

1-й этап

Модуль 1 --------> Об.Мод 1

Редактиро-

Модуль 2 --------> Об.Мод 2 вание

. внешних исполняемый

. связей модуль

.

Модуль n --------> Об. Мод n

Подсоединение объектных

Библиотек

На первый взгляд кажется, что двухэтапный процесс трансляции усложняет и

замедляет разработку программного обеспечения. Однако, разбивая программу на

модули мы можем перевести их в объектный формат и далее подсоединять их

только на втором этапе трансляции, что, в конечном итоге, ускоряет процесс

трансляции. Кстати, все стандартные функции, которыми Вы пользуетесь в своих

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

Описание же библиотечных функций содержится в H-файлах. Заметим, что при

любом количестве модулей один и только один будет содержать функцию main.

Этот модуль мы будем называть главным.

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

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

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

командном файле (если Вы работаете ) со строковым компилятором. При этом на

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

расширением .obj, то он будет учавствовать только во второй стадии трансляции, в

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

библиотеки в проекте указывать не надо - система автоматически подключает их

на втором этапе трансляции.

При разработке программного обеспечения разбиение на модули

осуществляется тематически. Например, в один модуль помещаются все функции

работающие с файлами, во второй - функции, осуществляющие математические

расчеты и т.д.

Заканчивая общетеоретическое рассмотрение модульного программирования

заметим, что в нем имеется еще один положительный момент. Дело в том, что

двух-этапный процесс трансляции и структура объектных файлов являются

стандартом для многих трансляторов с языков высокого уровня, а также

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

были написаны на разных языках. Ниже нами будет приведен пример

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

Приведем пример двухмодульной программы.

/*Модуль 1, главный*/

#include

Extern int min(int, int, int); /*находит минимальное значение из 3*/

Extern int max(int, int, int); /*находит максималное значение из 3*/

Void main ()

{

Int a,b,c;

A=2; b=10; c=14;

/*напечатать произведение минимального и максимального числа*/

Printf("%d\n", max(a,b,c)*min(a,b,c)); /*ответ 28*/

}

/*Модуль 2*/

#include

Extern int min(int, int, int); //находит минимальное значение из 3

Extern int max(int, int, int); //находит максималное значение из 3

Int max(int a1, int b1, int c1)

{

If(a1>b1)

{

If(c1>a1)return c1; else return a1;

}

Else

{

If(b1>c1)return b1; else return c1;

}

}

Int min(int a1, int b1, int c1)

{

If(a1