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

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

Общая характеристика языка Си в сравнении с другими процедурными языками

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

Общая характеристика языка Си в сравнении с другими процедурными языками.

В 1973 году Д. Ритчи разработал операционную систему “UNIX” на языке Си. Это был первый случай разработки операционной системы на языке высокого… В 1980 году Б. Страуструп разработал объектно-ориентированное расширение языка… В алфавит языка программирования Си включаются латинские буквы (прописные и строчные), цифры и некоторые специальные…

Основные типы данных, переменные и константы. Препроцессор языка Си.

В алфавит языка программирования Си включаются латинские буквы (прописные и строчные), цифры и некоторые специальные знаки: скобки круглые “(“ и “)”… Кроме одиночных символов, в алфавит языка входят пары символов (лексемы):… Ключевыми (зарезервированными) словами языка являются слова: “for”, “while”, “if”, “else”, “switch”, “case” и другие,…

Операции языка Си. Преобразование типов данных

Операции языка Си

 

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

 

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

Таблица 2

Знак операции Назначение операции

( ) Вызов функции

[ ] Выделение элемента массива

. Выделение элемента записи

-> Выделение элемента записи

! Логическое отрицание

~ Поразрядное отрицание

- Изменение знака

++ Увеличение на единицу

-- Уменьшение на единицу

& Взятие адреса

* Обращение по адресу

(тип) Преобразование типа (т.е. (float) a)

sizeof( ) Определение размера в байтах

* Умножение

/ Деление

% Определение остатка от деления

+ Сложение

- Вычитание

<< Сдвиг влево

>> Сдвиг вправо

< Меньше, чем

<= Меньше или равно

> Больше, чем

>= Больше или равно

= = Равно

!= Не равно

& Поразрядное логическое "И"

^ Поразрядное исключающее "ИЛИ"

| Поразрядное логическое "ИЛИ"

&& Логическое "И"

|| Логическое "ИЛИ"

?: Условная (тернарная) операция

= Присваивание

+=, - =, *=, /=, %=, <<=,

>>=, &=, |=, ^= Составные операции присваивания (например, а *= b

(т.е. a = a * b) и т.д.)

, Операция запятая

 

 

Для исключения путаницы в понятиях "операция" и "оператор", отметим, что оператор - это наименьшая исполняемая единица программы. Различают операторы выражения, действие которых состоит в вычислении заданных выражений (например: a = sin(b)+c; j++;), операторы объявления, составные операторы, пустые операторы, операторы метки, цикла и т.д. Для обозначения конца оператора в языке Си используется точка с запятой. Что касается составного оператора (или блока), представляющего собой набор логически связанных операторов, помещенных между открывающей ({) и закрывающей (}) фигурными скобками ("операторными скобками"), то за ним точка с запятой не ставится. Отметим, что блок отличается от составного оператора наличием определений в теле блока.

 

Охарактеризуем основные операции языка Си. Сначала рассмотрим одну из них - операцию присваивания (=). Выражение вида

х = у;

 

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

x = y = z = 100;

 

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

 

Арифметические операции.

Логические операции и операции отношения.

Операции с битами.

 

Арифметические операции задаются следующими символами (табл. 2): +, -, *, /, %. Последнюю из них нельзя применять к переменным вещественного типа. Например:

a = b + c;

x = y - z;

r = t * v;

s = k / l;

p = q % w;

 

Логические операции отношения задаются следующими символами (см. табл. 2): && ("И"), || ("ИЛИ"), ! ("НЕ"), >, >=, <, <= , = = (равно), != (не равно). Традиционно эти операции должны давать одно из двух значений: истину или ложь. В языке Си принято следующее правило: истина - это любое ненулевое значение; ложь - это нулевое значение. Выражения, использующие логические операции и операции отношения, возвращают 0 для ложного значения и 1 для истинного. Ниже приводится таблица истинности для логических операций.

 

 

Таблица 3

x y x&&y x||y !x

0 0 0 0 1

0 1 0 1 1

1 0 0 1 0

1 1 1 1 0

Битовые операции можно применять к переменным, имеющим типы int, char, а также их вариантам (например, long int). Их нельзя применять к переменным типов float, double, void (или более сложных типов). Эти операции задаются следующими символами: ~ (поразрядное отрицание), << (сдвиг влево), >> (сдвиг вправо), & (поразрядное "И"), ^ (поразрядное исключающее "ИЛИ"), | (поразрядное "ИЛИ").

 

Примеры: если a = 0000 1111 и b = 1000 1000, то

~a = 1111 0000,

a << 1 = 0001 1110,

a >> 1 = 0000 0111,

a & b = 0000 1000,

a ^ b = 1000 0111,

a | b = 1000 1111.

 

В языке предусмотрены две нетрадиционные операции инкремента (++) и декремента (--). Они предназначены для увеличения и уменьшения на единицу значения операнда. Операции ++ и -- можно записывать как перед операндом, так и после него. В первом случае (++n или --n) значение операнда (n) изменяется перед его использованием в соответствующем выражении, а во втором (n++ или n--) - после его использования

Преобразование типов

 

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

Если один из операндов в выражении имеет тип long double, то остальные тоже преобразуются к типу long double.

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

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

В противном случае, если один из операндов в выражении имеет тип unsigned long, то остальные тоже преобразуются к типу unsigned long.

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

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

В противном случае все операнды преобразуются к типу int. При этом тип char преобразуется в int со знаком; тип unsigned char в int, у которого старший байт всегда нулевой; тип signed char в int, у которого в знаковый разряд передается знак из сhar; тип short в int (знаковый или беззнаковый).

 

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

 

В языке Си можно явно указать тип любого выражения. Для этого используется операция преобразования ("приведения") типа. Она применяется следующим образом:

(тип) выражение

 

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

 

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

int a = 30000;

float b;

........

b = (float) a * 12;

 

(переменная a целого типа явно преобразована к типу float; если этого не сделать, то результат будет потерян, т.к. a * 12 > 32767).

 

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

 

 

Ввод-вывод чисел, символов и строк на консоль. Переключение ввода-вывода, работа с файлами.

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

Оператор ветвления, многовариантный выбор.

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

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

Самая простейшая форма оператора ветвления if представлена следующей синтаксической конструкцией:

if (ВЫРАЖЕНИЕ) БЛОК

Ее семантика такова — если ВЫРАЖЕНИЕ истинно, то выполняются операторы блока БЛОК, в противном случае он просто пропускается, например:

if ( $var == "print" ) {

print "Переменная $text = $text";

}

ВНИМАНИЕ Еще раз напомним читателю тот факт, что все составные операторы определяются в терминах блоков, задаваемых с помощью фигурных скобок, поэтому даже если в блоке содержится один оператор, он должен быть заключен в фигурные скобки. Такой синтаксис составных операторов Perl может оказаться не совсем привычным для программистов на языке С, в котором фигурные скобки в случае одного оператора в блоке не обязательны.

Обычно выражение условия представляет собой сложное выражение, составленное из операций отношения, связанных логическими операциями. Однако в Perl в качестве выражения-условия операторов if можно использовать любое выражение, а не только булево, возвращающее «истину» или «ложь». Результат вычисления такого «выражения-условия» в этих операторах просто интерпретируется в булевом контексте по следующей схеме: если вычисленное значение равно 0, "0" или пустой строке "", то оно трактуется как «ложь», иначе — «истина».

В связи со сказанным мы можем написать следующий оператор, который напечатает введенную пользователем строку, если только она не является пустой или состоящей из одного нуля (только строка "0" трактуется как «ложь»):

if (substr $var = <>, 0, length($var)-l) {

print "Ввели $var";

}

Интерес здесь представляет выражение-условие. Функция substr( ) выделяет из первого строкового параметра, начиная с позиции, определяемой вторым параметром, подстроку длины, определяемой третьим параметром. Первым параметром этой функции в нашем случае является введенная пользователем строка. Из нее, начиная с самого первого символа, выделяется подстрока на единицу меньшей длины, чем ввел пользователь. Такие действия необходимы для исключения из переменной $var символа перехода на новую строку, который автоматически включается в нее при вводе со стандартного устройства ввода (операция <>), когда пользователь завершает ввод нажатием клавиши Enter, Результатом выполнения указанной операции будет именно та последовательность символов, которую вводил пользователь, хотя в самой переменной $var символ перехода на новую строку будет сохранен. В этом можно убедиться, добавив в блок еще один оператор печати. Его вывод будет осуществляться уже на новой строке после вывода предыдущего оператора print.

Вторая форма оператора if используется, когда необходимо выполнить одну группу операторов (БЛОК1) в случае истинности некоторого выражения (ВЫРАЖЕНИЕ), а в случае его ложности — другую группу операторов (БЛОК2):

if (ВЫРАЖЕНИЕ) БЛОК1 else БЛОК2

По существу, первая форма оператора if эквивалентна второй форме, если БЛОК2 не содержит ни одного оператора.

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

if (ВЫРАЖЕНИЕ1) БЛОК1 [elsif (ВЫРАЖЕНИЕ2) БЛОК2] ... [else БЛОКn]

ПРИМЕЧАНИЕ Квадратные скобки используются исключительно для обозначения необязательности конструкции, а многоточие показывает, что заключенная в квадратные скобки стоящая перед ними конструкция может повторяться многократно. Таким образом, квадратные скобки не являются частью синтаксиса многовариантного оператора if.

Семантика этого оператора такова. Выполняются операторы блока БЛОК1, если истинно ВЫРАЖЕНИЕ1. Если оно ложно, то выполняются операторы блока БЛОК2 в случае истинности выражения ВЫРАЖЕНИЕ2 из конструкции elseif. Если и оно ложно, то проверяется выражение ВЫРАЖЕНИЕЗ из следующей конструкции elseif и т. д. Если ни одно из выражений-условий оператора if не истинно, то в случае наличия конструкции el se выполняются операторы ее блока, иначе выполняется следующий после оператора if оператор программы. Например, при выполнении приводимого ниже оператора многовариантного ветвления if:

if($var < 0) { # ВЫРАЖЕНИЕ1

print "Переменная отрицательна"; # БЛОК1

} elsif ( $var == 0) { # ВЫРАЖЕНИЕ2

print "Переменная равна нулю"; # БЛОК2

} else { print "Переменная положительна"; # БЛОКЗ }

сначала проверяется условие отрицательности переменной $var. Если значение переменной строго меньше нуля (ВЫРАЖЕНИЕ1), то печатается сообщение из блока БЛОК1 и оператор завершает свою работу. Если значение переменной не меньше нуля, то далее оно проверяется на равенство (ВЫРАЖЕНИЕ2), и в случае истинности выполняется оператор печати из блока операторов elsif (БЛОК2). Если проверка на равенство нулю дала ложный результат, то выполняется оператор печати из блока else (БЛОКЗ).

ПРИМЕЧАНИЕ Ключевое слово else вместе со своим блоком операторов может быть опущено.

Следует запомнить, что во многовариантном операторе if может быть сколько угодно блоков elseif, но только один или же вообще ни одного блока else.

Относительно многовариантного оператора ветвления if и оператора с блоком else языка Perl следует заметить, что, так как они определяются в терминах блоков, не возникает никакой двусмысленности при определении, какие операторы какой части оператора условия принадлежат. Блоки всегда дают нам однозначное решение.

ВНИМАНИЕ При работе с операторами ветвления важно помнить, что только один блок операторов будет выполнен – тот, для которого истинно соответствующее выражение условия.

В Perl кроме операторов ветвления if также определены операторы ветвления, в которых вместо ключевого слова if используется ключевое слово unless. В этом случае проверка выражения условия осуществляется на его ложность. Например, последний оператор if можно записать и так:

unless ($var >= 0) { # ВЫРАЖЕНИЕ1

print "Переменная отрицательна"; # БЛОК1

} elsif ($var == 0) { # ВЫРАЖЕНИЕ2

print "Переменная равна нулю"; # БЛОК2

} else {

print "Переменная положительна"; # БЛОК3

}

При этом нам пришлось заменить ВЫРАЖЕНИЕ1 на противоположное по смыслу. Подобные «замены» в выражениях условия операторов ветвления характерны при использовании вместо ключевого слова if ключевого слова unless.

ПРИМЕЧАНИЕ Все операторы могут быть вложенными, то есть в любом их блоке можно свободно использовать другие операторы ветвления.

Завершая разговор об операторах ветвления if/unless, следует сказать об использовании в них локальных лексических переменных. Если в выражении-условии объявить лексическую переменную, то она также будет видна во всех блоках оператора ветвления, включая блоки if, все elseif и else. Вне оператора ветвления, естественно, такая переменная недоступна. Например, следующий оператор if проверяет введенную пользователем строку на равенство yes или nо, сохраняя ее в локальной переменной $answer, которая доступна во всех блоках составного оператора:

if ((my $answer = <STDIN>) =~ /^yes$/i) {

chomp $answer

print "'$answer' равно 'yes'";

} elsif ($answer =~ /^no$/i) {

chomp $answer;

print "'$answer' равно 'nо'"; }

else {

die "'$answer' не равно ни 'yes', ни'nо'";

}

ПРИМЕЧАНИЕ Регулярные выражения использованного оператора if определяют, что введенная пользователем строка должна состоять либо из единственного слова yes, либо из единственного слова no, которое должно начинаться с первой позиции, на что указывает метасимвол ^, и «простираться» до конца строки, на что указывает метасимвол $. Флаг i в конце регулярного выражения определяет, что поиск соответствующего слова происходит без учета регистра, то есть заданным регулярным выражениям будут соответствовать слова yes или no, набранные как прописными, так и строчными буквами, а также в смешанном варианте.

 

 

Многовариантное ветвление — оператор switch

 

Конструкция if/else может оказаться неудобной, если вы стоите перед необходимостью сделать выбор из многих вариантов. В языке Java есть оператор switch, эквивалентный оператору switch из языков С и С++.

 

Операции отношения, логические операции.

Операции отношения

 

Операциями отношения являются => > <= <.

 

Все они имеют одинаковое старшинство. Непосредственно за ними по уровню старшинства следуют операции равенства и неравенства:

 

= = (равно), != (не равно) с одинаковым старшинством.

 

Операции отношения младше арифметических операций, так что выражения типа i < lim+3 понимаются как i < (lim+3).

 

Операция сравнения определяет некоторое выражение. Значение этого выражения равно целой 1, если условие, выраженное сравнением, выполняется и равно 0, если нет.

 

 

Логические операции

 

К логическим операциям относятся:

унарная операция логическое НЕ, ! (отрицание);

бинарная операция логическое И , && (конъюнкция);

бинарная операция логическое ИЛИ, || (дизъюнкция).

 

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

 

Операнды логических выражений вычисляются слева направо.

 

Результатом логической операции является 0 или 1 типа int.

 

Операция !операнд дает 0, если операнд ненулевой и 1 если операнд равен нулю.

 

Операция && (И-логическое, логическое умножение) дает значение 1, если оба операнда имеют ненулевое значение. Если один из операндов равен 0, то результат также равен 0. Если значение первого операнда равно 0, то второй операнд не вычисляется.

 

Операция || (ИЛИ-логическое, логическое сложение) вырабатывает значение 0, если оба операнда равны 0. Если какой-нибудь из операндов имеет ненулевое значение, то результат операции равен 1. Если первый операнд имеет ненулевое значение, то второй операнд не вычисляется.

 

По приоритету эти операции распределены так: !, &&, ||.

 

 

Циклы и другие управляющие средства.

  Существует три вида циклов: while, for и do. Цикл while имеет следующую… while (e) s;

Классы памяти и область действия. Автоматические переменные. Внешние переменные. Статические переменные. Внешние статические переменные. Регистровые переменные.

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

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

 

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

 

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

 

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

 

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

 

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

 

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

!

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

 

 

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

!

 

Явное указание памяти extern является отличительным признаком внешнего описания от внешнего определения.

 

 

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

 

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

 

^ Класс памяти позволяет установить два факта. Во-первых, определить, какие функции имеют доступ к переменной. Пределы, до которых переменная доступна, характеризуют ее область действия. Во-вторых, определить, как долго переменная находится в памяти. Теперь подробнее рассмотрим свойства каждого типа.

 

 

Автоматические переменные

 

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

 

main( )

 

{

 

auto int kat;

 

}

 

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

 

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

 

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

!

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

 

Внешние переменные

 

Переменная, описанная вне функции, является внешней.

 

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

 

Пример:

 

int global_flag;

 

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

 

Если слово extern не включено в описание внутри функции, то под этим именем создается новая автоматическая переменная. Мы можем пометить вторую переменную как автоматическую с помощью слова auto.

^ Статические переменные

 

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

 

Пример:

 

/* Статическая переменная */

 

main( )

 

{

 

int count

 

for(count = 1;count <= 3; count ++)

 

{

 

printf("Подсчет студентов %d:n", count);

 

man_woman ( );

 

}

 

}

 

man_woman( )

 

{

 

int man = 1;

 

static int woman = 1;

 

printf("юношей = %d и девушек = %dn",

 

man++, woman++);

 

}

 

Функция man_woman увеличивает каждую переменную после печати ее значения. Работа этой программы дает следующие результаты:

 

Подсчет студентов 1:

 

юношей = 1 и девушек = 1

 

Подсчет студентов 2:

 

юношей = 1 и девушек = 2

 

Подсчет студентов 3:

 

юношей = 1 и девушек = 3

 

Статическая переменная woman помнит, что ее значение было увеличено на 1, в то время как для переменной man начальное значение устанавливается каждый раз заново. Это указывает на разницу в инициализации: man инициализируется каждый раз, когда вызывается man_woman ( ), в то время как woman инициализируется только один раз при компиляции функции man_woman ( ).

^ Внешние статические переменные

 

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

^ Регистровые переменные

 

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

 

Пример:

 

main( )

 

{

 

register int pleat;

 

}

 

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

 

^ Особенности работы с языком Си. Какой класс памяти применять? Ответ на вопрос - автоматический. Этот класс памяти выбран по умолчанию. Использование внешних переменных очень соблазнительно. Если описать все переменные как внешние, то не будет забот при использовании аргументов и указателей для связи между функциями в прямом и обратном направлениях. Но тогда возникает проблема с функцией С, изменяющей переменные в функции А, а мы этого не хотели! Такая проблема значительно перевешивает кажущуюся привлекательность широкого использования внешних переменных. Одно из золотых правил программирования заключается в соблюдении принципа "необходимо знать только то, что нужно". Организуйте работу каждой функции автономно, насколько это возможно, и используйте глобальные переменные только тогда, когда это действительно необходимо!

 

Операция получения адреса & неприменима к регистровым переменным. Любые переменные в блоке, кроме формальных параметров функции, могут быть определены как статические.

 

Подведем итог.

 

^ Классы памяти, которые описываются внутри функции:

 

автоматический, продолжительность существования - временно, область действия - локальная;

 

регистровый, продолжительность существования - временно, область действия - локальная;

 

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

 

Массивы и указатели. Динамические объекты. Операции с указателями.

Массив – это упорядоченная последовательность переменных одного типа. Каждому элементу массива отводится одна ячейка памяти. Элементы одного массива занимают последовательно расположенные ячейки памяти. Все элементы имеют одно имя – имя массива и отличаются индексами – порядковыми номерами в массиве.

 

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

 

^ Определение массива в Си++

 

int a[100]; //массив из 100 элементов целого типа

 

Операция sizeof(a) даст результат 400, т. е.100 элементов по 4 байта.

 

Элементы массива всегда нумеруются с 0, (т.е. 0 1 2 ….)

 

Массивы бывают одномерные (mass_1[n]) и многомерные (mass_2[m][n]), где mass_1 и mass_2 – имена массива, а m и n – номера элементов в массиве (индексы):

 

a[0] – индекс задается как константа,

 

a[55] – индекс задается как константа,

 

a[I] – индекс задается как переменная,

 

a[2*I] – индекс задается как выражение.

 

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

 

int a[10]={1,2,3,4,5,6,7,8,9,10} ;

 

^ Сортировка массивов – это процесс перегруппировки заданного множества объектов в некотором установленном порядке.

 

Сортировки массивов подразделяются по быстродействию. Существуют простые методы сортировок, которые требуют n*n сравнений, где n – количество элементов массива и быстрые сортировки, которые требуют n*ln(n) сравнений. Простые методы удобны для объяснения принципов сортировок, т. к. имеют простые и короткие алгоритмы.

 

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

 

Простые методы подразделяются на три основные категории: сортировка методом простого включения, простого выделения, простого обмена;

 

^ Поиск в отсортированном массиве. В отсортированном массиве используется дихотомический (бинарный) поиск. При последовательном поиске требуется в среднем n/2 сравнений, где n – количество элементов в массиве. При дихотомическом поиске требуется не более m сравнений, если (n- m)-ая степень 2, если n не является степенью 2, то n

Массив делится пополам S:=(L+R)/ 2+1 и определяется в какой части массива находится нужный элемент Х. Так как массив упорядочен, то если a[S]

Указатели являются специальными объектами в программах на Си++. Указатели предназначены для хранения адресов памяти.

 

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

 

Указатели делятся на две категории: указатели на объекты и указатели на функции. Размер указателя зависит от модели памяти. Можно определить указатель на указатель: int**a;

 

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

 

Присваивание адреса существующего объекта:

 

с помощью операции получения адреса;

 

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

 

адрес присваивается в явном виде;

 

присваивание пустого значения.

 

Динамические переменные

 

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

 

Для создания динамических переменных используют операцию new, определенную в СИ++: указатель = new имя_типа[инициализатор];

 

где инициализатор – выражение в круглых скобках.

 

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

 

int*x=new int(5);

 

Для удаления динамических переменных используется операция delete, определенная в СИ++: delete указатель;

 

где указатель содержит адрес участка памяти, ранее выделенный с помощью операции new. delete x;

 

^ Одномерные массивы и указатели. При определении массива ему выделяется память. После этого имя массива воспринимается как константный указатель того типа, к которому относятся элементы массива. Исключением является использование операции sizeof (имя_массива) и операции &имя_массива. Имя массива является указателем-константой, значением которой служит адрес первого элемента массива, следовательно, к нему применимы все правила адресной арифметики, связанной с указателями. Запись имя_массива[индекс] это выражение с двумя операндами: имя массива и индекс. Имя_массива - это указатель константа, а индекс определяет смещение от начала массива. Используя указатели, обращение по индексу можно записать следующим образом: *(имя_массива+индекс).

 

^ Многомерные массивы и указатели. Многомерный массив это массив, элементами которого служат массивы. Например, массив с описанием int a[4][5] – это массив из 4 указателей типа int*, которые содержат адреса одномерных массивов из 5 целых элементов. Инициализация многомерных массивов выполняется аналогично одномерным массивам. Доступ к элементам многомерных массивов возможен и с помощью индексированных переменных и с помощью указателей.

 

^ Динамические массивы. Операция new при использовании с массивами имеет следующий формат: new тип_массива

 

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

 

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

 

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

 

Пример:

 

int *ptr, a[10];

 

ptr=&a[5];

 

ptr++; /* равно адресу элемента a[6] */

 

ptr--; /* равно адресу элемента a[5] */

 

 

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

 

Пример:

 

int *ptr1, *ptr2, a[10];

 

int i=2;

 

ptr1=a+(i+4); /* равно адресу элемента a[6] */

 

ptr2=ptr1-i; /* равно адресу элемента a[4] */

 

 

В операции вычитания могут участвовать два указателя на один и тот же тип. Результат такой операции имеет тип int и равен числу элементов исходного типа между уменьшаемым и вычитаемым, причем если первый адрес младше, то результат имеет отрицательное значение.

 

Пример:

 

int *ptr1, *ptr2, a[10];

 

int i;

 

ptr1=a+4;

 

ptr2=a+9;

 

i=ptr1-ptr2; /* равно 5 */

 

i=ptr2-ptr1; /* равно -5 */

 

 

Значения двух указателей на одинаковые типы можно сравнивать в операциях ==, !=, <, <=, >, >= при этом значения указателей рассматриваются просто как целые числа, а результат сравнения равен 0 (ложь) или 1 (истина).

 

Пример:

 

int *ptr1, *ptr2, a[10];

 

ptr1=a+5;

 

ptr2=a+7;

 

if (prt1>ptr2) a[3]=4;

 

 

В данном примере значение ptr1 меньше значения ptr2 и поэтому оператор a[3]=4 не будет выполнен.

 

 

Строковые константы, массивы символьных строк и их инициализация. Указатели и строки, ввод-вывод и обработка строк.

  Язык C поддерживает строковые константы, называемые строковыми литералами.…  

Определение структурных переменных. Доступ к компонентам структуры.

  struct имя_структуры {  

Объединения и перечисления. Указатели и структуры. Массив структур.

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

Стандартные библиотечные функции языка Си, функция генерации случайных чисел.

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

Динамические структуры данных (стек, список, дерево, граф).

Стек (англ. stack — стопка) — структура данных с методом доступа к элементам LIFO (англ. Last In — First Out, «последним пришел — первым вышел»).… В современных компьютерах стек используется для : 1размещения локальных… Всего существует 6 основных видов динамических структур данных :

Графический интерфейс пользователя (GUI). Типы данных Win32.

  В отличие от интерфейса командной строки, в ГПИ пользователь имеет…  

События и сообщения, оконная процедура, оконный класс, цикл обработки сообщений.

При создании нового сообщения необходимо выполнить следующие действия:

 

описать тип сообщения;

 

объявить номер (или индекс) сообщения;

 

объявить метод обработки нового сообщения в классе, который должен его обрабатывать;

 

инициализировать (передать) сообщение.

 

Сообщения Delphi. В Delphi определено около 100 стандартных типов сообщений. В соответствии с правилами Windows сообщение состоит из нескольких полей. Первое поле обычно называется Msg. Оно должно содержать индекс сообщения - 16 разрядное целое положительное число (тип Cardinal). Далее следуют поля, содержащие передаваемые значения. Последние поля обычно используются для записи результата обработки сообщения. Они могут отсутствовать.

 

Например, основной тип сообщений, используемых в Delphi, определяется следующим образом:

 

^ Type TMessage=record

 

Msg:Cardinal;

 

case Integer of

 

0: (WParam:LongInt; LParam:LongInt; Result:LongInt);

 

1: (WParamLo:Word; WParamHi:Word;

 

LParamLo:Word; LParamHi:Word;

 

ResultLo:Word; ResultHi:Word);

 

end;

 

end;

 

Номер сообщения. Номер (или индекс) сообщения используется для идентификации сообщения в системе: он определяет вид события, о котором система уведомляет приложение (нажатие клавиш, нажатие кнопок мыши и т.д.).

 

При создании собственных сообщений следует учитывать, что номера с 0 до $399 зарезервированы за системой. Первый свободный номер обозначен константой WM_USER = $400, относительно которой обычно и определяются номера пользовательских сообщений:

 

^ Const Mes1 = WM_USER;

 

Mes2 = WM_USER+1;

 

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

 

Метод обработки сообщения по умолчанию является динамическим, причем спецификаторы dinamic или override при его описании опускаются:

 

Procedure wm<имя метода>(var Message:<тип сообщения>);

 

message <номер сообщения>;

 

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

 

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

 

type <имя класса>= class <имя класса-родителя>

 

public

 

Procedure wm<имя метода>(var Message:<тип сообщения>);

 

message <номер сообщения>;

 

. . .

 

end;

 

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

 

procedure <имя класса>. wm<имя метода>;

 

begin

 

<специальная обработка>

 

inherited;

 

end;

 

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

 

^ Генерация сообщения. Для передачи сообщений объектам Delphi может использоваться несколько способов.

 

1. Для передачи сообщения оконному элементу управления через очередь сообщений с ожиданием завершения его обработки используется функция:

 

function SendMessage (hWnd:Integer, Mes:Cardinal;

 

^ WParam, LParam:LongInt):LongInt;

 

Она возвращает результат обработки сообщения. Параметр hWnd определяет номер, под которым окно - адресат сообщения - зарегистрировано в Windows (дескриптор окна). Для каждого оконного элемента управления этот номер хранится в свойстве Handle, определенном в классе TWinControl.

 

2. Для передачи сообщения оконному элементу управления через очередь сообщений без ожидания завершения его обработки используется функция:

 

function PostMessage(hWnd:Integer,Mes:Cardinal;

 

WParam,Param:LongInt):LongBool;

 

Список параметров функции совпадает со списком SendMessage, но в отличие от SendMessage PostMessage ставит сообщение в очередь сообщений и возвращает управление, не ожидая завершения обработки сообщения. Функция возвращает True, если сообщение поставлено в очередь, и False - в противном случае.

 

3. Для передачи сообщения элементу управления минуя очередь используется специальный метод этого элемента, определенный в классе TСontrol:

 

procedure Perform (Mes:Cardinal; WParam, LParam:LongInt);

 

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

 

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

Определение нового типа и создание его экземпляра в InitMainWindow - это все, что требуется для определения нового типа основного окна для TMyProgram. Объект приложения вызывает методы для создания интерфейсного элемента окна (Create) и вывода его на экран (Show). Вам почти никогда не потребуется использовать эти методы непосредственно. Обычно они вызываются при вызове метода MakeWindow объекта приложения.

 

Однако TStepWindow не определяет новых видов поведения, отличных от тех, которые наследуются от TWindow и TWindowObject. Другими словами, программа Step не становится более интересной. Такие виды поведения будут добавлены в следующем разделе.

 

// Создание основного окна.

 

hwndMain = CreateWindowEx(

0,// расширения стилей нет

"MainWClass",// имя класса

"Основное окно",// имя окна

WS_OVERLAPPEDWINDOW | // перекрывающее окно

WS_HSCROLL | // горизонтальная линейка прокрутки

WS_VSCROLL,// вертикальная линейка прокрутки

CW_USEDEFAULT,// горизонтальная позиция по умолчанию

CW_USEDEFAULT,// вертикальная позиция по умолчанию

CW_USEDEFAULT,// ширина по умолчанию

CW_USEDEFAULT,// высота по умолчанию

(HWND) NULL,// окно не родительское или

// имеющее в собственности окна

(HMENU) NULL,// используемый класс меню

hinstance,// дескриптор экземпляра

NULL);// нет данных создания окна

if (!hwndMain)

return FALSE;

// Показывает окно, использующее флажок, определенный программой,

// которая запускает прикладную программу и передает в приложение

// сообщение WM_PAINT.

ShowWindow(hwndMain, SW_SHOWDEFAULT);

UpdateWindow(hwndMain);

 

19.Стандартное окно с сообщением и кнопкой «ОК». Функции поддержки окон.

Простейшее диалоговое окно – это окно сообщения. Здесь присутствует только текст сообщения и кнопка «Ок». Нажав кнопку «Ок», Вы даёте понять Windows, что прочитали сообщение. И только после этого окно сообщения закрывается и перестаёт блокировать то окно, с которым мы работали до появления сообщения на экране.

 

Содержимое окна мы можем перечитать по команде «Insert+B». А для системного курсора здесь есть только один объект. Это кнопка «Ок». И никакие нажатия клавиши табуляции и стрелок не могут сдвинуть курсор с места. Мы можем только нажать «Пробел» или «Enter». Правда, можно ещё нажать «Escape» или «Alt+F4» для закрытия окна. Но это может и не сработать.

 

 

Обработка сообщений от клавиатуры, часто используемые сообщения.

  1. Обработка сообщений клавиатуры, посылаемых вашему приложению. Применяется когда, нужно обрабатывать сообщения клавиатуры и фокус ввода у вашего приложения. Есть несколько способов,…

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

  Команда однострочного текста (ТЕКСТ) позволяет создать одну или несколько…  

Список, раскрывающийся список, комбинированный список. Файловые операции.

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

 

 

csSimple, csDropDown, csDropDownList, csOwnerDrawFixed И csOwner DrawVariabie.

 

 

В первом случае список всегда раскрыт, в остальных он раскрывается после нажатия кнопки справа от редактора (рис. 18.7). В модификации csDropDownList редактор работает в режиме отображения выбора и его нельзя использовать для ввода новой строки (в других модификациях это возможно). Модификации csOwnerDrawFixed и csOwnerDrawVariable используются программной прорисовки элементов списка. Используемые для этого свойства и методы полностью совпадают со свойствами и методами TListBox аналогичного назначения.

 

По мере усложнения ваших программ они будут сохранять и получать информацию, используя файлы. Если вы знакомы с файловыми манипуляциями в языке С, вы сможете использовать подобные методы и в C++. Кроме того, как вы узнаете из этого урока, C++ предоставляет набор классов файловых потоков, с помощью которых можно очень легко выполнять операции ввода и вывода (В/В) с файлами. К концу данного урока вы освоите следующие основные концепции:

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

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

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

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

 

Многие программы, которые вы создадите в будущем, будут интенсивно использовать файлы. Выберите время для экспериментов с программами, представленными в данном уроке. И вы обнаружите, что в C++ выполнять файловые операции очень просто.

 

 

Создание процесса, создание потока, рабочие функции потока, обмен сообщениями между процессами и потоками.

  Для взаимодействия разных процессов или потоков разных процессов…  

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

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

 

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

 

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

 

В зависимости от ситуации нити могут находиться в трех состояниях. Во-первых, нить может выполняться, когда ей выделено процессорное время, т.е. она может находиться в состоянии активности. Во-вторых, она может быть неактивной и ожидать выделения процессора, т.е. быть в состоянии готовности. И есть еще третье, тоже очень важное состояние - состояние блокировки. Когда нить заблокирована, ей вообще не выделяется время. Обычно блокировка ставится на время ожидания какого-либо события. При возникновении этого события нить автоматически переводится из состояния блокировки в состояние готовности. Например, если одна нить выполняет вычисления, а другая должна ждать результатов, чтобы сохранить их на диск. Вторая могла бы использовать цикл типа "while( !isCalcFinished ) continue;", но легко убедиться на практике, что во время выполнения этого цикла процессор занят на 100 % (это называется активным ожиданием). Таких вот циклов следует по возможности избегать, в чем оказывает неоценимую помощь механизм блокировки. Вторая нить может заблокировать себя до тех пор, пока первая не установит событие, сигнализирующее о том, что чтение окончено.

 

Программа, выполняющая несколько действий одновременно, создает объекты, которые называются потоками или нитями (threads).

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

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

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

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

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

управление вводом от нескольких устройств.

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

для приложений с многодокументным интерфейсом (MDI) потоки для дочерних окон

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

Учтите: не все операционные системы осуществляют истинную многопроцессорную обработку, даже когда это поддерживается используемым оборудованием. Например, Windows 9x только моделирует многопроцессорную обработку, даже если используемое оборудование поддерживает это !

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

 

Синхронные и асинхронные сообщения, посылка сообщения из приложения Windows.

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

Асинхронные сообщения передаются непосредственно окну, когда Windows вызывает оконную процедуру.

Приведем примеры синхронных сообщений. Прежде всего, к ним относятся сообщения о событиях пользовательского ввода, таких как нажатие клавиш (WM_KEYDOWN и WM_KEYUP), перемещение мыши (WM_M0USEM0VE) или щелчок левой кнопкой мыши (WM_LBUTT0ND0WN). Кроме этого синхронными являются сообщения от таймера (WM_TIMER), сообщение о необходимости перерисовки клиентской области (WM_PAINT) и сообщение о выходе из программы (WM_QUIT). Приложение может само направить в очередь синхронное сообщение, вызвав функцию PostMessage.

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

Таким образом, оконная процедура должна быть повторно входимой (reentrant program). Это означает, что Windows часто вызывает функцию WndProc с новым сообщением, появившимся в результате вызова DefWindowProc из WndProc при обработке предыдущего сообщения. В большинстве случаев повторная входимость оконной процедуры не создает каких-то особых проблем, но знать об этом полезно.

Рассмотрим, например, какие события произойдут после щелчка кнопкой мыши на кнопке закрытия окна приложения Hellol. Все начнется с того, что Windows отправит асинхронное сообщение WM_SYSCOMMAND оконной процедуре WndProc. Оконная процедура передаст это сообщение на обработку функции DefWindowProc. Функция DefWindowProc реагирует на него, отправляя сообщение WM_CL0SE оконной процедуре. В рассматриваемом примере предусмотрена обработка этого сообщения — вызывается функция DestroyWindow. Однако если не предусмотреть эту обработку, то функция DefWindowProc сделала бы то же самое, то есть вызвала бы функцию DestroyWindow. Функция DestroyWindow заставляет Windows отправить оконной процедуре сообщение WM_DESTROY. И наконец, WndProc, обрабатывая это сообщение, вызывает функцию PostQuitMessage, которая посылает синхронное сообщение WM_QUIT в очередь сообщений приложения. Сообщение WM_QUIT прерывает цикл обработки сообщений в WinMain, и приложение завершает свою работу.

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

 

 

Графический интерфейс устройства (CDI). Контекст устройства. Регионы и отсечение.

Компания Microchip, ведущий производитель микроконтроллеров, известна своими решениями позволяющими снизить затраты как на разработку, так и общую…    

Файловый ввод-вывод данных средствами Win32API, файловые операции.

Файловый ввод-вывод в Win32

 

В этом разделе будут приведены минимальные сведения, необходимые для выполнения простых операций с файлами. В отличие от MS DOS среда Win32 способна поддерживать несколько файловых систем. Главные требования к этим системам — иерархичность и соблюдение определенных правил присвоения имен каталогам и файлам.

Перечислим функции API Win32, имеющие отношение к работе с файловой системой. Полное их описание можно получить в MSDN.

 

Прежде чем рассматривать функции API Win32, относящиеся к файловому вводу-выводу, отметим, как можно выяснить причину их ошибочного завершения. Для этого Windows предоставляет функцию GetLastError.

 

DWORD GetLastError(void):

 

Для вызова функции GetLastError не нужно передавать никаких параметров. Эту функцию необходимо вызывать сразу после функции API Win32, успешность работы которой мы проверяем.

 

;.........

push offset info

push hFile

call GetFilelnformationByHandle

call GetLastError ;в регистре ЕАХ возвращается код ошибки

 

В регистре ЕАХ возвращается код ошибки. Расшифровать его можно с помощью файла Winerror.h, где вместе с кодами ошибок приведены короткие сообщения о причине их возникновения.

 

Создание, открытие, закрытие и удаление файла

 

Создание и открытие файла в Win32 производится одной функцией CreateFile. HANDLE CreateFi1eCLPCTSTR ipFileName, DWORD dwDesiredAccess. DWORD dwShareMode. LPSECURITY_ATTRIBUTES ipSecurityAttributes, DWORD dwCreationDistribution, DWORD dwFlagsAndAttributes. HANDLE hTemplateFile):

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

 

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

 

Режимы многозадачности, многопоточная архитектура, преимущества Windows.

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

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

Двусвязный список состоит из элементов данных, каждый из которых содержит ссылки как на следующий, так и на предыдущий элементы. На рис. 22.5 показана организация ссылок в двусвязном списке.

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

 

Функция dlstore() помещает новые записи в конец списка. В качестве параметров ей необходимо передавать указатель на сохраняемые данные; а также указатель на конец списка, который при первом вызове должен быть равен нулю (NULL).

 

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

 

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

 

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

 

При удалении элемента двусвязного списка могут возникнуть три случая: удаление первого элемента, удаление элемента из середины и удаление последнего элемента. На рис. 22.7 показано, как при этом изменяются ссылки. Показанная ниже функция dldelete() удаляет элемент двусвязного списка

 

 

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

  Обзор методов интегрирования.  

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

 

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

Используемые теги: Общая, характеристика, языка, сравнении, другими, процедурными, языками0.099

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

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

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

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

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

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

Анализ обыденного языка: общая характеристика направления
Анализ обыденного языка и в терминах обыденного языка, конечно, не является чем-то новым в западной философии.Как отмечает Дж. Пассмор, мы… Однако большинство этих восстаний против техницизма философии было поднято в… Он выдвигается не в интересах какой-то частной отрасли философии, а в интересах изгнания путаницы из философии и…

Характеристика металлического состояния. Общая характеристика свойств металлов
На основе железа изготавливают не менее 90% всех конструкционных и инструментальных материалов. Металлическое состояние.Металлы в твердом и,… Физические свойства. К физическим свойствам металлов и сплавов относится температура плавления, плотность, температурный коэфициет…

Общая характеристика сети Internet
Эксперимент с ARPANET был настолько успешен, что многие организации захотели войти в нее, с целью использования для ежедневной передачи данных. И в… Для облегчения этого перехода DARPA обратилась с предложением к руководителям… Протоколы сети Internet Основное, что отличает Internet от других сетей - это ее протоколы - TCPIP. Вообще, термин…

Общая характеристика ранненовоанглийского периода
Экономическая общность приводит к образованию нации. Вместе с образованием нации складывается и национальный язык. В Англии в основу будущего… Этот процесс подробно исследовал английский лингвист Г.С. Уайлд. Согласно его… Эта классификация перекрещивается с классификацией по роду письменных памятников: 1) официальные документы, 2)…

Головной мозг. Общая характеристика головного мозга
В составе конечного мозга в толще белого вещества имеются скопления серого вещества базальные подкорковые или центральные ядра... Миндалевидное тело... Ограду...

ОБЩАЯ ХАРАКТЕРИСТИКА ПРОБЛЕМЫ РАСПОЗНАВАНИЯ ОБЪЕКТОВ И ЯВЛЕНИЙ
В А Скрипкин... Методы распознавания... ОБЩАЯ ХАРАКТЕРИСТИКА ПРОБЛЕМЫ РАСПОЗНАВАНИЯ ОБЪЕКТОВ И ЯВЛЕНИЙ...

Общая характеристика дисциплины
Программа курса... Содержание дисциплины по темам Тема Конституционное право РФ отрасль права наука...

ОБЩАЯ ХАРАКТЕРИСТИКА ПРОИЗВОДСТВА И ЕГО ТЕХНИКО-ЭКОНОМИЧЕСКИЙ УРОВЕНЬ
Пpи окислении в пpисутствии катализатоpа обpазуются окислы азота и воды по pеакции... NH O gt NO H O... Аммиак хоpошо pаствоpяется в воде обpазуя гидpат окиси аммония NH H O...

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