SlideShare a Scribd company logo
1 of 133
Download to read offline
1
Основы программирования на языке Си.
Содержание.
1. Лекция: Общее знакомство.
-Происхождение языка Си.
-Достоинства языка Си.
-Будущее языка Си.
-Использование языка Си.
-Использование текстового редактора для подготовки программ.
-Исходные и выполняемые файлы. Примеры простой программы.
-Пример простой программы на языке Си.
-Структура простой программы.
2. Лекция: Данные, символьные строки, директива #define
-Основные типы данных.
-Описание различных типов, переменные и константы.
-Символьные строки.
-Препроцессор языка Си.
3. Лекция: Операции.
-Основные операции.
-Дополнительные операции.
-Перечень операций языка Си.
4. Лекция: Операторы.
-Выражения.
-Простейшие выражения.
-Операторы.
-Составные операторы.
5. Лекция: Преобразование типов.
-Эквивалентность типов.
-Преобразование типов.
-Неявное преобразование типа.
-Арифметические преобразования.
-Явное преобразование типов.
-Синтаксис типов.
6. Лекция: Функции и переключение ввода-вывода.
-Ввод и вывод одного символа.
-Буферы.
-Чтение одной строки.
-Чтение файла.
-Переключение и работа с файлами.
7. Лекция: Выбор вариантов.
-Выбор вариантов.
-Оператор if.
-Расширение оператора if.
-Операции отношения.
-Логические операции.
-Операция условия: ?:.
2
-Множественный выбор.
8. Лекция: Циклы и другие управляющие средства. Структурное
программирование.
-Цикл с предусловием.
-Цикл со счетчиком.
-Цикл с постусловием.
-Другие управляющие операторы.
-Структурное программирование.
9. Лекция: Функции.
-Создание и использование функций.
-Аргументы функции.
-Возвращение значений.
-Локальные переменные.
-Нахождение адресов.
-Указатели, первое знакомство.
-Функции с переменным количеством аргументов.
10. Лекция: Классы памяти и разработка программ.
-Классы памяти и область действия.
-Автоматические переменные.
-Внешние переменные.
-Статические переменные.
-Внешние статические переменные.
-Регистровые переменные.
11. Лекция: Препроцессор языка Си.
-Общие сведения.
-Символические константы: #define.
-Использование аргументов с #define.
-Макроопределение или функция?
-Включение файла #include.
-Условная компиляция.
12. Лекция: Массивы и указатели.
-Указатели и массивы.
-Массивы.
-Указатели.
-Динамические объекты.
-Создание динамических объектов.
-Доступ к динамическим объектам.
-Строки - дополнительные сведения о связи между указателями и массивами.
-Инициализация массивов и классы памяти.
-Функции.
-Операции с указателями.
13. Лекция: Символьные строки и функции над ними.
-Строковые константы.
-Массивы символьных строк и их инициализация.
-Массив и указатель: различия.
-Указатели и строки.
-Ввод-вывод строк.
-Обработка строк.
14. Лекция: Структуры.
-Определение структурных переменных.
-Доступ к компонентам структуры.
3
-Поля битов в структурах.
-Объединения.
-Перечисления.
-Переменные структуры.
-Указатели структуры.
-Массив структур.
-Переименования типов.
15. Лекция: Библиотека языка Си и файлы ввода-вывода.
-Библиотека языка Си содержит множество функций и макроопределений.
-Библиотеки меняются от системы к системе, но есть ядро функций (стандартная
библиотека).
-Распределение памяти.
16. Лекция: Функции в примерах.
-Функция получения случайных чисел.
-Поиск узлов из простых чисел.
-Матрица инцидентности.
-Структуры данных.
-Работа с файлами.
-Все операции со стеком.
-Примеры из графики, все преобразования трехмерного пространства.
4
1. Лекция: Общее знакомство.
-Происхождение языка Си.
-Достоинства языка Си.
-Будущее языка Си.
-Использование языка Си.
-Использование текстового редактора для подготовки программ.
-Исходные и выполняемые файлы. Примеры простой программы.
-Пример простой программы на языке Си.
-Структура простой программы.
Происхождение языка Си.
Язык программирования Си был разработан и реализован в 1972 году сотрудником фирмы
AT&T Bell Laboratories Денисом Ритчи. Прообразом языка Си для Д. Ритчи послужил
язык Би, разработанный Кеном Томпсоном. Он является результатом эволюционного
развития языков BCPL (Richards, M., "BCPL: A. Tool for Compiler Writing and System
Programming", Proc. AFIPS SJCC, 34, 557-566, 1969) и Би (Johnson, S. C., and B. W.
Kernighan, "The Programming Language B", Comp. Sci. Tech. Rep. No. 8, Bell Laboratories.
1973). Основным достоинством языка Си по сравнению с языками BCPL и Би является
введение в него типов данных. Язык Си был разработан во время создания операционной
системы UNIX (OC UNIX). Развитие языка Си продолжалось и после окончания его
разработки и касалось, в частности, проверки типов данных и средств, облегчающих
перенос программ в другую среду. Например, разработка проекта переноса OC UNIX на
компьютер Interdata 8/32 привела к некоторым добавлениям в язык Си, а именно, к
включению в язык таких средств, как объединение (union). Позднее были сделаны
попытки включения в язык Си средств абстрагирования данных. В настоящее время
рассматривается проект стандарта ANSI C - стандарт языка Си Американского
национального института и the C Programming Language - Reference Manual, AT&T Bell
Laboratories. С языка Си разработаны совместимые по входному языку трансляторы для
40 типов вычислительных систем, начиная от 8-разрядных микропроцессоров и кончая
CRAY-1 - одним из самых мощных в настоящее время суперкомпьютеров. В ходе работ
по созданию Мобильного Транслятора с языка Си сам он был переработан для повышения
мобильности написанных на нем программ.
Достоинства языка Си.
Особое значение придается гибкости. Язык Си компактен, является относительно
маленьким языком программирования. Ввод-вывод не считается частью языка Си, а
определяется стандартной библиотекой. Вседозволенность в языке Си является
следствием желания как можно больше расширить область его применения. Язык Си
удалось сделать относительно маленьким языком программирования за счет того, что в
его состав не были включены ввод-вывод и средства для работы со строками. Язык Си
был задуман настолько гибким, что эти возможности могли быть реализованы в каждом
конкретном случае наиболее удачным образом. Практический опыт использования языка
Си показал правильность такого подхода. Большая часть операционной системы UNIX и
все утилиты этой операционной системы, включая и несколько трансляторов с языка
Паскаль, реализованы на языке Си. Язык программирования является языком
программирования с сильной типизацией, если:
· каждый объект в этом языке программирования принадлежит точно одному из
существующих в этом языке программирования типу данных;
5
· преобразование типов осуществляется только путем преобразования значения из
одного типа в другой;
· преобразование типов не производится путем трактовки представления значения
как данных различных типов.
Эксперименты показали, что языки программирования с сильной типизацией
способствуют увеличению ясности и надежности программ. Механизм трактовки
представления значения как данных различных типов приводит к тому, что использующие
его программы не обладают ни надежностью, ни мобильностью. В языке Си допускается
неявное преобразование типов для всех базовых типов и указателей. Однако Мобильный
Транслятор с языка Си выводит предупреждение о каждом встретившимся в программе
случае неявного преобразования типов, в котором участвует указатель.
Язык Си быстро становится одним из наиболее важных и популярных языков
программирования. Его использование все более расширяется, поскольку часто
программисты предпочитают язык Си всем другим языкам после первого знакомства с
ним. Сейчас мы упомянем лишь некоторые достоинства Си.
Си - современный язык. Он включает в себя те управляющие конструкции, которые
рекомендуются теоретическим и практическим программированием. Его структура
побуждает программиста использовать в своей работе нисходящее проектирование,
структурное программирование и пошаговую разработку модулей. Результатом такого
подхода является надежная и читаемая программа.
Си - эффективный язык. Его структура позволяет наилучшим образом использовать
возможности современных ЭВМ. Написанные на языке Си программы обычно
отличаются компактностью и быстротой исполнения.
Си - переносимый (или мобильный) язык. Это означает, что программа, написанная на Си
для одной вычислительной системы, может быть перенесена с небольшими изменениями
или вообще без них, на другую.
Си - мощный и гибкий язык. Например, большая часть мощной и гибкой OC UNIX
написана на языке Си. Речь идет о компиляторах и интерпретаторах других языков, таких,
как Фортран, АПЛ, Паскаль, Лисп, Лого и Бейсик. Кроме того, программы, написанные на
Си, используются для решения физических и технических проблем, компьютерной
графики и даже производства мультипликационных фильмов.
Си - обладает рядом конструкций управления, обычно ассоциируемых с ассемблерами.
Си - удобный язык. Он достаточно структурирован, чтобы поддерживать хороший стиль
программирования, и вместе с тем не связывает ограничениями.
Будущее языка Си.
Многие фирмы, производящие программное обеспечение, все чаще обращаются к Си как
к удобному языку для реализации своих проектов, поскольку известно, что Си позволяет
получить компактные и эффективные программы. И эти программы могут быть легко
модифицированы и адаптированы к новым моделям ЭВМ! Языки программирования как
С++, Java, С#, UML и т.д. имеют "сишную" семантику. Си используется фирмами,
производящими программное обеспечение, студентами, обучающимися
программированию. И если вы хотите работать в сфере программотехники, то один из
первых вопросов, на который вы должны будете отвечать "Да" - это вопрос "Умеете ли Вы
программировать на Си?"
Использование языка Си.
Си - язык компилируемого типа. Пример языков компилируемого типа: Паскаль, Фортран.
Пример языков интерпретируемого типа: Бейсик, Лого. Чтобы дать первое представление
6
о процессе создания программы, приведем упрощенную схему того, что необходимо
сделать - начиная от написания программы и заканчивая ее выполнением.
1. Для создания программы на языке Си используйте редактор текстов.
2. Попробуйте оттранслировать вашу программу с помощью удобного для вас
компилятора. Компилятор проведет проверку правильности вашей программы.
Если компилятор обнаружит ошибки в вашей программе, он выдаст сообщение об
этом. Если ошибок не будет, компилятор выполнит перевод программы на
внутренний язык ЭВМ, и поместит результат в новый файл.
3. Набрав имя этого нового файла на клавиатуре дисплея, вы можете запустить
программу.
В некоторых вычислительных системах второй этап может быть разбит на два или три
шага.
Использование текстового редактора для подготовки программ.
У Си нет собственного текстового редактора. В качестве него можно использовать любой
из редакторов общего типа. В операционной системе UNIX это чаще всего редакторы ed,
ex, edit, emacs, vi. На персональном компьютере это может быть ed, edlin, Wordstar,
Volkswriter или любой другой из большого набора редакторов. При работе с некоторыми
из них необходимо определить конкретную версию редактора путем задания
соответствующих параметров. Например, при использовании редактора Wordstar
необходимо ввести параметр N, указывающий на отсутствие документирования.
При работе с редактором лучше не ошибаться, набирая текст программы на пульте
дисплея, и правильно задать имя файла, в который она будет помещена. Имя файла
должно быть допустимым именем в вашей вычислительной системе и иметь расширение
.c.
Например,
sort.c
Sort.c
Первая часть имени должна напоминать, что программа делает или хотя бы того, кто
разработал алгоритм, который в ней реализован. Вторая часть, так называемое
расширение файла .с указывает на то, что данный файл содержит текст программы,
написанный на языке Си. Расширение файла используется для того, чтобы информировать
пользователя и вычислительную систему о типе файла. Предположим, что при помощи
редактора мы подготовили программу и поместили ее в файл с именем Nina.c. Текст,
который мы набрали на клавиатуре, называется исходным кодом и содержится в исходном
файле. Исходный файл - это начальный пункт процесса программирования.
Исходные и выполняемые файлы
Приведем простенькую программу на языке Си:
#include <stdio.h>
main( )
{
printf("Добро пожаловать!n");
}
Все конструкции языка мы рассмотрим в последующих лекциях. Если эту программу
оттранслировать, то получим файл с выполняемой программой. В результате работы этой
программы на дисплей будет выведено предложение: "Добро пожаловать!". Наша
программа, несмотря на свою лаконичность и простоту, для компьютера является
совершенно бессмысленным набором символов, так как он не понимает директив #include
или printf. Компьютер понимает только специальный язык, называемый машинным кодом,
7
т.е. набор последовательностей двоичных цифр, например 101000101. Если мы хотим,
чтобы компьютер выполнил программу, мы должны осуществить перевод (трансляцию)
кода, написанного на Си (исходного) в ее код (машинный). В результате этих действий
будет получен выполняемый файл. Процесс перевода (трансляции) удалось переложить на
сам компьютер. Программы, переводящие исходный код в машинный код, называются
компиляторами. Детали процесса перевода зависят от особенностей конкретной системы.
В некоторых компиляторах с языка Си, работающих на персональных ЭВМ, реализован
альтернативный способ трансляции. В процессе перевода получается файл с расширением
.obj, затем используется системный компоновщик для получения файла с выполняемой
программой, т.е. файла с расширением .exe. Почему компиляция, а не интерпретация?
Дело в том, что после компиляции получается более эффективный конечный продукт, чем
при интерпретации.
Пример простой программы на языке Си
Рассмотрим простую программу на языке Си:
#include <stdio.h>
main( )/*простая программа*/
{
int courses;
courses=30;
printf("Сколько учебных курсов на сайте");
printf(" www.intuit.ru?n");
printf("Более %d. Но будет еще больше!n",
courses);
}
Давайте, выполним эту программу. Сначала используем текстовый редактор для создания
файла, содержащего текст программы. Этому файлу нужно присвоить какое-то имя.
Допустим - intuit.c . Выполним компиляцию программы. После запуска программы,
при условии отсутствия синтаксических ошибок, результат должен выглядеть следующим
образом:
Сколько учебных курсов на сайте www.intuit.ru?
Более 30. Но будет еще больше!
Пояснения к программе
Мы выполним два просмотра текста программы: во время первого просмотра объясним
смысл каждой строки, а во время второго - рассмотрим детали.
Первый просмотр
#include <stdio.h> - включение другого файла.
Эта строка указывает компилятору, что нужно включить информацию, содержащуюся в
файле stdio.h.
main( ) - имя функции
Любая программа, написанная на языке Си, состоит из одной или более функций,
являющихся основными модулями, из которых она собирается. Наша программа состоит
из одной функции main( ), а круглые скобки указывают именно на то, что main( ) -
имя функции.
/* простая программа*/ – комментарий
/*, */ - открывающая и закрывающая скобки многострокового комментария.
Комментарии - это примечания, помогающие понять смысл программы. Они
предназначены для читателя, и игнорируются компилятором.
{ – начало тела функции
8
Открывающая фигурная скобка отмечает начало последовательности операторов - тело,
или определение, функции. Конец определения отмечается закрывающей фигурной
скобкой – }.
int courses; – оператор описания.
С помощью такого оператора мы объявляем, что будем использовать в программе
переменную courses, которая принимает целые (int) значения.
courses = 30; – оператор присваивания
Этот оператор служит для присваивания переменной courses значения 30.
printf("Сколько учебных курсов на сайте"); – оператор вывода на печать
С его помощью выводится на печать фраза, заключенная в кавычки:
Сколько учебных курсов на сайте
printf(" www.intuit.ru?n"); – еще один оператор вывода на печать. Этот
оператор добавляет слова www.intuit.ru? в конец последней печатаемой фразы.
Комбинация символов n указывает компилятору на начало новой строки.
printf("Более %d. Но будет еще больше!n",courses); – этот оператор
выводит на печать значение переменной courses, равное 30, содержащееся в кавычках.
Символы %d указывают компилятору, где и в какой форме печатать значение переменной
courses.
} - конец
Программа завершается закрывающей фигурной скобкой.
Второй просмотр
#include <stdio.h>
Файл с именем stdio.h является частью пакета, имеющегося в любом компиляторе
языка Си и содержащего информацию о вводе-выводе. В качестве имени файла
используется аббревиатура английских слов:
standard input/output header - заголовок стандартного ввода-вывода.
Программисты называют набор данных, содержащийся в начале файла, заголовком.
Строка "#include <stdio.h>" даже не является оператором языка Си. Символ #
указывает, что она должна быть обработана "препроцессором" языка Си. Препроцессор
осуществляет некоторую предварительную обработку текста программы перед началом
компиляции.
main( )
Программа, написанная на языке Си, всегда начинает выполняться с функции, называемой
main( ). Скобки указывают на то, что main( ) - имя функции.
Функция - это основные модули программы, написанные на языке Си. В круглых скобках
в общем случае содержится информация, передаваемая этой функции. В нашем случае
передача информации отсутствует и, следовательно, в скобках ничего не содержится.
Файл, содержащий программу, может иметь любое имя с тем ограничением, что оно
должно удовлетворять системным соглашениям, и оканчиваться символом с. Например,
game.c.
/* простая программа*/
Комментарии облегчают процесс понимания программы. Длинный комментарий может
помещаться на отдельной строке или даже занимать несколько строк. Все, что находится
между символом, указывающим на начало комментария /*, и символом, указывающим на
его конец */, игнорируется компилятором.
{,}
Фигурные скобки { } отмечают начало и конец тела функции.
int courses;
Это оператор описания переменной. В нашей программе в теле функции используется
переменная courses, и с помощью слова int объявляется, что переменная courses
принимает целые значения. Точка с запятой в конце строки указывает на то, что в ней
9
содержится оператор языка Си, причем этот символ является частью оператора, а не
разделителем операторов. int служит ключевым словом, определяющим один из
основных типов данных языка Си.
Ключевыми словами называются специальные зарезервированные слова, используемые
для построения фраз языка.
В языке Си все переменные должны быть объявлены. Это означает, что мы должны
привести список всех используемых переменных и указать тип каждой из них.
Имя переменной нужно давать осмысленно. Оно может содержать от одного до восьми
символов. Фактически мы можем использовать и большее их число, но компилятор
пропустит все символы, начиная с девятого.
Идентификатор переменной - имя переменной. Для обозначения имени переменной
разрешается использовать строчные и прописные буквы, цифры и символ подчеркивания,
считающийся буквой. Первым символом должна быть обязательно буква.
Например, courses, cat_1, _total - правильные идентификаторы, а $courses*,
1cat, -total - неправильные.
Переменные можно описывать по мере необходимости, но лучше размещать операторы
объявления переменных в начале программы. Любая программа, написанная на языке Си,
не будет выполняться, если
не описать все используемые переменные.
courses=30;
Оператор присваивания является одним из основных средств языка. Приведенную строку
программы можно интерпретировать так: присвоить переменной courses значение 30.
При описании переменной courses была выделена ячейка памяти, и только теперь в
результате выполнения оператора присваивания переменная получает свое значение. При
желании мы могли бы присвоить ей другое значение, поэтому имя courses и обозначает
переменную.
В данной программе используется стандартная функция языка Си - printf( ). Строка
символов, заключенная в скобки, является информацией, передаваемой функции
printf( ) из главной функции main( ). Такая информация называется аргументом. В
первом случае аргументом является "Сколько учебных курсов на сайте". Данная
строка дает пример того, как вызывать функцию или обратиться к ней, программируя на
языке Си. Для этого требуется только указать имя функции и заключить требуемый
аргумент, или аргументы, в скобки. Когда при выполнении функции программа достигнет
этой строки, управление будет передано указанной функции. Когда выполнение функции
будет завершено, управление вернется обратно в исходную, вызывающую программу.
Символы n служат директивой начать новую строку на устройстве вывода. Комбинация
n представляет один символ, называемый "новая строка". Его смысл формулируется
так: начать вывод новой строки с самой левой колонки. Символ "новая строка" служит
одним из примеров того, что называется "управляющей последовательностью".
Управляющая последовательность начинается с "".
Структура простой программы
Познакомимся с несколькими общими правилами, касающимися программ, написанных
на языке Си. Программа состоит из одной или более функций, причем какая-нибудь из
них (главная) обязательно должна называться main( ). Описание функции состоит из
заголовка и тела. Заголовок состоит из директив препроцессора типа #include и имени
функции. Отличительным признаком имени функции служат круглые скобки, а аргумент
может и отсутствовать. Тело функции заключено в фигурные скобки и представляет собой
набор операторов, каждый из которых оканчивается символом "точка с запятой".
Дополнительный пример.
10
Здесь мы приведем еще пример. Мы использовали только стандартную функцию
printf( ). В данном примере мы демонстрируем, как включить и использовать
функцию, которую мы сами написали:
dir( )/* dir*/
{
printf("На сайте проекта www.intuit.ru n");
printf(" большое количество учебных курсовn");
}
main ( )
{
dir ( );
printf("Над их созданием работают n");
printf(" профессора российских вузов.n");
}
Результат работы программы выглядит следующим образом:
На сайте проекта www.intuit.ru
большое количество учебных курсов
Над их созданием работают
профессора российских вузов.
Функция dir( ) определяется точно так же, как и функция main( ) - ее тело
заключено в фигурные скобки. Вызов функции осуществляется путем простого указания
ее имени, включая круглые скобки.
11
2. Лекция: Данные, символьные строки, директива #define.
-Основные типы данных.
-Описание различных типов, переменные и константы.
-Символьные строки.
-Препроцессор языка Си.
Основные типы данных
Чтобы реализовать алгоритм, программам необходимо работать с данными - числами,
символами, т.е. объектами, которые несут в себе информацию, предназначенную для
использования. Некоторые данные устанавливаются равными определенным значениям
еще до того, как программа начинает выполняться, а после ее запуска такие значения
сохраняются неизменными на всем протяжении работы программ. Эти данные
называются константами. Данные, которые могут изменяться, или же им могут быть
присвоены значения во время выполнения программы, называются переменными.
Различие между переменной и константой очевидно: во время выполнения программы
значение переменной может быть изменено (например, с помощью присваивания), а
значение константы изменить нельзя.
Кроме различия между переменными и константами существует еще различие между
типами данных. Некоторые данные в программе являются числами, некоторые -
символами. Компилятор должен уметь идентифицировать и обрабатывать данные любого
типа. В языке Си предусмотрено использование нескольких основных типов данных. Если
величина есть константа, то компилятор может распознать ее тип только по тому виду, в
котором она присутствует в программе. В случае переменной необходимо, чтобы ее тип
был объявлен в операторе описания. В стандарте языка Си используется семь ключевых
слов, указывающих на различные типы данных:
int
long
short
unsigned
char
float
double
Первые четыре ключевых слова используются для представления целых, т.е. целых чисел
без десятичной, дробной части. Если мы хотим подчеркнуть, что целое не может быть
отрицательным, то нужно к целому подписывать ключевое слово unsigned, например,
unsigned short. char предназначено для указания на буквы и другие символы.
float, double используются для представления чисел с десятичной точкой. Типы,
обозначаемые этими ключевыми словами, можно разделить на два класса по принципу
размещения в памяти машины. Первые пять ключевых слов определяют целые типы
данных, последние два - типы данных с плавающей точкой. Дадим краткое объяснение их
смысла. Термины бит, байт, слово используются для описания как элементов данных,
которые обрабатывает компьютер, так и элементов памяти. Рассмотрим эти понятия
относительно памяти. Наименьшая единица памяти называется бит. Она может принимать
одно из двух значений: 0 или 1. Байт в большинстве машин состоит из 8 бит. Всего в
байтовом формате можно представить 256 (два в восьмой степени) различных
комбинаций из нулей и единиц. Эти комбинации можно использовать для представления
целых чисел в диапазоне от 0 до 255 или для кодирования набора символов. Слово
является естественным элементом памяти. Есть ЭВМ, у которых слово равно 8 битам, 16
битам, 32 битам или 64 битам.
12
Описание различных типов, переменные и константы
Целые числа.
У целого числа никогда не бывает дробной части. Представив целое число в двоичном
виде, его нетрудно разместить в машине. Например, число 3 в двоичном виде выглядит
как 11. Если его поместить в слово 32-разрядной машины, необходимо первые 30 бит
установить в 0, а последние 2 бита - в 1.
Числа с плавающей точкой.
Числа с плавающей точкой соответствуют тому, что математики называют
вещественными числами. Способ кодирования, используемый для помещения в память
числа с плавающей точкой, полностью отличается от размещения целого числа. Числа с
плавающей точкой представляют в виде дробной части и порядка числа, а затем обе части
размещают в памяти.
Все данные типов int, short, long являются числами со знаками, т.е. значениями этих
типов могут быть только целые числа - положительные, отрицательные и нуль. Один бит
используется для указания знака числа, поэтому максимальное число со знаком,
которое можно представить в слове, меньше, чем максимальное число без знака.
Описание данных целого типа.
При описании данных необходимо написать только тип, за которым должен следовать
список имен переменных. Например, int dog, rad, nina. В качестве разделителя
между именами переменных необходимо использовать запятую.
Целые константы.
Согласно правилам языка Си, число без десятичной точки и без показателя степени
рассматривается как целое. Поэтому компилятор по записи константы определяет, целая
она или вещественная. Если нужно ввести константу типа long, то нужно указать
признак L или l в конце числа. Если при записи константы целое начинается с цифры 0,
то эта константа интерпретируется как восьмеричное число, если же целое начинается с
символа 0x или 0X - как шестнадцатеричное число.
Инициализация переменных целого типа.
Константы применяются при инициализации переменных. Это означает присваивание
переменной некоторого значения перед началом обработки. Можно инициализировать
переменную в операторе описания.
Например,
int dog=5;
int rad=077;
int nina=0X99;
! В языке Си введено три класса целых чисел, имеющих различные размеры. Тем самым
пользователю языка Си предоставили возможность выбора типа переменной с
требованием задачи. Например, если переменная типа int занимает одно слово, а
переменная типа long занимает два слова, значит, тип long позволяет обрабатывать
большие числа. Если в задаче не используются большие числа, то незачем вводить в
программу переменные типа long, т.к. если вместо числа, занимающего одно слово в
памяти, используется число, занимающее два слова, работа машины замедляется.
Описание данных типа unsigned.
Этот тип является модификатором типов: int, short, long. Мы можем использовать
комбинацию ключевых слов unsigned int, unsigned short, unsigned long, т.е.
13
переменная не может принимать отрицательного значения. Для указания типа unsigned
int достаточно написать unsigned. Целые беззнаковые константы записываются так
же, как и обычные константы, запрещено только использование знака минус.
Например, unsigned age;
Описание данных типа char.
Этот тип определяет целые числа без знака в диапазоне от 0 до 255. Такое целое обычно
размещается в одном байте памяти. Для описания символьной переменной применяется
ключевое слово char. Правила описания более чем одной переменной и инициализации
переменных остаются теми же, что и для других основных типов.
Например, char dog, cat;
Символьные константы. Символы в языке Си заключаются в апострофы.
Например, char dog; dog='b';
Если апострофы опущены, то компилятор считает, что используется неописанная
переменная b. В стандартном языке Си значением переменной или константы типа char
могут быть только одиночные символы.
Примеры символьных констант: 'A', 'a', '7', '$'.
Специальные (управляющие) символьные константы.
Новая строка (перевод строки) 'n'
Горизонтальная табуляция 't'
Вертикальная табуляция 'v'
Возврат на шаг 'b'
Возврат каретки 'r'
Перевод формата 'f'
Обратная косая ''
Апостроф '''
Кавычки '"'
Нулевой символ (пусто) '0'
Кроме того, любой символ может быть представлен последовательностью трех
восьмеричных цифр: 'ddd'. Символьные константы считаются данными типа int.
Строковые константы.
Строковая константа представляется последовательностью символов кода ASCII,
заключенной в кавычки.
Например,
"Это строковая константа"
В конце каждой строки компилятор помещает нулевой символ '0', отмечающий конец
данной строки. Каждая строковая константа, даже если она идентична другой строковой
константе, сохраняется в отдельном месте памяти. Если необходимо ввести в строку
символ кавычек ("), то перед ними надо поставить символ обратной косой (). В строку
могут быть введены любые специальные символьные константы, перед которыми стоит
символ . Символ  и следующий за ним символ новой строки игнорируется.
Перечисляемые константы.
Имена, указанные в описании перечисляемых констант, трактуются как целые числа (см.
описание перечисления).
14
Описание данных типа float и double.
Числа с плавающей точкой в языке Си описываются типом float. Числа с плавающей
точкой аналогичны числам в обычной алгебраической записи, используемой при работе с
очень большими или малыми числами.
Пример алгебраической записи чисел с плавающей точкой:
Число Алгебраическая запись Запись для ввода в машину
5000 = 5.0 * 103 = 5.0e3
0.000077 = 7.7 * 10-5 = 7.7e-5
Обычно для размещения в памяти числа с плавающей точкой отводится 32 бита - 8 бит
для представления порядка и знака и 24 бита - для мантиссы, т.е. коэффициента при
степени десяти. Для представления данных типа double (вычисление с двойной
точностью) для представления чисел используется удвоенное число битов. Другой способ
определения данных типа double заключается в использовании ключевых слов long
float.
Переменные с плавающей точкой описываются и инициализируются таким же образом,
что и переменные целого типа.
Например,
float dog, cat, bigword=5.77e+34;
Константы с плавающей точкой.
В языке Си имеется несколько возможностей записи констант с плавающей точкой.
Наиболее общая форма записи константы - это последовательность десятичных цифр со
знаком, включающим в себя десятичную точку, затем символ e или Е и показатель
степени по основанию 10 со знаком. Знак “+” можно не писать. Ниже приведено
несколько правильно записанных констант с плавающей точкой:
1.1e+12
3.14159
! Во время разработки программы необходимо составить список требуемых переменных
и указать при этом, какого они должны быть типа. Описывайте эти данные в самом
начале тела функции, в которой они используются. Имена переменных выбирайте таким
образом, чтобы они указывали на их смысл. При инициализации переменной следите за
тем, чтобы тип константы соответствовал типу переменной, хотя язык Си рассматривает
такие несоответствия менее жестко, чем Паскаль, но лучше учиться избегать дурного
тона в программировании!
Символьные строки
Символьная строка - это последовательность символов, возможно пустая ("").
Рассмотрим пример:
"Большой спрос на образование в области
информационных дисциплин объясняется не только
популярностью компьютеров в современном обществе,
но и реальной пользой от их применения."
Кавычки не являются частью строки. Они вводятся только для того, чтобы отметить ее
начало и конец. В языке Си нет специального типа, который можно было бы использовать
для описания строк. Вместо этого строки представляются в виде "набора" элементов типа
char. Это означает, что символы в строке можно представить расположенными в
соседних ячейках памяти - по одному символу в ячейке. Символ 0 в языке Си
используется для того, чтобы отмечать конец строки. Нуль-символ не выводится на печать
и в таблице кода ASCII (American Standard Code for Information Interchange) имеет номер
15
0. Наличие нуль-символа означает, что количество ячеек массива символов должно быть
на одну больше, чем число символов строки. Массив можно представить как
совокупность нескольких ячеек памяти, объединенных в одну строку. Массив - это
упорядоченная последовательность элементов данных одного типа. В нашем примере мы
создали массив из 177 ячеек памяти, в каждую из которых можно поместить один символ
типа char. Это можно сделать с помощью оператора описания:
char String[177];
Квадратные скобки указывают, что переменная String - массив из 177 элементов, а char
задает тип каждого элемента. Длину строки в символах (без завершающего символа)
определяет функция strlen( ). Обращение к ней в нашем примере выглядит так:
strlen(String);
Результат - целое число.
Препроцессор языка Си
Вернемся к константам. Чтобы ввести ту или иную константу в программу, нужно указать
ее фактическое значение, как было сказано выше. Можно использовать вместо этого
"символические константы" и позволить компилятору заменить символические константы
числами. Как можно создать такую константу? Можно это сделать так:
float cost = 0.0012;
Такой способ задания констант в больших программах неэкономичен. В Си имеется
другой, лучший способ. Этот способ реализуется с помощью препроцессора языка Си.
Препроцессор дает возможность задавать константы. Для этого в начало программы
нужно добавить строку, аналогичную следующей:
#define COST 0.0012
При компиляции программы каждый раз, когда появится переменная COST, она будет
заменяться величиной 0.0012. Такой процесс называется подстановкой во время
компиляции. Замечание по поводу формата: сначала идет ключевое слово #define (оно
должно начинаться с самой левой позиции), потом идет символическое имя константы, а
затем ее величина. Символ "точка с запятой" не используется, потому что это не
оператор языка Си.
Если в качестве первого символа в строке программы используется символ #, то эта
строка является командной строкой препроцессора (макропроцессора). Командная строка
препроцессора заканчивается символом перевода на новую строку. Если непосредственно
перед концом строки поставить символ обратной косой (), то командная строка будет
продолжаться на следующей строке программы.
Препроцессор используется для обработки текста программы до этапа ее компиляции.
Обычно препроцессоры служили средством расширения языков с целью обеспечения
дополнительных возможностей. Несмотря на бесчисленное множество препроцессоров,
созданных для расширения возможностей языков программирования, все они были
нестандартными. Для некоторых языков, например для языков общего назначения ПЛ/1 и
Си, препроцессоры поставлялись как часть их стандартной среды. Препроцессор для
языка Си обеспечивает средства для определения макросов, определения констант,
включения файлов и условную компиляцию. Препроцессор языка Си вызывается
автоматически при обращении к компилятору. Программа может быть обработана
только препроцессором без компиляции, если в команде сс указать ключ -Е:
cc -E имя_файла
Результат работы препроцессора помещается в поток стандартного вывода stdout.
Обработка программы препроцессором без компиляции позволяет программисту
проанализировать действие определений препроцессора и макровызовов.
16
! Символическую константу после #define лучше писать прописными буквами. В
процессе использования языка Си выработалась традиция писать константы большими
буквами. Если при просмотре программы встречается имя, написанное прописными
буквами, сразу становится ясно, что это константа, а не переменная. Давайте не
нарушать традицию!
Директиву #define можно использовать для определения символьных и строковых
констант. В первом случае необходимо использовать "апостроф", а во втором кавычки.
Например,
#define NULL '0'
#define USA '$'
#define RUSSIA "Рубль"
#undef USA
Команда #undef USA отменяет предыдущее определение для идентификатора USA.
Через команду #define можно задавать выражения - макросы, которые вычисляются и
при компиляции подставляются в программу. Воизбежании ошибок при вычислении
выражений макроопределения необходимо заключать в скобки:
#define идентификатор1 (идентификатор2,_) строка
Пример:
#define abs(A) (((A)>0) ? (A): - (A))
Каждое вхождение выражения abs(arg) в тексте программы заменяется на ((arg)>0)
? (arg): -(arg)), причем параметр макроопределения A заменяется на arg.
Пpимер:
#define nmem(P,N)
(P)->p_mem[N].u_long
Символ  продолжает макроопределение на вторую строку. Это макроопределение
уменьшает сложность выражения, описывающего массив объединений внутри структуры.
Макроопределения препроцессора языка Си имеют две формы - простую и
параметризованную,
#define идентификатор строка_замены
#define идентификатор(x1,x2,_,xn) строка_замены
где строка_замены может содержать идентификаторы, ключевые слова, разделители,
такие как круглая или прямоугольная скобка, или строки знаков, не содержащие каких-
либо разделителей.
Замечание.
Командная строка #include может встречаться в любом месте программы, но обычно
все включения размещаются в начале исходного текста:
#include <имя_файла>
Пример:
#include <math.h>
Препроцессор заменяет эту строку содержимым файла math.h. Угловые скобки
обозначают, что файл math.h будет взят из некоторого стандартного каталога, обычно
это /usr/include. Текущий каталог не просматривается:
#include "имя_файла"
Пример:
#include "ABC"
Препроцессор заменяет эту строку содержимым файла ABC. Так как имя файла заключено
в кавычки, то поиск производится в текущем каталоге, в котором содержится основной
файл исходного текста. Если в текущем каталоге данного файла нет, то поиск
производится в каталогах, определенных именем пути в опции -i препроцессора. Если и
там файла нет, то просматривается стандартный каталог.
17
Командные строки препроцессора используются для условной компиляции различных
частей исходного текста в зависимости от внешних условий. Условной компиляцией
называется выборочная компиляция только тех частей программы, которые
удовлетворяют определенным условиям. Например, можно скомпилировать только те
части программы, которые необходимы для конкретной версии системы.
Условная компиляция обладает следующими достоинствами:
Обеспечивается средство параметризации во время компиляции. Например, такая
возможность может быть использована для генерации программ с различной
структурой.
Обеспечивается эффективное использование оперативной памяти, поскольку во время
выполнения нет необходимости держать в памяти неиспользуемые коды программы.
Обеспечивается возможность принятия решений во время компиляции, а не во время
выполнения. Часто это оказывается более эффективным подходом.
Для условной компиляции используется инструкция препроцессора if. Она имеет две
формы - с частью else и без нее:
#if - заголовок
текстовые строки для случая "истина"
#endif
и
#if - заголовок
текстовые строки для случая "истина"
#else
текстовые строки для случая "ложь"
#endif
где if - заголовок является управляющей строкой препроцессора, а текстовые строки
могут содержать произвольный текст. Управляющая строка препроцессора if-заголовка
содержит условие, на основе анализа которого производится выбор соответствующих
текстовых строк:
#if константное_выражение
Пример:
#ifdef ABC
Истина, если идентификатор ABC определен ранее
командой #define.
#ifndef идентификатор
Пример:
#ifndef ABC
Истина, если идентификатор ABC не определен
в настоящий момент.
#else
...
#endif
Если предшествующие проверки #if, #ifdef или #ifndef дают значение Истина, то
строки от #else до #endif игнорируются при компиляции. Если эти проверки дают
значение Ложь, то строки от проверки до #else, а при отсутствии #else - до #endif,
игнорируются. Команда #endif обозначает конец условной компиляции.
Пример:
#ifdef DEBUG
fprintf (stderr, "location. X=%dn",x);
#endif
При помощи команд препроцессора можно изменить номер текущей строки или имя
компилируемого файла:
18
#line целая_константа "имя_файла"
Пример:
#line 20 "ABC"
Препроцессор изменяет номер текущей строки и имя компилируемого файла. Имя файла
может быть опущено.
Замечание.
Хотя препроцессоры и расширяют возможности языков программирования, их
использование не лишено недостатков: использование препроцессоров требует
дополнительного просмотра текста программы и, как следствие, добавочного времени.
19
3. Лекция: Операции.
-Основные операции.
-Дополнительные операции.
-Перечень операций языка Си.
Основные операции
Рассмотрим способы обработки данных - для этого язык Си имеет широкий набор
возможностей. Основные арифметические операции: сложения, вычитания, умножения,
деления. Операции в языке Си применяются для представления арифметических
действий. Например, выполнение операции + приводит к сложению двух величин,
стоящих слева и справа от этого знака. Рассмотрим операции =, +, -, *, /. В языке Си нет
операции возведения в степень.
Операция присваивания: =
В языке Си знак равенства не означает "равно". Он означает операцию присваивания
некоторого значения. С помощью оператора
yar=2004;
переменной c именем yar присваивается значение 2004, т.е. элемент слева от знака = -
это имя переменной, а элемент справа - ее значение. Мы называем символ = операцией
присваивания. В этой операции действие выполняется справа налево.
Возможно, различие между именем переменной и ее значением покажется
незначительным? В таком случае давайте рассмотрим следующий оператор:
i=i+1;
C математической точки зрения это бессмыслица. Если вы прибавляете единицу к
конечному числу, результат не может быть равен исходному числу. Но как оператор
присваивания, данная строка имеет вполне определенный смысл, который можно
выразить, например, такой фразой. Взять значение переменной с именем i, к нему
прибавить 1, а затем присвоить новое значение переменной с именем i.
Оператор вида
2004=yar;
на языке Си не имеет смысла, поскольку 2004 - число. Мы не можем присвоить константе
какое-то значение; ее значением является она сама. Поэтому, помните, что элемент,
стоящий слева от знака =, всегда должен быть именем переменной. Операнд - это то, над
чем выполняются операции. Например, можно описать процесс "поедания" картошки как
применения операции "поедание" к операнду "картошка".
Операция присваивания в языке Си представляется более интересной, чем в большинстве
других языков. Рассмотрим простую программу:
/* таблица результатов по шахматам */
main( )
{
int l, m, n;
n=m=l=165;
printf("l m nn");
printf("Счет первой партии %4d %8d %8dn", l, m, n);
}
Присваивания выполняются справа налево: сначала переменная l получает значение 165,
затем переменная m и наконец n. В языке Си имеется несколько других операций
присваивания, которые отличаются от описанной операции. Их мы рассмотрим попозже.
Представим еще один пример простой программы:
/* использование операции присваивания */
main( )
20
{
/* переменные number, ouzo, cost инициализируются конкретными
значениями*/
int number=5;
float ouzo=13.5;
int cost=31000;
printf("number ouzo costn");
printf("number=%d ouzo=%f cost=%dn",
number, ouzo, cost);
}
Операция сложения: +
Выполнение операции + приводит к сложению двух величин, стоящих слева и справа от
этого знака. Например, в результате работы оператора
printf("%d", 100 + 65);
на печать будет выведено число 165, а не выражение 100+65. Операнды могут быть как
переменными, так и константами. Операция + называется "бинарной", или
"диадической". Эти названия отражают тот факт, что она имеет дело с двумя операндами.
Пример:
i=j+2;
Переменной i присваивается значение переменной j плюс 2.
Операция вычитания: -
Выполнение операции вычитания приводит к вычитанию числа, расположенного справа
от знака -, из числа, стоящего слева от этого знака. Оператор
n = 163.00 - 100.00;
присваивает переменной n значение 63.00.
Операция изменения знака: -
Знак минус используется для указания или изменения алгебраического знака некоторой
величины. Например, в результате выполнения последовательности операторов
teg = -15;
get = -teg;
переменной get будет присвоено значение 15. Когда знак используется подобным
образом, данная операция называется "унарной". Такое название указывает на то, что она
имеет дело только с одним операндом.
Пример:
x = -x;
Операция изменяет алгебраический знак x.
Операция умножения: *
Операция умножения обозначается знаком *. При выполнении оператора
z = 3 * x
значение переменной x умножается на 3, и результат присваивается переменной z.
Операция деления: /
В языке Си символ / указывает на операцию деления. Величина, стоящая слева от этого
знака, делится на величину, расположенную справа от этого знака. Например, в результате
выполнения оператора
l = 126.0 / 2.0;
переменной l будет присвоено значение 63.0. Над данными целого типа операция
деления производится не так, как над данными с плавающей точкой: в первом случае
21
результат будет целым числом, а во втором - числом с плавающей точкой. В языке Си
принято правило, согласно которому дробная часть у результата деления целых чисел
отбрасывается. Это действие называется "усечением".
Рассмотрим пример, как выполняется усечение и чем деление целых чисел отличается от
деления чисел с плавающей точкой:
main( )
{
printf("деление целых: 5/4 это %d n", 5/4);
printf("деление целых: 6/3 это %d n", 6/3);
printf("деление целых: 7/4 это %d n", 7/4);
printf("деление чисел с плавающей точкой: 7./4. это %2.2f
n", 7./4.);
printf("смешанное деление: 7./4 это %2.2f n", 7./4);
}
Последний пример на использование смешанных типов, т.е. деление вещественного числа
на целое. Язык Си менее строго подходит к подобным вопросам, и позволяет выполнять
такие операции.
! Смешения типов следует избегать!
Результат выполнения указанной программы:
деление целых: 5/4 это 1
деление целых: 6/3 это 2
деление целых: 7/4 это 1
деление чисел с плавающей точкой: 7./4. это 1.75
смешанное деление: 7./4 это 1.75
Результат деления целых чисел округляется не до ближайшего целого, а всегда до
меньшего целого числа. Когда мы смешиваем целые числа и числа с плавающей точкой,
результат будет таким же, как если бы оба операнда были числами с плавающей точкой. В
этом случае перед делением целое преобразуется в число с плавающей точкой.
Для того чтобы понять, что происходит в тех случаях, когда в одном операторе
используется несколько операций, рассмотрим порядок выполнения операций.
Совершенно очевидно, что изменение порядка выполнения действий может приводить к
различным результатам. В языке Си каждой операции назначается уровень старшинства.
Умножение и деление имеют более высокий уровень, чем сложение и вычитание, поэтому
они выполняются первыми. Если же две операции имеют один и тот же уровень
старшинства, они выполняются в том порядке, в котором присутствуют в операторе. Для
большинства операций обычный порядок - слева направо. Операция = является
исключением из этого правила. Многие программисты предпочитают представлять
порядок вычислений с помощью дерева выражений. Например, выражение
(a+b)*c
будет выглядеть так:
*
/ 
+ c
/ 
a b
Мы можем составить таблицу правил описанных нами операций. В дальнейшем мы
приведем таблицу, где содержатся правила, относящиеся ко всем операциям языка Си.
Таблица 1.1. Операции в порядке уменьшения уровня старшинства
Операции Порядок вычисления
( ) слева направо
22
- (унарный) слева направо
* / слева направо
+ - (вычитание) слева направо
= справа налево
Дополнительные операции
В языке Си имеется около сорока операций. Те операции, которые мы рассмотрели,
являются наиболее общеупотребительными. Рассмотрим еще три операции, наиболее
используемые программистами.
Операция деления по модулю: %
Эта операция используется в целочисленной арифметике. Ее результатом является остаток
от деления целого числа, стоящего слева от знака операции, на число, расположенное
справа от нее. Например, 63%5, читается как 63 по модулю 5, имеет значение 3, т.к.
12*5+3.
В результате выполнения оператора
minutes=time%60;
переменной minutes будет присвоено значение остатка от деления time на 60.
Операция увеличения: ++
Операция увеличения осуществляет следующее простое действие: она увеличивает
значение своего операнда на единицу. Существуют две возможности использования
данной операции: первая, когда символы ++ находятся слева от переменной (операнда), -
"префиксная" форма, и вторая, когда символы ++ стоят справа от переменной, -
"постфиксная" форма. Эти две формы указанной операции различаются между собой
только тем, в какой момент осуществляется увеличение операнда. Префиксная форма
изменяет значение операнда перед тем, как операнд используется. Постфиксная форма
изменяет значение после того как операнд использовался.
В примере,
j=i++;
переменной j сначала присваивается значение i, затем значение переменной i
увеличивается на 1.
Операция уменьшения: --
Каждой операции увеличения соответствует некоторая операция уменьшения, при этом
вместо символов ++ мы используем --. Когда символы -- находятся слева от операнда -
"префиксная" форма операции уменьшения. Если символы -- стоят справа от операнда -
это "постфиксная" форма операции уменьшения.
В соответствии с принятым в языке Си порядком вычислений операции увеличения и
уменьшения имеют очень высокий уровень старшинства. Только круглые скобки
обладают более высоким приоритетом. Поэтому выражение a/b++ означает (a)/(b++), а не
(a/b)++.
! Не применяйте операции увеличения или уменьшения к переменной, присутствующей в
более чем одном аргументе функции. Не применяйте операции увеличения или
уменьшения к переменной, которая входит в выражение более одного раза.
Перечень операций языка Си
23
Рассмотрим множество операций языка Си. Описанные операции входят в это множество.
Язык Си отличается их большим разнообразием. В этом разделе будет обсуждаться их
семантика. Каждая операция характеризуется уровнем приоритета и порядком, в котором
эти операции выполняются - слева направо или справа налево. Если все операции
выражения имеют один и тот же уровень приоритета, то значение выражения вычисляется
слева направо в соответствии с порядком выполнения операций. Все операции с одним и
тем же уровнем приоритета имеют один и тот же порядок. Однако если в выражении
имеются операции с различными уровнями приоритета, то сначала выполняются операции
с наивысшим уровнем приоритета, затем - следующего за ним приоритета и так далее в
порядке убывания приоритета. Операции одного уровня приоритета выполняются в
последовательности, указанной их порядком.
Операции, уровень приоритета которых равен 1
Операции вызова функции, индексирования и выбора.
В качестве операций языка Си рассматриваются также скобки в вызове функции,
квадратные скобки для индексирования массивов, точка и стрелка вправо для выбора
компонентов структуры или объединения. Уровень этих операторов равен 1, все операции
выполняются слева направо.
Операция вызова функции: ( )
Пример 1:
fe(e1, e2,...,en);
Вызов функции fe с аргументами e1, e2, ..., en. Значением этого выражения является
значение, которое возвращает функция.
Пример 2:
x = sqrt (y);
Операция индексирования массива: []
Синтаксис:
array [2]
Значением выражения является третий элемент массива.
Присвоение значения 26 одиннадцатому элементу массива записывается таким образом:
array[10]=26;
Первый элемент массива описывается выражением array[0] (более подробно о
массивах описано в лекции 12).
Операция выбора компонентов структуры или объединения: .
Синтаксис:
struct.element
Значением этого выражения является элемент element структуры struct или
объединения (см. лекцию 14). Оператор:
struct.element=1963;
присваивает значение 1963 этому элементу.
Операция выбора компонентов структуры с указателем: ->
Синтаксис:
my_birthday->day,
my_birthday - указатель на структуру.
Оператор:
my_birthday->day=26;
присваивает значение 26 структурной переменной day, на которую указывает
my_birthday.
24
Операции, уровень приоритета которых равен 2
Унарные операции.
Для унарных операций требуется только один операнд; эти операции либо префиксные,
либо префиксные и постфиксные. Операция sizeof имеет два варианта: префиксная
операция и унарная операция.
Операция косвенной ссылки: *
Это указатель на любой тип T, кроме void. Тип результата T.
Использование:
*pe
Значением выражения является переменная, адресуемая указателем pe.
Пример 1:
*ptr=c;
Пример 2:
*fpe;
Значением выражения является функция, адресуемая указателем fpe.
Пример 3:
fpe=*funcname;
(*fpe)(arg1, arg2);
Операция получения адреса: &
У этой операции тип операнда есть переменная любого типа, кроме void. Тип результата
- указатель на Т.
Использование:
&v
Значением выражения является адрес переменной v.
Пример:
myptr=&n;
Операция отрицания: -
Тип операнда - арифметический. Тип результата: unsigned, long, double, int.
Операция логического отрицания: !
Тип операнда - арифметический или указатель. Тип результата - int. Если операнд равен
0, то результат равен 1 и наоборот.
Пример:
if(!good) printf("not good");
Операция дополнения до 1: ~
Тип операнда - интегральный. Тип результата: int, long, unsigned.
Пример:
opposite=~mask;
Дополнение до единицы значения mask. Результат присваивается переменной opposite.
Операция увеличения: ++
Тип операнда - арифметический или указатель. Тип результата: int, unsigned, long,
double, указатель. Значение операнда увеличивается, и становится новым значением
операнда. Значение указателя увеличивается на величину указываемого объекта, значения
других операндов увеличиваются на единицу.
Операция увеличения, постфиксная: ++
25
Тип операнда - арифметический или указатель. Тип результата: int, unsigned, long,
double, указатель. Значение операнда увеличивается, но возвращается старое значение
операнда. Значение указателя увеличивается на величину указываемого объекта, другие
операнды увеличиваются на единицу.
Использование:
iv++
Увеличение iv на 1. Значением этого выражения является значение iv до увеличения.
Пример:
j=i++;
Использование:
pv++;
Увеличение указателя pv на 1, так что он будет указывать на следующий объект того же
типа. Значением этого выражения является значение pv до увеличения.
Пример:
*ptr++=0;
Присвоить значение 0 переменной, на которую указывает ptr, затем увеличить значение
указателя ptr так, чтобы он указывал на следующую переменную того же типа.
Операция уменьшения: --
Тип операнда - те же, что и для ++. Тип результата - те же, что и для ++.
Использование:
--iv
Уменьшение iv на 1. Значением этого выражения является значение iv после уменьшения.
Пример:
i=--j;
Операция уменьшения (постфиксная): --
Тип операнда - те же, что и для ++ (постфиксная).
Использование:
iv--
Уменьшение iv на 1. Значением этого выражения является значение iv до уменьшения.
Пример:
j=i--;
Операция определения требуемой памяти в байтах: sizeof
Тип операнда - значение любого типа или имени типа. Тип результата - unsigned.
Используется как sizeof (выражение) или sizeof (имя типа).
Пример:
n=sizeof(arname)/sizeof(int);
Число элементов в массиве целых чисел, определяемое как число байт в массиве,
поделенное на число байт, занимаемых одним элементом массива.
Операции, уровень приоритета которых равен 3
Мультипликативные операции.
Порядок выполнения мультипликативных операций - слева направо.
Операция умножения: *
Тип операндов - арифметический. Тип результатов: int, unsigned, long, double.
Использование:
ae1*ae2
Произведение значений ae1*ae2.
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17
Languages b6cc1c17

More Related Content

What's hot

Памятка о php-шниках
Памятка о php-шникахПамятка о php-шниках
Памятка о php-шникахKaterina Starostina
 
Programming history. Algorithm
Programming history. AlgorithmProgramming history. Algorithm
Programming history. AlgorithmIhor Porotikov
 
презентация языки программирования
презентация языки программированияпрезентация языки программирования
презентация языки программированияnhfkzkz
 
История программирования
История программированияИстория программирования
История программированияAndrey1245
 
языки программирования презетнация
языки программирования презетнацияязыки программирования презетнация
языки программирования презетнацияsonyadark
 

What's hot (7)

Памятка о php-шниках
Памятка о php-шникахПамятка о php-шниках
Памятка о php-шниках
 
Programming history. Algorithm
Programming history. AlgorithmProgramming history. Algorithm
Programming history. Algorithm
 
презентация языки программирования
презентация языки программированияпрезентация языки программирования
презентация языки программирования
 
История программирования
История программированияИстория программирования
История программирования
 
Pascal+
Pascal+Pascal+
Pascal+
 
лекция 17
лекция 17лекция 17
лекция 17
 
языки программирования презетнация
языки программирования презетнацияязыки программирования презетнация
языки программирования презетнация
 

Similar to Languages b6cc1c17

C++ Базовый. Занятие 01.
C++ Базовый. Занятие 01.C++ Базовый. Занятие 01.
C++ Базовый. Занятие 01.Igor Shkulipa
 
языки программирования
языки программированияязыки программирования
языки программированияDmitry Kulikov
 
Функции в языке программирования QBasic
Функции в языке программирования QBasicФункции в языке программирования QBasic
Функции в языке программирования QBasickvlar
 
Основные понятия связанные с разработкой ПО: просто о сложном. Лаабе Дмитрий.
Основные понятия связанные с разработкой ПО: просто о сложном. Лаабе Дмитрий.Основные понятия связанные с разработкой ПО: просто о сложном. Лаабе Дмитрий.
Основные понятия связанные с разработкой ПО: просто о сложном. Лаабе Дмитрий.IT-Доминанта
 
языки программирования презетнация
языки программирования презетнацияязыки программирования презетнация
языки программирования презетнацияtimofey_kravchenko
 
Терминология как основной способ поиска разработчиков или как не опозорится п...
Терминология как основной способ поиска разработчиков или как не опозорится п...Терминология как основной способ поиска разработчиков или как не опозорится п...
Терминология как основной способ поиска разработчиков или как не опозорится п...SBTech
 
Programming Concepts
Programming ConceptsProgramming Concepts
Programming ConceptsMister_Lee
 
Algorithms and programming lecture in ru
Algorithms and programming lecture in ruAlgorithms and programming lecture in ru
Algorithms and programming lecture in russuser0562f1
 
Алгоритмизация и программирование С/С++
Алгоритмизация и  программирование С/С++Алгоритмизация и  программирование С/С++
Алгоритмизация и программирование С/С++ssuser0562f1
 
Inroducing SAP ABAP - Presentation with basics SAP ABAP
Inroducing SAP ABAP - Presentation with basics SAP ABAPInroducing SAP ABAP - Presentation with basics SAP ABAP
Inroducing SAP ABAP - Presentation with basics SAP ABAPmikhailshurgulaya
 
терминология vol.2
терминология vol.2терминология vol.2
терминология vol.2SBTech
 
Занятие № 4 Языки и системы программирования. Их назначение и характеристики
Занятие № 4 Языки и системы программирования. Их назначение и характеристикиЗанятие № 4 Языки и системы программирования. Их назначение и характеристики
Занятие № 4 Языки и системы программирования. Их назначение и характеристикиAibek9
 
Никита Вельмаскин - Интерпретатор или думаем над скриптовым движком для Ваше...
Никита Вельмаскин -  Интерпретатор или думаем над скриптовым движком для Ваше...Никита Вельмаскин -  Интерпретатор или думаем над скриптовым движком для Ваше...
Никита Вельмаскин - Интерпретатор или думаем над скриптовым движком для Ваше...IT Share
 
Qasimli aysel 9 r2 klassifikasiya proqrammnoqo obespeceniya
Qasimli aysel 9 r2  klassifikasiya proqrammnoqo obespeceniyaQasimli aysel 9 r2  klassifikasiya proqrammnoqo obespeceniya
Qasimli aysel 9 r2 klassifikasiya proqrammnoqo obespeceniyaaysel9r2
 
Qasimli Aysel 9r2
Qasimli Aysel 9r2  Qasimli Aysel 9r2
Qasimli Aysel 9r2 aysel9r2
 
Технология OpenMP
Технология OpenMPТехнология OpenMP
Технология OpenMPTatyanazaxarova
 
Программирование
ПрограммированиеПрограммирование
Программированиеalecsa
 
Как и зачем можно создать DSL на Python
Как и зачем можно создать DSL на PythonКак и зачем можно создать DSL на Python
Как и зачем можно создать DSL на PythonPyNSK
 
паскаль язык структурного программирования
паскаль   язык структурного программированияпаскаль   язык структурного программирования
паскаль язык структурного программированияЕлена Ключева
 

Similar to Languages b6cc1c17 (20)

C++ Базовый. Занятие 01.
C++ Базовый. Занятие 01.C++ Базовый. Занятие 01.
C++ Базовый. Занятие 01.
 
языки программирования
языки программированияязыки программирования
языки программирования
 
Функции в языке программирования QBasic
Функции в языке программирования QBasicФункции в языке программирования QBasic
Функции в языке программирования QBasic
 
Основные понятия связанные с разработкой ПО: просто о сложном. Лаабе Дмитрий.
Основные понятия связанные с разработкой ПО: просто о сложном. Лаабе Дмитрий.Основные понятия связанные с разработкой ПО: просто о сложном. Лаабе Дмитрий.
Основные понятия связанные с разработкой ПО: просто о сложном. Лаабе Дмитрий.
 
языки программирования презетнация
языки программирования презетнацияязыки программирования презетнация
языки программирования презетнация
 
Терминология как основной способ поиска разработчиков или как не опозорится п...
Терминология как основной способ поиска разработчиков или как не опозорится п...Терминология как основной способ поиска разработчиков или как не опозорится п...
Терминология как основной способ поиска разработчиков или как не опозорится п...
 
Programming Concepts
Programming ConceptsProgramming Concepts
Programming Concepts
 
378 васильев куницын
378 васильев куницын378 васильев куницын
378 васильев куницын
 
Algorithms and programming lecture in ru
Algorithms and programming lecture in ruAlgorithms and programming lecture in ru
Algorithms and programming lecture in ru
 
Алгоритмизация и программирование С/С++
Алгоритмизация и  программирование С/С++Алгоритмизация и  программирование С/С++
Алгоритмизация и программирование С/С++
 
Inroducing SAP ABAP - Presentation with basics SAP ABAP
Inroducing SAP ABAP - Presentation with basics SAP ABAPInroducing SAP ABAP - Presentation with basics SAP ABAP
Inroducing SAP ABAP - Presentation with basics SAP ABAP
 
терминология vol.2
терминология vol.2терминология vol.2
терминология vol.2
 
Занятие № 4 Языки и системы программирования. Их назначение и характеристики
Занятие № 4 Языки и системы программирования. Их назначение и характеристикиЗанятие № 4 Языки и системы программирования. Их назначение и характеристики
Занятие № 4 Языки и системы программирования. Их назначение и характеристики
 
Никита Вельмаскин - Интерпретатор или думаем над скриптовым движком для Ваше...
Никита Вельмаскин -  Интерпретатор или думаем над скриптовым движком для Ваше...Никита Вельмаскин -  Интерпретатор или думаем над скриптовым движком для Ваше...
Никита Вельмаскин - Интерпретатор или думаем над скриптовым движком для Ваше...
 
Qasimli aysel 9 r2 klassifikasiya proqrammnoqo obespeceniya
Qasimli aysel 9 r2  klassifikasiya proqrammnoqo obespeceniyaQasimli aysel 9 r2  klassifikasiya proqrammnoqo obespeceniya
Qasimli aysel 9 r2 klassifikasiya proqrammnoqo obespeceniya
 
Qasimli Aysel 9r2
Qasimli Aysel 9r2  Qasimli Aysel 9r2
Qasimli Aysel 9r2
 
Технология OpenMP
Технология OpenMPТехнология OpenMP
Технология OpenMP
 
Программирование
ПрограммированиеПрограммирование
Программирование
 
Как и зачем можно создать DSL на Python
Как и зачем можно создать DSL на PythonКак и зачем можно создать DSL на Python
Как и зачем можно создать DSL на Python
 
паскаль язык структурного программирования
паскаль   язык структурного программированияпаскаль   язык структурного программирования
паскаль язык структурного программирования
 

More from Anastasia Snegina

птп по ппп 2013 2014
птп по ппп 2013 2014 птп по ппп 2013 2014
птп по ппп 2013 2014 Anastasia Snegina
 
прикл.прогр птп 13 14
прикл.прогр птп 13 14прикл.прогр птп 13 14
прикл.прогр птп 13 14Anastasia Snegina
 
2012 2013 пм спп провидошина
2012 2013  пм спп провидошина2012 2013  пм спп провидошина
2012 2013 пм спп провидошинаAnastasia Snegina
 
2012 2013 пм спп провидошина
2012 2013  пм спп провидошина2012 2013  пм спп провидошина
2012 2013 пм спп провидошинаAnastasia Snegina
 
рп по у пп практике в
рп по у пп практике врп по у пп практике в
рп по у пп практике вAnastasia Snegina
 
рп по пр практике в
рп по пр практике врп по пр практике в
рп по пр практике вAnastasia Snegina
 
рп по у сп практике в
рп по у сп практике врп по у сп практике в
рп по у сп практике вAnastasia Snegina
 
рп по у пп практике вт
рп по у пп практике втрп по у пп практике вт
рп по у пп практике втAnastasia Snegina
 
рп по пр практике вт
рп по пр практике втрп по пр практике вт
рп по пр практике втAnastasia Snegina
 
рп по у сп практике вт
рп по у сп практике втрп по у сп практике вт
рп по у сп практике втAnastasia Snegina
 
рп по у пп практике вт
рп по у пп практике втрп по у пп практике вт
рп по у пп практике втAnastasia Snegina
 
рп по пр практике вт
рп по пр практике втрп по пр практике вт
рп по пр практике втAnastasia Snegina
 
рп по у сп практике вт
рп по у сп практике втрп по у сп практике вт
рп по у сп практике втAnastasia Snegina
 

More from Anastasia Snegina (20)

птп по ппп 2013 2014
птп по ппп 2013 2014 птп по ппп 2013 2014
птп по ппп 2013 2014
 
прикл.прогр птп 13 14
прикл.прогр птп 13 14прикл.прогр птп 13 14
прикл.прогр птп 13 14
 
я.прогр птп
я.прогр птпя.прогр птп
я.прогр птп
 
пп кос вт
пп кос втпп кос вт
пп кос вт
 
пп кос в
пп кос впп кос в
пп кос в
 
пп кос в
пп кос впп кос в
пп кос в
 
2012 2013 пм спп провидошина
2012 2013  пм спп провидошина2012 2013  пм спп провидошина
2012 2013 пм спп провидошина
 
2012 2013 пм спп провидошина
2012 2013  пм спп провидошина2012 2013  пм спп провидошина
2012 2013 пм спп провидошина
 
пп кос вт
пп кос втпп кос вт
пп кос вт
 
рп по у пп практике в
рп по у пп практике врп по у пп практике в
рп по у пп практике в
 
рп по пр практике в
рп по пр практике врп по пр практике в
рп по пр практике в
 
рп по у сп практике в
рп по у сп практике врп по у сп практике в
рп по у сп практике в
 
рп по у пп практике вт
рп по у пп практике втрп по у пп практике вт
рп по у пп практике вт
 
рп по пр практике вт
рп по пр практике втрп по пр практике вт
рп по пр практике вт
 
рп по у сп практике вт
рп по у сп практике втрп по у сп практике вт
рп по у сп практике вт
 
рп по у пп практике вт
рп по у пп практике втрп по у пп практике вт
рп по у пп практике вт
 
рп по пр практике вт
рп по пр практике втрп по пр практике вт
рп по пр практике вт
 
рп по у сп практике вт
рп по у сп практике втрп по у сп практике вт
рп по у сп практике вт
 
лр18
лр18лр18
лр18
 
лр15
лр15лр15
лр15
 

Languages b6cc1c17

  • 1. 1 Основы программирования на языке Си. Содержание. 1. Лекция: Общее знакомство. -Происхождение языка Си. -Достоинства языка Си. -Будущее языка Си. -Использование языка Си. -Использование текстового редактора для подготовки программ. -Исходные и выполняемые файлы. Примеры простой программы. -Пример простой программы на языке Си. -Структура простой программы. 2. Лекция: Данные, символьные строки, директива #define -Основные типы данных. -Описание различных типов, переменные и константы. -Символьные строки. -Препроцессор языка Си. 3. Лекция: Операции. -Основные операции. -Дополнительные операции. -Перечень операций языка Си. 4. Лекция: Операторы. -Выражения. -Простейшие выражения. -Операторы. -Составные операторы. 5. Лекция: Преобразование типов. -Эквивалентность типов. -Преобразование типов. -Неявное преобразование типа. -Арифметические преобразования. -Явное преобразование типов. -Синтаксис типов. 6. Лекция: Функции и переключение ввода-вывода. -Ввод и вывод одного символа. -Буферы. -Чтение одной строки. -Чтение файла. -Переключение и работа с файлами. 7. Лекция: Выбор вариантов. -Выбор вариантов. -Оператор if. -Расширение оператора if. -Операции отношения. -Логические операции. -Операция условия: ?:.
  • 2. 2 -Множественный выбор. 8. Лекция: Циклы и другие управляющие средства. Структурное программирование. -Цикл с предусловием. -Цикл со счетчиком. -Цикл с постусловием. -Другие управляющие операторы. -Структурное программирование. 9. Лекция: Функции. -Создание и использование функций. -Аргументы функции. -Возвращение значений. -Локальные переменные. -Нахождение адресов. -Указатели, первое знакомство. -Функции с переменным количеством аргументов. 10. Лекция: Классы памяти и разработка программ. -Классы памяти и область действия. -Автоматические переменные. -Внешние переменные. -Статические переменные. -Внешние статические переменные. -Регистровые переменные. 11. Лекция: Препроцессор языка Си. -Общие сведения. -Символические константы: #define. -Использование аргументов с #define. -Макроопределение или функция? -Включение файла #include. -Условная компиляция. 12. Лекция: Массивы и указатели. -Указатели и массивы. -Массивы. -Указатели. -Динамические объекты. -Создание динамических объектов. -Доступ к динамическим объектам. -Строки - дополнительные сведения о связи между указателями и массивами. -Инициализация массивов и классы памяти. -Функции. -Операции с указателями. 13. Лекция: Символьные строки и функции над ними. -Строковые константы. -Массивы символьных строк и их инициализация. -Массив и указатель: различия. -Указатели и строки. -Ввод-вывод строк. -Обработка строк. 14. Лекция: Структуры. -Определение структурных переменных. -Доступ к компонентам структуры.
  • 3. 3 -Поля битов в структурах. -Объединения. -Перечисления. -Переменные структуры. -Указатели структуры. -Массив структур. -Переименования типов. 15. Лекция: Библиотека языка Си и файлы ввода-вывода. -Библиотека языка Си содержит множество функций и макроопределений. -Библиотеки меняются от системы к системе, но есть ядро функций (стандартная библиотека). -Распределение памяти. 16. Лекция: Функции в примерах. -Функция получения случайных чисел. -Поиск узлов из простых чисел. -Матрица инцидентности. -Структуры данных. -Работа с файлами. -Все операции со стеком. -Примеры из графики, все преобразования трехмерного пространства.
  • 4. 4 1. Лекция: Общее знакомство. -Происхождение языка Си. -Достоинства языка Си. -Будущее языка Си. -Использование языка Си. -Использование текстового редактора для подготовки программ. -Исходные и выполняемые файлы. Примеры простой программы. -Пример простой программы на языке Си. -Структура простой программы. Происхождение языка Си. Язык программирования Си был разработан и реализован в 1972 году сотрудником фирмы AT&T Bell Laboratories Денисом Ритчи. Прообразом языка Си для Д. Ритчи послужил язык Би, разработанный Кеном Томпсоном. Он является результатом эволюционного развития языков BCPL (Richards, M., "BCPL: A. Tool for Compiler Writing and System Programming", Proc. AFIPS SJCC, 34, 557-566, 1969) и Би (Johnson, S. C., and B. W. Kernighan, "The Programming Language B", Comp. Sci. Tech. Rep. No. 8, Bell Laboratories. 1973). Основным достоинством языка Си по сравнению с языками BCPL и Би является введение в него типов данных. Язык Си был разработан во время создания операционной системы UNIX (OC UNIX). Развитие языка Си продолжалось и после окончания его разработки и касалось, в частности, проверки типов данных и средств, облегчающих перенос программ в другую среду. Например, разработка проекта переноса OC UNIX на компьютер Interdata 8/32 привела к некоторым добавлениям в язык Си, а именно, к включению в язык таких средств, как объединение (union). Позднее были сделаны попытки включения в язык Си средств абстрагирования данных. В настоящее время рассматривается проект стандарта ANSI C - стандарт языка Си Американского национального института и the C Programming Language - Reference Manual, AT&T Bell Laboratories. С языка Си разработаны совместимые по входному языку трансляторы для 40 типов вычислительных систем, начиная от 8-разрядных микропроцессоров и кончая CRAY-1 - одним из самых мощных в настоящее время суперкомпьютеров. В ходе работ по созданию Мобильного Транслятора с языка Си сам он был переработан для повышения мобильности написанных на нем программ. Достоинства языка Си. Особое значение придается гибкости. Язык Си компактен, является относительно маленьким языком программирования. Ввод-вывод не считается частью языка Си, а определяется стандартной библиотекой. Вседозволенность в языке Си является следствием желания как можно больше расширить область его применения. Язык Си удалось сделать относительно маленьким языком программирования за счет того, что в его состав не были включены ввод-вывод и средства для работы со строками. Язык Си был задуман настолько гибким, что эти возможности могли быть реализованы в каждом конкретном случае наиболее удачным образом. Практический опыт использования языка Си показал правильность такого подхода. Большая часть операционной системы UNIX и все утилиты этой операционной системы, включая и несколько трансляторов с языка Паскаль, реализованы на языке Си. Язык программирования является языком программирования с сильной типизацией, если: · каждый объект в этом языке программирования принадлежит точно одному из существующих в этом языке программирования типу данных;
  • 5. 5 · преобразование типов осуществляется только путем преобразования значения из одного типа в другой; · преобразование типов не производится путем трактовки представления значения как данных различных типов. Эксперименты показали, что языки программирования с сильной типизацией способствуют увеличению ясности и надежности программ. Механизм трактовки представления значения как данных различных типов приводит к тому, что использующие его программы не обладают ни надежностью, ни мобильностью. В языке Си допускается неявное преобразование типов для всех базовых типов и указателей. Однако Мобильный Транслятор с языка Си выводит предупреждение о каждом встретившимся в программе случае неявного преобразования типов, в котором участвует указатель. Язык Си быстро становится одним из наиболее важных и популярных языков программирования. Его использование все более расширяется, поскольку часто программисты предпочитают язык Си всем другим языкам после первого знакомства с ним. Сейчас мы упомянем лишь некоторые достоинства Си. Си - современный язык. Он включает в себя те управляющие конструкции, которые рекомендуются теоретическим и практическим программированием. Его структура побуждает программиста использовать в своей работе нисходящее проектирование, структурное программирование и пошаговую разработку модулей. Результатом такого подхода является надежная и читаемая программа. Си - эффективный язык. Его структура позволяет наилучшим образом использовать возможности современных ЭВМ. Написанные на языке Си программы обычно отличаются компактностью и быстротой исполнения. Си - переносимый (или мобильный) язык. Это означает, что программа, написанная на Си для одной вычислительной системы, может быть перенесена с небольшими изменениями или вообще без них, на другую. Си - мощный и гибкий язык. Например, большая часть мощной и гибкой OC UNIX написана на языке Си. Речь идет о компиляторах и интерпретаторах других языков, таких, как Фортран, АПЛ, Паскаль, Лисп, Лого и Бейсик. Кроме того, программы, написанные на Си, используются для решения физических и технических проблем, компьютерной графики и даже производства мультипликационных фильмов. Си - обладает рядом конструкций управления, обычно ассоциируемых с ассемблерами. Си - удобный язык. Он достаточно структурирован, чтобы поддерживать хороший стиль программирования, и вместе с тем не связывает ограничениями. Будущее языка Си. Многие фирмы, производящие программное обеспечение, все чаще обращаются к Си как к удобному языку для реализации своих проектов, поскольку известно, что Си позволяет получить компактные и эффективные программы. И эти программы могут быть легко модифицированы и адаптированы к новым моделям ЭВМ! Языки программирования как С++, Java, С#, UML и т.д. имеют "сишную" семантику. Си используется фирмами, производящими программное обеспечение, студентами, обучающимися программированию. И если вы хотите работать в сфере программотехники, то один из первых вопросов, на который вы должны будете отвечать "Да" - это вопрос "Умеете ли Вы программировать на Си?" Использование языка Си. Си - язык компилируемого типа. Пример языков компилируемого типа: Паскаль, Фортран. Пример языков интерпретируемого типа: Бейсик, Лого. Чтобы дать первое представление
  • 6. 6 о процессе создания программы, приведем упрощенную схему того, что необходимо сделать - начиная от написания программы и заканчивая ее выполнением. 1. Для создания программы на языке Си используйте редактор текстов. 2. Попробуйте оттранслировать вашу программу с помощью удобного для вас компилятора. Компилятор проведет проверку правильности вашей программы. Если компилятор обнаружит ошибки в вашей программе, он выдаст сообщение об этом. Если ошибок не будет, компилятор выполнит перевод программы на внутренний язык ЭВМ, и поместит результат в новый файл. 3. Набрав имя этого нового файла на клавиатуре дисплея, вы можете запустить программу. В некоторых вычислительных системах второй этап может быть разбит на два или три шага. Использование текстового редактора для подготовки программ. У Си нет собственного текстового редактора. В качестве него можно использовать любой из редакторов общего типа. В операционной системе UNIX это чаще всего редакторы ed, ex, edit, emacs, vi. На персональном компьютере это может быть ed, edlin, Wordstar, Volkswriter или любой другой из большого набора редакторов. При работе с некоторыми из них необходимо определить конкретную версию редактора путем задания соответствующих параметров. Например, при использовании редактора Wordstar необходимо ввести параметр N, указывающий на отсутствие документирования. При работе с редактором лучше не ошибаться, набирая текст программы на пульте дисплея, и правильно задать имя файла, в который она будет помещена. Имя файла должно быть допустимым именем в вашей вычислительной системе и иметь расширение .c. Например, sort.c Sort.c Первая часть имени должна напоминать, что программа делает или хотя бы того, кто разработал алгоритм, который в ней реализован. Вторая часть, так называемое расширение файла .с указывает на то, что данный файл содержит текст программы, написанный на языке Си. Расширение файла используется для того, чтобы информировать пользователя и вычислительную систему о типе файла. Предположим, что при помощи редактора мы подготовили программу и поместили ее в файл с именем Nina.c. Текст, который мы набрали на клавиатуре, называется исходным кодом и содержится в исходном файле. Исходный файл - это начальный пункт процесса программирования. Исходные и выполняемые файлы Приведем простенькую программу на языке Си: #include <stdio.h> main( ) { printf("Добро пожаловать!n"); } Все конструкции языка мы рассмотрим в последующих лекциях. Если эту программу оттранслировать, то получим файл с выполняемой программой. В результате работы этой программы на дисплей будет выведено предложение: "Добро пожаловать!". Наша программа, несмотря на свою лаконичность и простоту, для компьютера является совершенно бессмысленным набором символов, так как он не понимает директив #include или printf. Компьютер понимает только специальный язык, называемый машинным кодом,
  • 7. 7 т.е. набор последовательностей двоичных цифр, например 101000101. Если мы хотим, чтобы компьютер выполнил программу, мы должны осуществить перевод (трансляцию) кода, написанного на Си (исходного) в ее код (машинный). В результате этих действий будет получен выполняемый файл. Процесс перевода (трансляции) удалось переложить на сам компьютер. Программы, переводящие исходный код в машинный код, называются компиляторами. Детали процесса перевода зависят от особенностей конкретной системы. В некоторых компиляторах с языка Си, работающих на персональных ЭВМ, реализован альтернативный способ трансляции. В процессе перевода получается файл с расширением .obj, затем используется системный компоновщик для получения файла с выполняемой программой, т.е. файла с расширением .exe. Почему компиляция, а не интерпретация? Дело в том, что после компиляции получается более эффективный конечный продукт, чем при интерпретации. Пример простой программы на языке Си Рассмотрим простую программу на языке Си: #include <stdio.h> main( )/*простая программа*/ { int courses; courses=30; printf("Сколько учебных курсов на сайте"); printf(" www.intuit.ru?n"); printf("Более %d. Но будет еще больше!n", courses); } Давайте, выполним эту программу. Сначала используем текстовый редактор для создания файла, содержащего текст программы. Этому файлу нужно присвоить какое-то имя. Допустим - intuit.c . Выполним компиляцию программы. После запуска программы, при условии отсутствия синтаксических ошибок, результат должен выглядеть следующим образом: Сколько учебных курсов на сайте www.intuit.ru? Более 30. Но будет еще больше! Пояснения к программе Мы выполним два просмотра текста программы: во время первого просмотра объясним смысл каждой строки, а во время второго - рассмотрим детали. Первый просмотр #include <stdio.h> - включение другого файла. Эта строка указывает компилятору, что нужно включить информацию, содержащуюся в файле stdio.h. main( ) - имя функции Любая программа, написанная на языке Си, состоит из одной или более функций, являющихся основными модулями, из которых она собирается. Наша программа состоит из одной функции main( ), а круглые скобки указывают именно на то, что main( ) - имя функции. /* простая программа*/ – комментарий /*, */ - открывающая и закрывающая скобки многострокового комментария. Комментарии - это примечания, помогающие понять смысл программы. Они предназначены для читателя, и игнорируются компилятором. { – начало тела функции
  • 8. 8 Открывающая фигурная скобка отмечает начало последовательности операторов - тело, или определение, функции. Конец определения отмечается закрывающей фигурной скобкой – }. int courses; – оператор описания. С помощью такого оператора мы объявляем, что будем использовать в программе переменную courses, которая принимает целые (int) значения. courses = 30; – оператор присваивания Этот оператор служит для присваивания переменной courses значения 30. printf("Сколько учебных курсов на сайте"); – оператор вывода на печать С его помощью выводится на печать фраза, заключенная в кавычки: Сколько учебных курсов на сайте printf(" www.intuit.ru?n"); – еще один оператор вывода на печать. Этот оператор добавляет слова www.intuit.ru? в конец последней печатаемой фразы. Комбинация символов n указывает компилятору на начало новой строки. printf("Более %d. Но будет еще больше!n",courses); – этот оператор выводит на печать значение переменной courses, равное 30, содержащееся в кавычках. Символы %d указывают компилятору, где и в какой форме печатать значение переменной courses. } - конец Программа завершается закрывающей фигурной скобкой. Второй просмотр #include <stdio.h> Файл с именем stdio.h является частью пакета, имеющегося в любом компиляторе языка Си и содержащего информацию о вводе-выводе. В качестве имени файла используется аббревиатура английских слов: standard input/output header - заголовок стандартного ввода-вывода. Программисты называют набор данных, содержащийся в начале файла, заголовком. Строка "#include <stdio.h>" даже не является оператором языка Си. Символ # указывает, что она должна быть обработана "препроцессором" языка Си. Препроцессор осуществляет некоторую предварительную обработку текста программы перед началом компиляции. main( ) Программа, написанная на языке Си, всегда начинает выполняться с функции, называемой main( ). Скобки указывают на то, что main( ) - имя функции. Функция - это основные модули программы, написанные на языке Си. В круглых скобках в общем случае содержится информация, передаваемая этой функции. В нашем случае передача информации отсутствует и, следовательно, в скобках ничего не содержится. Файл, содержащий программу, может иметь любое имя с тем ограничением, что оно должно удовлетворять системным соглашениям, и оканчиваться символом с. Например, game.c. /* простая программа*/ Комментарии облегчают процесс понимания программы. Длинный комментарий может помещаться на отдельной строке или даже занимать несколько строк. Все, что находится между символом, указывающим на начало комментария /*, и символом, указывающим на его конец */, игнорируется компилятором. {,} Фигурные скобки { } отмечают начало и конец тела функции. int courses; Это оператор описания переменной. В нашей программе в теле функции используется переменная courses, и с помощью слова int объявляется, что переменная courses принимает целые значения. Точка с запятой в конце строки указывает на то, что в ней
  • 9. 9 содержится оператор языка Си, причем этот символ является частью оператора, а не разделителем операторов. int служит ключевым словом, определяющим один из основных типов данных языка Си. Ключевыми словами называются специальные зарезервированные слова, используемые для построения фраз языка. В языке Си все переменные должны быть объявлены. Это означает, что мы должны привести список всех используемых переменных и указать тип каждой из них. Имя переменной нужно давать осмысленно. Оно может содержать от одного до восьми символов. Фактически мы можем использовать и большее их число, но компилятор пропустит все символы, начиная с девятого. Идентификатор переменной - имя переменной. Для обозначения имени переменной разрешается использовать строчные и прописные буквы, цифры и символ подчеркивания, считающийся буквой. Первым символом должна быть обязательно буква. Например, courses, cat_1, _total - правильные идентификаторы, а $courses*, 1cat, -total - неправильные. Переменные можно описывать по мере необходимости, но лучше размещать операторы объявления переменных в начале программы. Любая программа, написанная на языке Си, не будет выполняться, если не описать все используемые переменные. courses=30; Оператор присваивания является одним из основных средств языка. Приведенную строку программы можно интерпретировать так: присвоить переменной courses значение 30. При описании переменной courses была выделена ячейка памяти, и только теперь в результате выполнения оператора присваивания переменная получает свое значение. При желании мы могли бы присвоить ей другое значение, поэтому имя courses и обозначает переменную. В данной программе используется стандартная функция языка Си - printf( ). Строка символов, заключенная в скобки, является информацией, передаваемой функции printf( ) из главной функции main( ). Такая информация называется аргументом. В первом случае аргументом является "Сколько учебных курсов на сайте". Данная строка дает пример того, как вызывать функцию или обратиться к ней, программируя на языке Си. Для этого требуется только указать имя функции и заключить требуемый аргумент, или аргументы, в скобки. Когда при выполнении функции программа достигнет этой строки, управление будет передано указанной функции. Когда выполнение функции будет завершено, управление вернется обратно в исходную, вызывающую программу. Символы n служат директивой начать новую строку на устройстве вывода. Комбинация n представляет один символ, называемый "новая строка". Его смысл формулируется так: начать вывод новой строки с самой левой колонки. Символ "новая строка" служит одним из примеров того, что называется "управляющей последовательностью". Управляющая последовательность начинается с "". Структура простой программы Познакомимся с несколькими общими правилами, касающимися программ, написанных на языке Си. Программа состоит из одной или более функций, причем какая-нибудь из них (главная) обязательно должна называться main( ). Описание функции состоит из заголовка и тела. Заголовок состоит из директив препроцессора типа #include и имени функции. Отличительным признаком имени функции служат круглые скобки, а аргумент может и отсутствовать. Тело функции заключено в фигурные скобки и представляет собой набор операторов, каждый из которых оканчивается символом "точка с запятой". Дополнительный пример.
  • 10. 10 Здесь мы приведем еще пример. Мы использовали только стандартную функцию printf( ). В данном примере мы демонстрируем, как включить и использовать функцию, которую мы сами написали: dir( )/* dir*/ { printf("На сайте проекта www.intuit.ru n"); printf(" большое количество учебных курсовn"); } main ( ) { dir ( ); printf("Над их созданием работают n"); printf(" профессора российских вузов.n"); } Результат работы программы выглядит следующим образом: На сайте проекта www.intuit.ru большое количество учебных курсов Над их созданием работают профессора российских вузов. Функция dir( ) определяется точно так же, как и функция main( ) - ее тело заключено в фигурные скобки. Вызов функции осуществляется путем простого указания ее имени, включая круглые скобки.
  • 11. 11 2. Лекция: Данные, символьные строки, директива #define. -Основные типы данных. -Описание различных типов, переменные и константы. -Символьные строки. -Препроцессор языка Си. Основные типы данных Чтобы реализовать алгоритм, программам необходимо работать с данными - числами, символами, т.е. объектами, которые несут в себе информацию, предназначенную для использования. Некоторые данные устанавливаются равными определенным значениям еще до того, как программа начинает выполняться, а после ее запуска такие значения сохраняются неизменными на всем протяжении работы программ. Эти данные называются константами. Данные, которые могут изменяться, или же им могут быть присвоены значения во время выполнения программы, называются переменными. Различие между переменной и константой очевидно: во время выполнения программы значение переменной может быть изменено (например, с помощью присваивания), а значение константы изменить нельзя. Кроме различия между переменными и константами существует еще различие между типами данных. Некоторые данные в программе являются числами, некоторые - символами. Компилятор должен уметь идентифицировать и обрабатывать данные любого типа. В языке Си предусмотрено использование нескольких основных типов данных. Если величина есть константа, то компилятор может распознать ее тип только по тому виду, в котором она присутствует в программе. В случае переменной необходимо, чтобы ее тип был объявлен в операторе описания. В стандарте языка Си используется семь ключевых слов, указывающих на различные типы данных: int long short unsigned char float double Первые четыре ключевых слова используются для представления целых, т.е. целых чисел без десятичной, дробной части. Если мы хотим подчеркнуть, что целое не может быть отрицательным, то нужно к целому подписывать ключевое слово unsigned, например, unsigned short. char предназначено для указания на буквы и другие символы. float, double используются для представления чисел с десятичной точкой. Типы, обозначаемые этими ключевыми словами, можно разделить на два класса по принципу размещения в памяти машины. Первые пять ключевых слов определяют целые типы данных, последние два - типы данных с плавающей точкой. Дадим краткое объяснение их смысла. Термины бит, байт, слово используются для описания как элементов данных, которые обрабатывает компьютер, так и элементов памяти. Рассмотрим эти понятия относительно памяти. Наименьшая единица памяти называется бит. Она может принимать одно из двух значений: 0 или 1. Байт в большинстве машин состоит из 8 бит. Всего в байтовом формате можно представить 256 (два в восьмой степени) различных комбинаций из нулей и единиц. Эти комбинации можно использовать для представления целых чисел в диапазоне от 0 до 255 или для кодирования набора символов. Слово является естественным элементом памяти. Есть ЭВМ, у которых слово равно 8 битам, 16 битам, 32 битам или 64 битам.
  • 12. 12 Описание различных типов, переменные и константы Целые числа. У целого числа никогда не бывает дробной части. Представив целое число в двоичном виде, его нетрудно разместить в машине. Например, число 3 в двоичном виде выглядит как 11. Если его поместить в слово 32-разрядной машины, необходимо первые 30 бит установить в 0, а последние 2 бита - в 1. Числа с плавающей точкой. Числа с плавающей точкой соответствуют тому, что математики называют вещественными числами. Способ кодирования, используемый для помещения в память числа с плавающей точкой, полностью отличается от размещения целого числа. Числа с плавающей точкой представляют в виде дробной части и порядка числа, а затем обе части размещают в памяти. Все данные типов int, short, long являются числами со знаками, т.е. значениями этих типов могут быть только целые числа - положительные, отрицательные и нуль. Один бит используется для указания знака числа, поэтому максимальное число со знаком, которое можно представить в слове, меньше, чем максимальное число без знака. Описание данных целого типа. При описании данных необходимо написать только тип, за которым должен следовать список имен переменных. Например, int dog, rad, nina. В качестве разделителя между именами переменных необходимо использовать запятую. Целые константы. Согласно правилам языка Си, число без десятичной точки и без показателя степени рассматривается как целое. Поэтому компилятор по записи константы определяет, целая она или вещественная. Если нужно ввести константу типа long, то нужно указать признак L или l в конце числа. Если при записи константы целое начинается с цифры 0, то эта константа интерпретируется как восьмеричное число, если же целое начинается с символа 0x или 0X - как шестнадцатеричное число. Инициализация переменных целого типа. Константы применяются при инициализации переменных. Это означает присваивание переменной некоторого значения перед началом обработки. Можно инициализировать переменную в операторе описания. Например, int dog=5; int rad=077; int nina=0X99; ! В языке Си введено три класса целых чисел, имеющих различные размеры. Тем самым пользователю языка Си предоставили возможность выбора типа переменной с требованием задачи. Например, если переменная типа int занимает одно слово, а переменная типа long занимает два слова, значит, тип long позволяет обрабатывать большие числа. Если в задаче не используются большие числа, то незачем вводить в программу переменные типа long, т.к. если вместо числа, занимающего одно слово в памяти, используется число, занимающее два слова, работа машины замедляется. Описание данных типа unsigned. Этот тип является модификатором типов: int, short, long. Мы можем использовать комбинацию ключевых слов unsigned int, unsigned short, unsigned long, т.е.
  • 13. 13 переменная не может принимать отрицательного значения. Для указания типа unsigned int достаточно написать unsigned. Целые беззнаковые константы записываются так же, как и обычные константы, запрещено только использование знака минус. Например, unsigned age; Описание данных типа char. Этот тип определяет целые числа без знака в диапазоне от 0 до 255. Такое целое обычно размещается в одном байте памяти. Для описания символьной переменной применяется ключевое слово char. Правила описания более чем одной переменной и инициализации переменных остаются теми же, что и для других основных типов. Например, char dog, cat; Символьные константы. Символы в языке Си заключаются в апострофы. Например, char dog; dog='b'; Если апострофы опущены, то компилятор считает, что используется неописанная переменная b. В стандартном языке Си значением переменной или константы типа char могут быть только одиночные символы. Примеры символьных констант: 'A', 'a', '7', '$'. Специальные (управляющие) символьные константы. Новая строка (перевод строки) 'n' Горизонтальная табуляция 't' Вертикальная табуляция 'v' Возврат на шаг 'b' Возврат каретки 'r' Перевод формата 'f' Обратная косая '' Апостроф ''' Кавычки '"' Нулевой символ (пусто) '0' Кроме того, любой символ может быть представлен последовательностью трех восьмеричных цифр: 'ddd'. Символьные константы считаются данными типа int. Строковые константы. Строковая константа представляется последовательностью символов кода ASCII, заключенной в кавычки. Например, "Это строковая константа" В конце каждой строки компилятор помещает нулевой символ '0', отмечающий конец данной строки. Каждая строковая константа, даже если она идентична другой строковой константе, сохраняется в отдельном месте памяти. Если необходимо ввести в строку символ кавычек ("), то перед ними надо поставить символ обратной косой (). В строку могут быть введены любые специальные символьные константы, перед которыми стоит символ . Символ и следующий за ним символ новой строки игнорируется. Перечисляемые константы. Имена, указанные в описании перечисляемых констант, трактуются как целые числа (см. описание перечисления).
  • 14. 14 Описание данных типа float и double. Числа с плавающей точкой в языке Си описываются типом float. Числа с плавающей точкой аналогичны числам в обычной алгебраической записи, используемой при работе с очень большими или малыми числами. Пример алгебраической записи чисел с плавающей точкой: Число Алгебраическая запись Запись для ввода в машину 5000 = 5.0 * 103 = 5.0e3 0.000077 = 7.7 * 10-5 = 7.7e-5 Обычно для размещения в памяти числа с плавающей точкой отводится 32 бита - 8 бит для представления порядка и знака и 24 бита - для мантиссы, т.е. коэффициента при степени десяти. Для представления данных типа double (вычисление с двойной точностью) для представления чисел используется удвоенное число битов. Другой способ определения данных типа double заключается в использовании ключевых слов long float. Переменные с плавающей точкой описываются и инициализируются таким же образом, что и переменные целого типа. Например, float dog, cat, bigword=5.77e+34; Константы с плавающей точкой. В языке Си имеется несколько возможностей записи констант с плавающей точкой. Наиболее общая форма записи константы - это последовательность десятичных цифр со знаком, включающим в себя десятичную точку, затем символ e или Е и показатель степени по основанию 10 со знаком. Знак “+” можно не писать. Ниже приведено несколько правильно записанных констант с плавающей точкой: 1.1e+12 3.14159 ! Во время разработки программы необходимо составить список требуемых переменных и указать при этом, какого они должны быть типа. Описывайте эти данные в самом начале тела функции, в которой они используются. Имена переменных выбирайте таким образом, чтобы они указывали на их смысл. При инициализации переменной следите за тем, чтобы тип константы соответствовал типу переменной, хотя язык Си рассматривает такие несоответствия менее жестко, чем Паскаль, но лучше учиться избегать дурного тона в программировании! Символьные строки Символьная строка - это последовательность символов, возможно пустая (""). Рассмотрим пример: "Большой спрос на образование в области информационных дисциплин объясняется не только популярностью компьютеров в современном обществе, но и реальной пользой от их применения." Кавычки не являются частью строки. Они вводятся только для того, чтобы отметить ее начало и конец. В языке Си нет специального типа, который можно было бы использовать для описания строк. Вместо этого строки представляются в виде "набора" элементов типа char. Это означает, что символы в строке можно представить расположенными в соседних ячейках памяти - по одному символу в ячейке. Символ 0 в языке Си используется для того, чтобы отмечать конец строки. Нуль-символ не выводится на печать и в таблице кода ASCII (American Standard Code for Information Interchange) имеет номер
  • 15. 15 0. Наличие нуль-символа означает, что количество ячеек массива символов должно быть на одну больше, чем число символов строки. Массив можно представить как совокупность нескольких ячеек памяти, объединенных в одну строку. Массив - это упорядоченная последовательность элементов данных одного типа. В нашем примере мы создали массив из 177 ячеек памяти, в каждую из которых можно поместить один символ типа char. Это можно сделать с помощью оператора описания: char String[177]; Квадратные скобки указывают, что переменная String - массив из 177 элементов, а char задает тип каждого элемента. Длину строки в символах (без завершающего символа) определяет функция strlen( ). Обращение к ней в нашем примере выглядит так: strlen(String); Результат - целое число. Препроцессор языка Си Вернемся к константам. Чтобы ввести ту или иную константу в программу, нужно указать ее фактическое значение, как было сказано выше. Можно использовать вместо этого "символические константы" и позволить компилятору заменить символические константы числами. Как можно создать такую константу? Можно это сделать так: float cost = 0.0012; Такой способ задания констант в больших программах неэкономичен. В Си имеется другой, лучший способ. Этот способ реализуется с помощью препроцессора языка Си. Препроцессор дает возможность задавать константы. Для этого в начало программы нужно добавить строку, аналогичную следующей: #define COST 0.0012 При компиляции программы каждый раз, когда появится переменная COST, она будет заменяться величиной 0.0012. Такой процесс называется подстановкой во время компиляции. Замечание по поводу формата: сначала идет ключевое слово #define (оно должно начинаться с самой левой позиции), потом идет символическое имя константы, а затем ее величина. Символ "точка с запятой" не используется, потому что это не оператор языка Си. Если в качестве первого символа в строке программы используется символ #, то эта строка является командной строкой препроцессора (макропроцессора). Командная строка препроцессора заканчивается символом перевода на новую строку. Если непосредственно перед концом строки поставить символ обратной косой (), то командная строка будет продолжаться на следующей строке программы. Препроцессор используется для обработки текста программы до этапа ее компиляции. Обычно препроцессоры служили средством расширения языков с целью обеспечения дополнительных возможностей. Несмотря на бесчисленное множество препроцессоров, созданных для расширения возможностей языков программирования, все они были нестандартными. Для некоторых языков, например для языков общего назначения ПЛ/1 и Си, препроцессоры поставлялись как часть их стандартной среды. Препроцессор для языка Си обеспечивает средства для определения макросов, определения констант, включения файлов и условную компиляцию. Препроцессор языка Си вызывается автоматически при обращении к компилятору. Программа может быть обработана только препроцессором без компиляции, если в команде сс указать ключ -Е: cc -E имя_файла Результат работы препроцессора помещается в поток стандартного вывода stdout. Обработка программы препроцессором без компиляции позволяет программисту проанализировать действие определений препроцессора и макровызовов.
  • 16. 16 ! Символическую константу после #define лучше писать прописными буквами. В процессе использования языка Си выработалась традиция писать константы большими буквами. Если при просмотре программы встречается имя, написанное прописными буквами, сразу становится ясно, что это константа, а не переменная. Давайте не нарушать традицию! Директиву #define можно использовать для определения символьных и строковых констант. В первом случае необходимо использовать "апостроф", а во втором кавычки. Например, #define NULL '0' #define USA '$' #define RUSSIA "Рубль" #undef USA Команда #undef USA отменяет предыдущее определение для идентификатора USA. Через команду #define можно задавать выражения - макросы, которые вычисляются и при компиляции подставляются в программу. Воизбежании ошибок при вычислении выражений макроопределения необходимо заключать в скобки: #define идентификатор1 (идентификатор2,_) строка Пример: #define abs(A) (((A)>0) ? (A): - (A)) Каждое вхождение выражения abs(arg) в тексте программы заменяется на ((arg)>0) ? (arg): -(arg)), причем параметр макроопределения A заменяется на arg. Пpимер: #define nmem(P,N) (P)->p_mem[N].u_long Символ продолжает макроопределение на вторую строку. Это макроопределение уменьшает сложность выражения, описывающего массив объединений внутри структуры. Макроопределения препроцессора языка Си имеют две формы - простую и параметризованную, #define идентификатор строка_замены #define идентификатор(x1,x2,_,xn) строка_замены где строка_замены может содержать идентификаторы, ключевые слова, разделители, такие как круглая или прямоугольная скобка, или строки знаков, не содержащие каких- либо разделителей. Замечание. Командная строка #include может встречаться в любом месте программы, но обычно все включения размещаются в начале исходного текста: #include <имя_файла> Пример: #include <math.h> Препроцессор заменяет эту строку содержимым файла math.h. Угловые скобки обозначают, что файл math.h будет взят из некоторого стандартного каталога, обычно это /usr/include. Текущий каталог не просматривается: #include "имя_файла" Пример: #include "ABC" Препроцессор заменяет эту строку содержимым файла ABC. Так как имя файла заключено в кавычки, то поиск производится в текущем каталоге, в котором содержится основной файл исходного текста. Если в текущем каталоге данного файла нет, то поиск производится в каталогах, определенных именем пути в опции -i препроцессора. Если и там файла нет, то просматривается стандартный каталог.
  • 17. 17 Командные строки препроцессора используются для условной компиляции различных частей исходного текста в зависимости от внешних условий. Условной компиляцией называется выборочная компиляция только тех частей программы, которые удовлетворяют определенным условиям. Например, можно скомпилировать только те части программы, которые необходимы для конкретной версии системы. Условная компиляция обладает следующими достоинствами: Обеспечивается средство параметризации во время компиляции. Например, такая возможность может быть использована для генерации программ с различной структурой. Обеспечивается эффективное использование оперативной памяти, поскольку во время выполнения нет необходимости держать в памяти неиспользуемые коды программы. Обеспечивается возможность принятия решений во время компиляции, а не во время выполнения. Часто это оказывается более эффективным подходом. Для условной компиляции используется инструкция препроцессора if. Она имеет две формы - с частью else и без нее: #if - заголовок текстовые строки для случая "истина" #endif и #if - заголовок текстовые строки для случая "истина" #else текстовые строки для случая "ложь" #endif где if - заголовок является управляющей строкой препроцессора, а текстовые строки могут содержать произвольный текст. Управляющая строка препроцессора if-заголовка содержит условие, на основе анализа которого производится выбор соответствующих текстовых строк: #if константное_выражение Пример: #ifdef ABC Истина, если идентификатор ABC определен ранее командой #define. #ifndef идентификатор Пример: #ifndef ABC Истина, если идентификатор ABC не определен в настоящий момент. #else ... #endif Если предшествующие проверки #if, #ifdef или #ifndef дают значение Истина, то строки от #else до #endif игнорируются при компиляции. Если эти проверки дают значение Ложь, то строки от проверки до #else, а при отсутствии #else - до #endif, игнорируются. Команда #endif обозначает конец условной компиляции. Пример: #ifdef DEBUG fprintf (stderr, "location. X=%dn",x); #endif При помощи команд препроцессора можно изменить номер текущей строки или имя компилируемого файла:
  • 18. 18 #line целая_константа "имя_файла" Пример: #line 20 "ABC" Препроцессор изменяет номер текущей строки и имя компилируемого файла. Имя файла может быть опущено. Замечание. Хотя препроцессоры и расширяют возможности языков программирования, их использование не лишено недостатков: использование препроцессоров требует дополнительного просмотра текста программы и, как следствие, добавочного времени.
  • 19. 19 3. Лекция: Операции. -Основные операции. -Дополнительные операции. -Перечень операций языка Си. Основные операции Рассмотрим способы обработки данных - для этого язык Си имеет широкий набор возможностей. Основные арифметические операции: сложения, вычитания, умножения, деления. Операции в языке Си применяются для представления арифметических действий. Например, выполнение операции + приводит к сложению двух величин, стоящих слева и справа от этого знака. Рассмотрим операции =, +, -, *, /. В языке Си нет операции возведения в степень. Операция присваивания: = В языке Си знак равенства не означает "равно". Он означает операцию присваивания некоторого значения. С помощью оператора yar=2004; переменной c именем yar присваивается значение 2004, т.е. элемент слева от знака = - это имя переменной, а элемент справа - ее значение. Мы называем символ = операцией присваивания. В этой операции действие выполняется справа налево. Возможно, различие между именем переменной и ее значением покажется незначительным? В таком случае давайте рассмотрим следующий оператор: i=i+1; C математической точки зрения это бессмыслица. Если вы прибавляете единицу к конечному числу, результат не может быть равен исходному числу. Но как оператор присваивания, данная строка имеет вполне определенный смысл, который можно выразить, например, такой фразой. Взять значение переменной с именем i, к нему прибавить 1, а затем присвоить новое значение переменной с именем i. Оператор вида 2004=yar; на языке Си не имеет смысла, поскольку 2004 - число. Мы не можем присвоить константе какое-то значение; ее значением является она сама. Поэтому, помните, что элемент, стоящий слева от знака =, всегда должен быть именем переменной. Операнд - это то, над чем выполняются операции. Например, можно описать процесс "поедания" картошки как применения операции "поедание" к операнду "картошка". Операция присваивания в языке Си представляется более интересной, чем в большинстве других языков. Рассмотрим простую программу: /* таблица результатов по шахматам */ main( ) { int l, m, n; n=m=l=165; printf("l m nn"); printf("Счет первой партии %4d %8d %8dn", l, m, n); } Присваивания выполняются справа налево: сначала переменная l получает значение 165, затем переменная m и наконец n. В языке Си имеется несколько других операций присваивания, которые отличаются от описанной операции. Их мы рассмотрим попозже. Представим еще один пример простой программы: /* использование операции присваивания */ main( )
  • 20. 20 { /* переменные number, ouzo, cost инициализируются конкретными значениями*/ int number=5; float ouzo=13.5; int cost=31000; printf("number ouzo costn"); printf("number=%d ouzo=%f cost=%dn", number, ouzo, cost); } Операция сложения: + Выполнение операции + приводит к сложению двух величин, стоящих слева и справа от этого знака. Например, в результате работы оператора printf("%d", 100 + 65); на печать будет выведено число 165, а не выражение 100+65. Операнды могут быть как переменными, так и константами. Операция + называется "бинарной", или "диадической". Эти названия отражают тот факт, что она имеет дело с двумя операндами. Пример: i=j+2; Переменной i присваивается значение переменной j плюс 2. Операция вычитания: - Выполнение операции вычитания приводит к вычитанию числа, расположенного справа от знака -, из числа, стоящего слева от этого знака. Оператор n = 163.00 - 100.00; присваивает переменной n значение 63.00. Операция изменения знака: - Знак минус используется для указания или изменения алгебраического знака некоторой величины. Например, в результате выполнения последовательности операторов teg = -15; get = -teg; переменной get будет присвоено значение 15. Когда знак используется подобным образом, данная операция называется "унарной". Такое название указывает на то, что она имеет дело только с одним операндом. Пример: x = -x; Операция изменяет алгебраический знак x. Операция умножения: * Операция умножения обозначается знаком *. При выполнении оператора z = 3 * x значение переменной x умножается на 3, и результат присваивается переменной z. Операция деления: / В языке Си символ / указывает на операцию деления. Величина, стоящая слева от этого знака, делится на величину, расположенную справа от этого знака. Например, в результате выполнения оператора l = 126.0 / 2.0; переменной l будет присвоено значение 63.0. Над данными целого типа операция деления производится не так, как над данными с плавающей точкой: в первом случае
  • 21. 21 результат будет целым числом, а во втором - числом с плавающей точкой. В языке Си принято правило, согласно которому дробная часть у результата деления целых чисел отбрасывается. Это действие называется "усечением". Рассмотрим пример, как выполняется усечение и чем деление целых чисел отличается от деления чисел с плавающей точкой: main( ) { printf("деление целых: 5/4 это %d n", 5/4); printf("деление целых: 6/3 это %d n", 6/3); printf("деление целых: 7/4 это %d n", 7/4); printf("деление чисел с плавающей точкой: 7./4. это %2.2f n", 7./4.); printf("смешанное деление: 7./4 это %2.2f n", 7./4); } Последний пример на использование смешанных типов, т.е. деление вещественного числа на целое. Язык Си менее строго подходит к подобным вопросам, и позволяет выполнять такие операции. ! Смешения типов следует избегать! Результат выполнения указанной программы: деление целых: 5/4 это 1 деление целых: 6/3 это 2 деление целых: 7/4 это 1 деление чисел с плавающей точкой: 7./4. это 1.75 смешанное деление: 7./4 это 1.75 Результат деления целых чисел округляется не до ближайшего целого, а всегда до меньшего целого числа. Когда мы смешиваем целые числа и числа с плавающей точкой, результат будет таким же, как если бы оба операнда были числами с плавающей точкой. В этом случае перед делением целое преобразуется в число с плавающей точкой. Для того чтобы понять, что происходит в тех случаях, когда в одном операторе используется несколько операций, рассмотрим порядок выполнения операций. Совершенно очевидно, что изменение порядка выполнения действий может приводить к различным результатам. В языке Си каждой операции назначается уровень старшинства. Умножение и деление имеют более высокий уровень, чем сложение и вычитание, поэтому они выполняются первыми. Если же две операции имеют один и тот же уровень старшинства, они выполняются в том порядке, в котором присутствуют в операторе. Для большинства операций обычный порядок - слева направо. Операция = является исключением из этого правила. Многие программисты предпочитают представлять порядок вычислений с помощью дерева выражений. Например, выражение (a+b)*c будет выглядеть так: * / + c / a b Мы можем составить таблицу правил описанных нами операций. В дальнейшем мы приведем таблицу, где содержатся правила, относящиеся ко всем операциям языка Си. Таблица 1.1. Операции в порядке уменьшения уровня старшинства Операции Порядок вычисления ( ) слева направо
  • 22. 22 - (унарный) слева направо * / слева направо + - (вычитание) слева направо = справа налево Дополнительные операции В языке Си имеется около сорока операций. Те операции, которые мы рассмотрели, являются наиболее общеупотребительными. Рассмотрим еще три операции, наиболее используемые программистами. Операция деления по модулю: % Эта операция используется в целочисленной арифметике. Ее результатом является остаток от деления целого числа, стоящего слева от знака операции, на число, расположенное справа от нее. Например, 63%5, читается как 63 по модулю 5, имеет значение 3, т.к. 12*5+3. В результате выполнения оператора minutes=time%60; переменной minutes будет присвоено значение остатка от деления time на 60. Операция увеличения: ++ Операция увеличения осуществляет следующее простое действие: она увеличивает значение своего операнда на единицу. Существуют две возможности использования данной операции: первая, когда символы ++ находятся слева от переменной (операнда), - "префиксная" форма, и вторая, когда символы ++ стоят справа от переменной, - "постфиксная" форма. Эти две формы указанной операции различаются между собой только тем, в какой момент осуществляется увеличение операнда. Префиксная форма изменяет значение операнда перед тем, как операнд используется. Постфиксная форма изменяет значение после того как операнд использовался. В примере, j=i++; переменной j сначала присваивается значение i, затем значение переменной i увеличивается на 1. Операция уменьшения: -- Каждой операции увеличения соответствует некоторая операция уменьшения, при этом вместо символов ++ мы используем --. Когда символы -- находятся слева от операнда - "префиксная" форма операции уменьшения. Если символы -- стоят справа от операнда - это "постфиксная" форма операции уменьшения. В соответствии с принятым в языке Си порядком вычислений операции увеличения и уменьшения имеют очень высокий уровень старшинства. Только круглые скобки обладают более высоким приоритетом. Поэтому выражение a/b++ означает (a)/(b++), а не (a/b)++. ! Не применяйте операции увеличения или уменьшения к переменной, присутствующей в более чем одном аргументе функции. Не применяйте операции увеличения или уменьшения к переменной, которая входит в выражение более одного раза. Перечень операций языка Си
  • 23. 23 Рассмотрим множество операций языка Си. Описанные операции входят в это множество. Язык Си отличается их большим разнообразием. В этом разделе будет обсуждаться их семантика. Каждая операция характеризуется уровнем приоритета и порядком, в котором эти операции выполняются - слева направо или справа налево. Если все операции выражения имеют один и тот же уровень приоритета, то значение выражения вычисляется слева направо в соответствии с порядком выполнения операций. Все операции с одним и тем же уровнем приоритета имеют один и тот же порядок. Однако если в выражении имеются операции с различными уровнями приоритета, то сначала выполняются операции с наивысшим уровнем приоритета, затем - следующего за ним приоритета и так далее в порядке убывания приоритета. Операции одного уровня приоритета выполняются в последовательности, указанной их порядком. Операции, уровень приоритета которых равен 1 Операции вызова функции, индексирования и выбора. В качестве операций языка Си рассматриваются также скобки в вызове функции, квадратные скобки для индексирования массивов, точка и стрелка вправо для выбора компонентов структуры или объединения. Уровень этих операторов равен 1, все операции выполняются слева направо. Операция вызова функции: ( ) Пример 1: fe(e1, e2,...,en); Вызов функции fe с аргументами e1, e2, ..., en. Значением этого выражения является значение, которое возвращает функция. Пример 2: x = sqrt (y); Операция индексирования массива: [] Синтаксис: array [2] Значением выражения является третий элемент массива. Присвоение значения 26 одиннадцатому элементу массива записывается таким образом: array[10]=26; Первый элемент массива описывается выражением array[0] (более подробно о массивах описано в лекции 12). Операция выбора компонентов структуры или объединения: . Синтаксис: struct.element Значением этого выражения является элемент element структуры struct или объединения (см. лекцию 14). Оператор: struct.element=1963; присваивает значение 1963 этому элементу. Операция выбора компонентов структуры с указателем: -> Синтаксис: my_birthday->day, my_birthday - указатель на структуру. Оператор: my_birthday->day=26; присваивает значение 26 структурной переменной day, на которую указывает my_birthday.
  • 24. 24 Операции, уровень приоритета которых равен 2 Унарные операции. Для унарных операций требуется только один операнд; эти операции либо префиксные, либо префиксные и постфиксные. Операция sizeof имеет два варианта: префиксная операция и унарная операция. Операция косвенной ссылки: * Это указатель на любой тип T, кроме void. Тип результата T. Использование: *pe Значением выражения является переменная, адресуемая указателем pe. Пример 1: *ptr=c; Пример 2: *fpe; Значением выражения является функция, адресуемая указателем fpe. Пример 3: fpe=*funcname; (*fpe)(arg1, arg2); Операция получения адреса: & У этой операции тип операнда есть переменная любого типа, кроме void. Тип результата - указатель на Т. Использование: &v Значением выражения является адрес переменной v. Пример: myptr=&n; Операция отрицания: - Тип операнда - арифметический. Тип результата: unsigned, long, double, int. Операция логического отрицания: ! Тип операнда - арифметический или указатель. Тип результата - int. Если операнд равен 0, то результат равен 1 и наоборот. Пример: if(!good) printf("not good"); Операция дополнения до 1: ~ Тип операнда - интегральный. Тип результата: int, long, unsigned. Пример: opposite=~mask; Дополнение до единицы значения mask. Результат присваивается переменной opposite. Операция увеличения: ++ Тип операнда - арифметический или указатель. Тип результата: int, unsigned, long, double, указатель. Значение операнда увеличивается, и становится новым значением операнда. Значение указателя увеличивается на величину указываемого объекта, значения других операндов увеличиваются на единицу. Операция увеличения, постфиксная: ++
  • 25. 25 Тип операнда - арифметический или указатель. Тип результата: int, unsigned, long, double, указатель. Значение операнда увеличивается, но возвращается старое значение операнда. Значение указателя увеличивается на величину указываемого объекта, другие операнды увеличиваются на единицу. Использование: iv++ Увеличение iv на 1. Значением этого выражения является значение iv до увеличения. Пример: j=i++; Использование: pv++; Увеличение указателя pv на 1, так что он будет указывать на следующий объект того же типа. Значением этого выражения является значение pv до увеличения. Пример: *ptr++=0; Присвоить значение 0 переменной, на которую указывает ptr, затем увеличить значение указателя ptr так, чтобы он указывал на следующую переменную того же типа. Операция уменьшения: -- Тип операнда - те же, что и для ++. Тип результата - те же, что и для ++. Использование: --iv Уменьшение iv на 1. Значением этого выражения является значение iv после уменьшения. Пример: i=--j; Операция уменьшения (постфиксная): -- Тип операнда - те же, что и для ++ (постфиксная). Использование: iv-- Уменьшение iv на 1. Значением этого выражения является значение iv до уменьшения. Пример: j=i--; Операция определения требуемой памяти в байтах: sizeof Тип операнда - значение любого типа или имени типа. Тип результата - unsigned. Используется как sizeof (выражение) или sizeof (имя типа). Пример: n=sizeof(arname)/sizeof(int); Число элементов в массиве целых чисел, определяемое как число байт в массиве, поделенное на число байт, занимаемых одним элементом массива. Операции, уровень приоритета которых равен 3 Мультипликативные операции. Порядок выполнения мультипликативных операций - слева направо. Операция умножения: * Тип операндов - арифметический. Тип результатов: int, unsigned, long, double. Использование: ae1*ae2 Произведение значений ae1*ae2.