
Лекция-11.ppt
- Количество слайдов: 17
Тема Указатели и массивы (продолжение) Лекция 10. 11 г. 1
Константные указатели Свойство константности объекта задаётся описателем const и символизирует запрет на выполнение операций записи в память. Это свойство можно задать для разных объектов программы: - переменных, - параметров функций, - возвращаемых из функций значений. Контроль за корректным использованием свойства const выполняет компилятор, поэтому ошибки обнаруживаются на ранних стадиях создания программы, что повышает ее надежность. Лекция 10. 11 г. 2
Константные указатели С помощью описателя const можно сделать неизменяемым как указатель, так и область памяти, на которую он ссылается. … main() { int a = 5, b = 7; int *p 1 = &a; *p 1 = 3; // ok! p 1 = &b; // ok! const int *p 2 = &a; //констант. область памяти *p 2 = 9; // err! p 2 = &b; // ok! int *const p 3 = &a; //констант. указатель *p 3 = 9; // ok! p 3 = &b; // err! const int *const p 4 = &a; //и указ. , и обл. пам. конст. *p 4 = 6; // err! p 4 = &b; // err! … } Лекция 10. 11 г. 3
Аргументы командной строки В операционной среде, обеспечивающей поддержку С, имеется возможность передать аргументы (параметры) запускаемой программе с помощью командной строки. В момент вызова функции main она получает два аргумента. В первом, обычно называемом argc (от argument count – счетчик аргументов), содержится число, равное количеству аргументов, заданных в командной строке. Второй, argv (от argument vector – вектор аргументов), является указателем на массив символьных строк, содержащих сами аргументы, - по одному в строке. #include
Аргументы командной строки Следующая программа, которая названа factorial, позволяет вычислить факториалы нескольких чисел, которые задаются как параметры вызова данной программы. #include
Дополнительные сведения о функциях: rvalue и lvalue Если тип возвращаемого значения функции отличен от void, то в результате вызова функции получается, как правило, некоторое значение, которое может быть использовано как операнд в выражении. Например, для подсчета среднего значения массива может быть использован следующий фрагмент: double sum(double *x, int n); // прототип функции sum. . . sr = sum(m, 100)/100; В данном примере функция возвращает так называемое rvalue, иначе говоря, значение. Термин rvalue происходит от read value – значение для чтения, или от right value – правое значение – по его месту относительно операции присваивания. Лекция 10. 11 г. 6
Дополнительные сведения о функциях: rvalue и lvalue В некоторых случаях типом возвращаемого значения функции может быть тип, дающий lvalue, иначе говоря, адрес. Термин lvalue происходит от location value – значение местоположения, или от left value – левое значение – также по его месту относительно оператора присваивания. Следовательно, вызов такой функции может располагаться слева от оператора присваивания. Например: #include
Дополнительные сведения о функциях: rvalue и lvalue Внимание! Необходимо с осторожностью обращаться с lvalue, возвращаемыми из функций и не допускать, чтобы из функций возвращались адреса несуществующих объектов, например, локальных переменных, объявляемых внутри функции: #include
Указатели на функции В программировании для Windows широко применяется техника функций обратного вызова (callback functions). Функции обратного вызова – это указатели на функции, через которые могут быть вызваны функции. Пример указателя на функцию: #include
Указатели на функции В предыдущем примере был использован указатель на функцию pf как самостоятельная переменная. Синтаксис языка С допускает объявить указатель на функцию как тип данных, что позволяет использовать динамические переменные и массивы указателей. #include
Сложные объявления Язык С часто обвиняют за чрезмерно сложный синтаксис объявлений, особенно тех, которые содержат в себе указатели на функции. Например: int *f(); функция f, возвращающая указатель на int (*f)(); указатель на функцию f, возвращающую int Приоритет оператора * ниже, чем приоритет (), поэтому во втором случае скобки необходимы. Ещё пример: int *daytab[13]; массив из 13 указателей на int (*daytab)[13]; указатель на массив из 13 чисел типа int И ещё одно (очень запутанное!) объявление: int (*(*(*fun)())[])(); Его следует понимать так: «fun – это указатель на функцию, возвращающую указатель на массив указателей на функции, возвращающие int» . Рассмотрим общее правило (которое называется правило «право-лево» ), позволяющее разбирать любые «запутанные» объявления. Лекция 10. 11 г. 11
Сложные объявления (правило «право-лево» ) При описании этого правила необходимо помнить следующие 3 операции: () - функция, возвращающая. . . [] - массив из. . . * - указатель на. . . Первые две имеют наивысший приоритет, а третья – более низкий. Процесс разбора объявления итеративный: Шаг 1. Находим имя, с которого начинается разбор, и записываем начало предложения «Имя есть. . . » . Шаг 2. Начинаем движение вправо для поиска () или []. Если справа оказывается (), то в конструируемое предложение вместо многоточия подставляем: «функция, возвращающая. . . » и в итоге получаем: «Имя есть функция, возвращающая. . . » . Если справа [], то подставляем «массив из…» и получаем «Имя есть массив из. . . » . Таким образом мы идём вправо до тех пор, пока не дойдём до конца объявления или правой ) скобки. Шаг 3. После этого начинаем перемещаться влево. Если слева обнаруживается что-то отличное от упомянутых выше операций (то есть не (), [], *), то просто добавляем к уже имеющемуся предложению. Если же там что-то из этих трёх операций, то к предложению добавляем соответствующий текст. И так перемещаемся до начала объявления или левой ( скобки. Если обнаружена (, то переходим к шагу 2. Если дошли до начала объявления, разбор закончен. Лекция 10. 11 г. 12
Сложные объявления (правило «право-лево» ) Рассмотрим сложный пример: int (*(*(*fun)())[])(); ^^^ Hаходим имя и записываем: «fun есть. . . » . Шаг вправо, но там ), и потому идём влево int (*(*(*fun)())[])(); ^ и получаем «fun есть указатель на. . . » . Продолжаем двигаться влево, но тут (. Идём вправо int (*(*(*fun)())[])(); ^^ получаем «fun есть указатель на функцию, возвращающую. . . » . Шаг вправо, но там ), и потому идём влево. Получаем int (*(*(*fun)())[])(); ^ «fun есть указатель на функцию, возвращающую указатель на. . . » . Слева опять (, поэтому идём вправо. Получаем int (*(*(*fun)())[])(); ^^ «fun есть указатель на функцию, возвращающую указатель на массив. . . » . Лекция 10. 11 г. 13
Сложные объявления (правило «право-лево» ) И снова справа ), поэтому перемещаемся влево и получаем int (*(*(*fun)())[])(); ^ «fun есть указатель на функцию, возвращающую указатель на массив указателей на. . . » . Снова разворот вправо, т. к. обнаруживается ( , и получаем int (*(*(*fun)())[])(); ^^ «fun есть указатель на функцию, возвращающую указатель на массив указателей на функции, возвращающие. . . » . Обнаруживаем конец описания, переключаемся на движение влево и получаем окончательную расшифровку этого очень сложного и запутанного описания: int (*(*(*fun)())[])(); ^^^ «fun есть указатель на функцию, возвращающую указатель на массив указателей на функции, возвращающие int» . Лекция 10. 11 г. 14
Тема Структуры Лекция 10. 11 г. 15
Основные понятия Структура – это набор нескольких именованных переменных, объединённых в единое целое под общим именем. Входящие в структуру переменные называются элементами, полями или членами структуры. Члены структуры имеют произвольные типы и уникальные в пределах структуры имена. Доступ к членам структуры производится по составному имени, включающему имя структуры и имя члена структуры. Пример: struct {int x; int y; } pt 1, pt 2; pt 1. x = 3; pt 1. y = 6; pt 2 = pt 1; Синтаксис языка С позволяет отделить описание «внутреннего устройства» структуры от определения конкретных переменных, имеющих это внутреннее устройство: struct point {int x; int y; }; struct point pt 1, pt 2; Такой подход позволяет рассматривать первое объявление как новый тип данных, а второе – как определение переменных этого типа. Замечание. Допускается совмещать объявление типа и объявление переменных: struct point {int x; int y; } pt 1, pt 2; Лекция 10. 11 г. 16
Основные понятия Элементы структуры могут иметь произвольный тип, в том числе, они сами могут быть структурами. #include