- •Алфавит языка
- •Служебные слова
- •Константы
- •Комментарии
- •Переменные
- •Int I,j,k; //переменные I, j, k – целого типа
- •Математические функции
- •Выражения
- •Выражения целого типа
- •Примеры записи выражений целого типа:
- •Примеры вычислений выражений целого типа:
- •Выражения вещественного типа
- •Примеры записи выражений вещественного типа
- •Примеры вычислений выражений вещественного типа:
- •Операторы присваивания
- •Примеры записи операторов присваивания:
- •Ввод и вывод данных
- •Стандартный ввод-вывод
- •Посимвольный ввод-вывод
- •Ввод-вывод строк
- •Форматированный вывод
- •Форматированный ввод
- •Scanf(“формат”, аргументы);
- •Int age, rost;
- •Vasja Pupkin
- •Vasja Pupkin
- •Структура программы
- •Void main()
- •Int main()
- •Int age, rost;
- •Директивы препроцессора
- •Включение файлов
- •Int main()
- •Int age, rost;
- •Int main()
- •Int age, rost;
- •Подстановка имен
- •Макросы
- •Структуры данных
- •Массивы
- •Int vect[5];
- •Int vect[count];
- •Vect[0] vect[1] vect[2] vect[3] vect[4]
- •Int main()
- •Int temp;
- •Int matr[row][col];
- •Алгоритм и его свойства
- •Схемы алгоритмов
- •Пример записи алгоритма:
- •Базовые структуры
- •Цепочка
- •Ветвления
- •Альтернатива
- •If (условие)
- •Вариант 2 – с использованием операции конъюнкции
- •Int main()
- •Int c, y1, y2, kl, day, month, year;
- •Часто встречающиеся ошибки программирования:
- •Int main()
- •Переключатель
- •Int main()
- •Int month;
- •Часто встречающиеся ошибки программирования:
- •Бесконечные циклы
- •Циклы с предусловием
- •Int main()
- •Программа
- •Int main()
- •Программа
- •Int main()
- •Часто встречающиеся ошибки программирования:
- •Циклы с постусловием
- •Int main()
- •Int main()
- •Программа
- •Int main()
- •Int main()
- •Int main()
- •Int month;
- •Циклы с параметром
- •Действия цикла:
- •Int main()
- •Int top, bottom;
- •Int main()
- •Int num, sum, factor;
- •Int main()
- •Int main()
- •Int main()
- •Int vector_min, vector_max, temp;
- •Int vector[n];
- •Функции
- •Void main()
- •Int summa(int a, int b)
- •Int summa(int a, int b)
- •Void swap(int a, int b)
- •Int temp;
- •Void poplavok(int n, int vector[n])
- •5 * 4 * Factorial(3)
- •5 * 4 * 3 * Factorial(2)
- •5 * 4 * 3 * 2 * Factorial(1)
- •Int fibo(int n)
- •Int binom(int m, int n)
- •Int max_element(int k, int n, int vector[])
- •Int temp;
- •Void quick_sort(int left, int right, int vector[])
- •Адреса и указатели
- •Операции над указателями
- •Указатели и массивы
- •Int mass[5];
- •Int trio[5][2][3];
- •Указатели и функции
- •Int sloshenie(int a, int b);
- •Int sloshenie(int a, int b)
- •Int main()
- •Указатели и строки
- •Функции для работы со строками
- •Vtorokursnik
- •Vtorokursnik
- •Itoa(I, str, 16);
- •Текстовые файлы
- •Int vector[k];
- •Vector_1:
- •Vector_2:
- •Int ocenka;
- •Imja: Vasilij
- •Imja: Ivan
- •Int ocenka;
- •Бинарные файлы
Адреса и указатели
Между объектами реального мира, которые моделируются на компьютерах, существуют разнообразные, постоянно меняющиеся связи. Эти связи, как и сами объекты, могут появляться и исчезать. Поэтому если мы хотим описать в программе группу с переменным числом объектов, связи между которыми тоже подвержены изменениям, нужны соответствующие структуры. Эти структуры должны позволять устанавливать, изменять и разрывать связи между моделируемыми объектами, а также порождать или уничтожать сами объекты.
Для этой цели в Сииспользуются указатели и динамические структуры.
До сих пор мы рассматривали только статические структуры. Этим термином обозначаются структуры данных (массивы, файлы, структуры), которые возникают непосредственно перед выполнением программы в соответствии со своим описанием, существуют в течение всего времени ее выполнения, и размер которых задается заранее с помощью описания их типов и не изменяется в ходе выполнения программы.
Однако при решении многих задач мы заранее, то есть на этапе написания программы, не знаем не только размера того или иного программного объекта (структуры данных), но и даже того, будет ли вообще нужен этот объект. Такого рода программные объекты или структуры данных, возникающие уже в процессе выполнения программы по мере необходимости, размер которых определяется или изменяется при ее выполнении, называются динамическими объектамиили структурами.
Язык Сиотличается от других языков программирования, прежде всего широким использованием указателей. Именно наличие в нем указателей сделало его очень удобным для системного программирования.
Под указателем(ссылкой) понимается переменная, содержащая адрес (номер) ячейки памяти, в которой хранится значение любого программного объекта – переменной, элемента массива, функции, структуры.
Оперативная память компьютера – это последовательность байтов, каждый из которых имеет номер (адрес). Адреса байтов памяти идут по возрастанию: еслик– это номер текущего байта, ток-1– номер предыдущего, ак+1– последующего байтов. Указатель как раз и содержит адрес некоторого байта памяти. Меняя значение указателя, можно перемещаться по памяти, адресуясь к различным данным, записанным в просматриваемых ячейках.
Таким образом, в Сипод указателем понимается переменная, содержащая адрес любого объекта программы. Значит, указатель говорит о том, где в памяти размещен тот или иной программный объект (переменная, массив, структура, функция), но ничего не говорит об имени и значении этого объекта. По аналогии – можно знать почтовый адрес человека, но этот адрес не дает нам информацию о количестве комнат в его квартире и ее обстановке.
Применение указателей полезно:
при работе с массивами – обеспечивается использование сразу всех элементов массива,
при обращении к функциям – можно одновременно возвратить сразу несколько значений, вычисляемых функцией,
при работе с файлами – обеспечивается быстрый доступ к компонентам файла,
при создании новых переменных в процессе выполнения программы – можно динамически выделять память для них.
Для работы с указателями в Сииспользуются две операции:
*- доступ по адресу (обращение по адресу),
&- получение адреса.
Знак *, стоящий перед именемпеременной-указателя, означает «взять (записать) значение по данному адресу»:*ptr– записать значение по адресуptr.
Знак &, стоящий перед именем обычной переменной, означает «получить адрес переменной»:&x– получить адрес переменнойx.
Перед использованием в программе указатели, как и любые другие переменные, должны быть описаны – задан тип объекта, адрес которого будет хранить указатель, поставлена звездочка *и задано имя указателя:
int i, j, *ptr;
float x, y, *ukaz;
char c, d, *adr;
Описаны указатели:
рtr– на любой объект (переменную, массив, функцию) целого типа,
ukaz– на любой объект вещественного типа,
adr– на любой объект символьного типа.
После описания указателей им можно присвоить значения адресов переменных этого же типа, используя операцию получения адреса &:
ptr = &i;
ukaz = &x;
adr = &c;
Сейчас указателиptr, ukaz, adrбудут хранить адреса (номера) первых (младших) байтов памяти, отведенной для переменныхi, x, c(адрес байта памяти – этошестнадцатеричноечисло).
Присвоим этим переменным некоторые значения:
i = 5;
x = 3.1416;
c = ‘@’;
Обратимся к ним по адресу:
j = *ptr;
y = *ukaz;
d = *adr;
Содержимое ячейки памяти с адресомptr(а там записано число5– ведь это адрес переменнойi) будет присвоено переменнойj, содержимое ячейки памяти с адресомukaz– переменнойy, содержимое ячейки памяти с адресомadr– переменнойd.
Таким образом, два оператора присваивания:
ptr = &i;
j = *ptr;
выполняют то же самое, что и один оператор:
j = i;
Значит, можно организовать не только прямуюпередачу данных от одной переменной к другой (j = i), но икосвенную– через адреса переменных, даже не упоминая их имен. Указатели позволяют обращаться к конкретным ячейкам памяти и изменять их содержимое, не интересуясь тем, значения каких именно переменных хранятся в этих ячейках:
*adr = ‘+’;
переменой по адресу adrприсвоено значение символа‘+’,
(*ptr)++;
значение переменной по адресу ptrувеличивается на единицу,
(*ptr) += 3;
значение переменной по адресу ptrувеличивается на3,
j = (*ptr)++;
значение переменной по адресу ptrприсваивается переменнойjи после этого увеличивается на единицу.
Если это выражение записать без скобок:
j = *ptr++;
то сначала значение адреса ptrувеличивается на единицу (получаем адрес следующей ячейки памяти), а затем содержимое новой ячейки памяти присваивается переменнойj: операции доступа по адресу* и инкремента++имеют одинаковый приоритет, но выполняются справа налево.