- •Иркутский государственный университет путей сообщения кафедра “информатика” программирование на языке Cи
- •Иркутск
- •Содержание
- •Предисловие
- •Алфавит языка
- •Служебные слова
- •Константы
- •Комментарии
- •Переменные
- •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;
- •Бинарные файлы
Операции над указателями
Помимо операций доступа по адресу * и получения адреса&, над указателями определены следующие операции:
сложение с константой,
вычитание,
инкремент,
декремент,
операции отношений.
Операция доступа по адресу* предназначена для доступа к величине, адрес которой хранится в указателе. Эту операцию можно использовать как для получения, так и для изменения значения величины (если она не объявленакак константа):
char a; // a - переменная типа char
char *ptr; // выделение памяти под указатель ptr
*ptr = ‘@’; // по адресу ptr записано значение @
a = *ptr; // переменной а присвоено значение, // записанное по адресу ptr
Как видно из примера, конструкцию *указательможно использовать в левой части оператора присваивания, так как она определяет адрес области памяти. Эту конструкцию можно считать именем переменной, на которую ссылается указатель. С ней допустимы все действия, определенные для величин соответствующего типа.
Арифметические операциис указателями (сложение с константой, вычитание, инкремент и декремент) автоматически учитывают размер типа величин, адресуемых указателями. Эти операции применимы только к указателям одного типа и имеют смысл в основном при работе со структурами данных, последовательно размещенными в памяти, например, с массивами.
Инкремент++перемещает указатель к следующему элементу массива,декремент-к предыдущему. Если указатель на определенный тип увеличивается или уменьшается на константу, то его значение изменяется на величину этой константы, умноженной на размер объекта данного типа. Эта операция производится автоматически.
Разностьдвух указателей – это расстояние между двумя областями памяти, определяемое в единицах, кратных размеру (в байтах) объекта того типа, к которому отнесены эти указатели. Таким образом, разность указателей, адресующих двасмежныхобъекта одинакового типа, по абсолютной величине всегда равнаединице.
Внимание!Суммирование двух указателейнедопустимо!
Указатели редко используются с простыми данными вроде отдельных переменных. Преимущества указателей наглядно проявляются при использовании их вместе с массивами, функциями и строками.
Указатели и массивы
В Сисуществует самая тесная связь между указателями и массивами, поэтому лучше эти средства рассматривать вместе.
Как мы знаем, структура массива полностью соответствует структуре оперативной памяти – элементы массива занимают в ней подряд идущие ячейки. Значит, если описан массив:
Int mass[5];
то в оперативной памяти для его элементов выделяется пять подряд идущих ячеек:
К i-му элементу этого массива можно обратиться, назвав его индекс:mass[i].
Доступ к любому элементу массива, осуществляемый по его индексу (номеру), может быть выполнен при помощи указателя, причем это будет сделано быстрее. Опишем переменную ptrкак указатель на данные целого типа:
int *ptr;
В результате присваивания
ptr = &mass[0];
эта переменная будет содержать адрес начального (нулевого) элемента этого массива, то есть указатель ptrбудет указывать на элементmass[0]:
Адрес начального элемента любого массива называется базовымадресом этого массива. Таким образом, сейчас указательptrсодержит базовый адрес массиваmass .Если увеличить значение указателя на единицу, тоptr + 1будет указывать на следующий элемент массива, то есть наmass[1],ptr + 2- на элементmass[2]и так далее. В общем случае, если значение указателя увеличить наk, то можно получить адресk-го элемента массиваmass.
Значит, адрес любого элемента массива равен сумме его базовогоадреса, который является адресом его начального элемента, исмещенияэтого элемента от начала массива. Для начального (нулевого) элемента массива это смещение равнонулю, для первого элемента –единице, для второго –двум, дляk-го оно равно k. Это верно для массива любого типа. Смысл выражения “увеличить указательptrна единицу “ , как и смысл любой арифметики с указателями заключается в том, чтоptr + 1указывает на следующий заptr элемент, аptr + kнаk-й послеptr элемент массива.
Между индексированием элементов массива и арифметикой с указателями существует очень тесная связь, потому что имя любого массива в Си есть адрес его начального элемента, то естьимя массива является его базовым адресом. Значит, в нашем примере присваивание:
ptr = &mass[0];
можно записать в другом виде:
ptr = mass;
Это будет одно и то же: записи &mass[0]иmassэквивалентны.
Из всего этого следует, что в общем случае запись &mass[k]будет эквивалентна записи(mass + k), а самk-й элемент массива можно определить какmass[k]или как*(mass + k). С другой стороны, еслиptr – указатель, то в выражениях его можно использовать с индексом, то есть записьptr[k]эквивалентна записи*(ptr + k).
Таким образом, элемент массива в Сиразрешается изображать и в виде указателя со смещением, и в виде имени массива с индексом.
Между именем массива и указателем, выступающим в роли имени массива, однако существует различие. Указатель – это переменная, поэтому можно записать ptr = massилиptr++.Но имя массива не является переменной, и записи типаmass = ptrилиmass++не допускаются.
Помимо рассмотренной операции сложения, над указателями можновыполнять следующие операции:
складывать и вычитать указатели и целые данные,
вычитать и сравнивать два указателя, ссылающиеся на элементы одного и того же массива,
присваивать значение указателя другому указателю того же типа,
присваивать указателю нуль и сравнивать его с нулем.
Над указателями нельзявыполнять следующие операции:
складывать два указателя, перемножать их, делить, сдвигать, выделять разряды,
складывать указатели со значениями типа floatиdouble,
присваивать указателю одного типа значение указателя другого типа (исключение составляют указатели типа void).
Указатели можно использовать и при работе с многомерными массивами: