- •1.1. Алфавит языка Си
- •1.2. Лексемы
- •1.3. Идентификаторы и ключевые слова
- •1.4. Знаки операций
- •1.5. Литералы (константы)
- •1.6. Комментарии
- •1.7. Общая структура программы на языке Си.
- •1.8. Функциональная и модульная декомпозиции
- •1.9. Этапы обработки программы.
- •1.10. Роль препроцессора.
- •1.11. Ошибки
- •2. Переменные и константы. Типы данных
- •2.1. Основные типы данных
- •2.2. Декларация (объявление) объектов
- •2.3. Константы в программах
- •2.4. Целочисленные константы
- •2.5. Константы вещественного типа
- •2.6. Символьные константы
- •2.7. Строковые константы
- •2.8. Логические константы
- •3. Обзор операций
- •3.1. Операции, выражения
- •3.2. Арифметические операции
- •3.3. Операции сравнения
- •3.4. Логические операции
- •3.5. Операция присваивания
- •Примеры недопустимых выражений:
- •3.6. Сокращенная запись операции присваивания
- •3.7. Операция «,» (запятая)
- •4. Обзор операций (продолжение)
- •4.1. Преобразование типов операндов бинарных операций
- •4.2. Преобразование типов при присваивании.
- •4.3. Операция явного приведения типа
- •4.4. Приоритеты операций
- •5. Стандартная библиотека языка Си
- •5.1. Стандартные математические функции
- •5.2. Потоковый ввод-вывод
- •5.3. Консольные функции вывода данных на экран
- •5.4. Консольные функции ввода информации
- •5.5. Ввод-вывод в оконных приложениях.
- •Советы по программированию
- •6. Операторы языка с.
- •7. Составление разветвляющихся алгоритмов
- •7.1. Условные операторы
- •If (выражение) оператор;
- •If (выражение) оператор 1 ;
- •If (выражение 1) оператор 1;
- •If (выражение 2) оператор 2;
- •If (выражение 3) оператор 3;
- •7.2. Оператор выбора альтернатив (переключатель)
- •Void main(void)
- •7.3. Условная операция «? :»
- •8. Составление циклических алгоритмов
- •8.1. Оператор с предусловием while
- •8.2. Оператор цикла с постусловием do – while
- •Void main(void)
- •8.3. Оператор цикла с предусловием и коррекцией for
- •8.4. Вложенные циклы.
- •Пример 1.
- •Void main(){
- •Пример 2.
- •9. Операторы передачи управления.
- •9.1. Оператор безусловного перехода goto
- •9.2. Операторы continue, break и return
- •10. Массивы
- •10.1. Одномерные массивы
- •10.2. Примеры алгоритмов, использующих одномерные массивы.
- •10.3. Многомерные массивы
- •10.4. Примеры алгоритмов, использующих двумерные массивы.
- •10.5. Компонента StringGrid
- •11. Размещение данных и программ в памяти пэвм
- •11.1. Общие понятия.
- •11.2. Кодирование целых чисел.
- •11.3. Кодирование вещественных чисел.
- •11.4. Кодирование символов.
- •Примеры кодов символов:
- •Стандартная часть таблицы символов (ascii)
- •Дополнительная часть таблицы символов (ascii, кириллица)
- •Дополнительная часть таблицы символов (ansi, кириллица)
- •11.5. Операция sizeof
- •11.6. Кодирование программы.
- •11.8. Регистры
- •12.1. Строки как нуль-терминированные массивы char.
- •Void main(){
- •If (!strcmp(a,b))
- •Itoa(I, s, 10);
- •If (! sscanf(s, "%d", &I))
- •If (!strnicmp(s, "song", 4)) {
- •If (!strnicmp(s, "song", 4)) {
- •12.2. Русификация консольных приложений.
- •Void main(void)
- •12.3. Строки как переменные типа AnsiString.
- •12.4. Преобразования строковых типов.
- •12.5. Тип String в консольных приложениях.
- •Void main(){
- •13. Функции пользователя.
- •13.1. Сущность и предназначение функций.
- •13.2. Определение и вызов функции.
- •Void main(){
- •14. Область видимости и классы памяти
- •14.1. Область видимости.
- •Void fun(void);
- •14.2. Классы памяти объектов в языке Cи.
- •Void f1(int);
- •Void main(void)
- •Void f1(int I)
- •Void st(void){
- •14.3. Разбиение программы на модули.
- •15. Генерация псевдослучайных чисел.
- •16. Отладка и пошаговое выполнение программы
- •17. Указатели
- •17.1. Определение указателей
- •17.2. Связь указателей и массивов.
- •17.3. Операции над указателями (косвенная адресация)
- •17.4. Сравнение указателей
- •17.5. Массивы указателей.
- •17.6. Указатели на указатели.
- •17.7 . Указатели как параметры функций.
- •Void zam(int *X, int *y)
- •Void zam(int &X, int &y)
- •Void zam (int&, int&);
- •Void main (void)
- •17.9. Указатели на функции
- •Void FunOut(double (*p_f )(char, double)){
- •18.2. Создание одномерного динамического массива.
- •18.3. Создание двуxмерного динамического массива.
- •19. Операция typedef
Void fun(void);
void fun2(int a);
int a=10;
void main(){
cout<<a<<endl; // a=10
int a=20;
cout<<a<<endl; // a=20
do{
int a=30;
cout<<a<<endl; // a=30
} while(0);
cout<<a<<endl; // a=20
for (int i=0; i<1; i++) {
int a=40;
cout<<i<<endl; // i=0
cout<<a<<endl; // a=40
}
cout<<a<<endl; // a=20
fun();
fun2(a);
}
void fun(void){
cout<<a<<endl; // a=10
}
void fun2(int a){
cout<<a<<endl; // a=20
}
Некоторые уточнения:
Параметры функции являются локальными переменными, их область действия - вся функция;
Если переменная объявлена внутри круглых скобок какого-либо оператора (например, for (int i=0; i<n: i++) { … } ), то областью ее действия одни компиляторы считают этот оператор (вместе с его телом), а другие - весь блок, в котором он находится. Рекомендуется поэтому использовать подобное место объявления, только если это не может привести к двусмысленности.
Область действия метки - вся функция (даже если метка лежит во вложенном блоке).
Функции не могут быть объявлены внутри других функций; поэтому они, как правило, являются глобальными. (При необходимости их область видимости можно ограничить с помощью не рассматриваемого здесь оператора namespace).
Замечание. Некоторые компиляторы не допускают переход с помощью goto внутрь области видимости переменной извне ("перескакивая" ее объявление), даже если сама эта переменная при этом не используется, т.к. это мешает им распределять память:
goto M;
int i;
…
M: // Может вызвать ошибку компиляции
Связь между функциями осуществляется через аргументы и возвращаемые функциями значения. Ее можно осуществить также через внешние, глобальные переменные.
Глобальные переменные доступны всем функциям, где они не описаны как локальные переменные. Использовать их для передачи данных между функциями довольно просто: значение, присвоенное глобальной переменной в одной функции, доступно в другой функции. Тем не менее, без нужды этого делать не рекомендуется. Необходимо стремиться к тому, чтобы функции в программе были максимально независимыми, и чтобы их интерфейс полностью определялся прототипами этих функции.
14.2. Классы памяти объектов в языке Cи.
Класс памяти определяет время жизни объекта и место его размещения в памяти (относительно границ сегмента памяти, выделенного для программы в целом).
Существует 4 класса памяти: static (статический), extern (внешний), auto (автоматический), register (регистровый).
Объекты, имеющие класс памяти static, существуют (занимают место в памяти) в течение всего времени работы программы. Их место в памяти определяется на этапе компиляции. К ним по умолчанию относятся глобальные переменные.
Объекты, имеющие класс памяти auto, существуют (занимают место в памяти) лишь во время выполнения блока, в котором объявлены. К ним по умолчанию относятся локальные переменные. Память для них выделяется при входе в блок в пределах определенной области, называемой программным стеком. После выхода из блока занимаемая ими память освобождается и может быть использована для других автоматических переменных. Это позволяет экономить память, а также осуществлять рекурсию (при вызове функцией самой себя создается новая копия всех ее автоматических переменных). Но это приводит к тому, что при повторном входе в блок значение, ранее присвоенное переменной, теряется.
Кроме того, общий размер стека должен быть задан на этапе компиляции и, таким образом, ограничен; в большинстве компиляторов по умолчанию (если не менять настроек) он равен всего лишь 1 мегабайт.
При любом вызове функции в программном стеке размещаются ее параметры, а также сохраняется содержимое регистров процессора на момент, предшествующий вызову функции, и адрес возврата из функции для того, чтобы при выходе из нее можно было продолжить выполнение вызывающей функции.
Класс памяти extern похож на static, но означает, что объект объявлен позже в этом или другом файле (см. ниже). Он может применяться к глобальным переменным.
Класс памяти register похож на auto; но он рекомендует компилятору разместить (если возможно) переменную не в стеке, а непосредственно в регистрах процессора. Регистровая память позволяет увеличить быстродействие программы, но к размещаемым в ней объектам в языке Си (но не С++) не применима операция получения адреса «&».
Обычно класс памяти переменных определяется по умолчанию (static либо auto). Но программист имеет возможность поменять класс памяти объекта, указав требуемый класс при объявлении перед его типом (в пределах допустимого по смыслу - например, глобальная переменная не может быть auto или register).
Например, объявление локальной переменной как static позволяет сохранять однажды присвоенное ей значение до следующего вызова функции. (Этого можно добиться также, объявив ее глобально; но тогда программа станет менее наглядной; а если уже есть глобальная переменная с таким именем, то вообще возникнет конфликт).
Объявление локальной переменной как register может ускорить работу с ней. Однако число регистров ограничено. Компилятор (при включенной оптимизации) и сам пытается разместить в регистрах наиболее "критичные по быстродействию" переменные. Поэтому указывать класс памяти register имеет смысл лишь для того, чтобы "обратить внимание" компилятора именно на те переменные, обработка которых является "узким местом" для повышения быстродействия программы.
Описание глобальной переменной или функции как extern указывает, что ее определение содержится ниже, либо в другом файле; а данное описание лишь сообщает компилятору типы. Во всех файлах, составляющих исходную программу, должно содержаться только одно определение данной функции или глобальной переменной. Другие файлы могут содержать описание extern для доступа к ней.
Инициализация объектов классов памяти static и extern происходит один раз при запуске программы. Если инициализация не указана, объект обязательно инициализируется нулем (или пустым значением - для нечисловых переменных).
Инициализация объектов классов памяти auto или register происходит каждый раз при входе в блок, где они объявлены. Если инициализация не указана, объект не инициализируется; его начальное значение тогда непредсказуемо. Исключение составляют переменные некоторых типов (например, String тогда инициализируется пустым значением).
Пример 1:
#include <stdio.h>
