Л. № 4, 2012 -2013 г. , Ионов Ю. Г. В данной презентации приводятся дополнителные сведения по 2 -м темам: 1 - массивы и указатели (необходимо разобраться в том, какой смысл следует вкладывать в арифметические операции над указателями и в каком отношении между собой находятся массивы и указатели); 2 - функции (здесь на примерах с помощью комментариев рассмотрен ОБМЕН ДАННЫМИ между функциями программы. При этом используются разные механизмы обмена. Необходимо понять, какая между ними разница и в каких случаях следует предпочесть тот или иной механизм). Примечание: мы начинаем готовиться ко 2 -й контрольной работе !
I. О массивах и указателях
/*Вначале проиллюстрируем различие в способе обращения к переменным*/ # include < iostream. h > # include < conio. h > void main ( ) { clrscr(); int *x, y; //объявление указателя и переменной *x=200; y=300; cout <
Адресная арифметика Пусть дано следующее описание int a[100], определяющее массив из ста элементов типа int. Поскольку a==&a[0] , то адрес элемента a[i] равен a + sizeof(int)*i, где функция sizeof(int)- возвращает размер типа в байтах. Если учесть соглашение о том, что выражение вида a+i как раз и определяет адрес i-ого элемента, т. е. &a[i] == a+i, тогда обозначение a[i] становится эквивалентным адресному выражению *(a+i) в том смысле, что оба они определяют одно и то же числовое значение, а именно: a[i] == *(a+i). Пусть теперь имеются описания int a[10]; int *pa; выполняя операцию присваивания pa = a или pa = &a[0] мы устанавливаем указатель pa на нулевой элемент массива a и поэтому справедливы равенства &a[i] == pa+i и a[i] == *(pa+i), т. е. операцию pa+i, увеличивающую значение указателя, можно интерпретировать как смещение вправо на i элементов базового типа. Все это означает, что всякое обращение к i-ому элементу массива или его адресу допустимо представлять как в индексной форме, так и на языке указателей.
Пусть array – имя массива, а ptr - указатель Первый способ доступа: // указатели array[2]=3 или array[i+1]=7 // с использованием обычных // индексных выражений array[2] и 2[array] //эквивалентные выражения или ptr[2] или 2[ptr] //доступ к 3 -му элементу Второй способ: Ptr : Ptr+1 : Ptr+2 : • • array: array[0] Ptr+3 : • • можно: *( Ptr+i ) т. е. *( Ptr +2 )=3
1. Использование указателей для объявления сложной структуры такой, как массив, снижает затраты на указатели. 2. Память, связанную с указателем, можно вернуть в свободную область памяти. Этого нельзя делать с обычными величинами, в том числе, с массивом, объявленным например так: int x[75]. 3. С объектом, объявленным как указатель, проще оперировать в случае, если есть необходимость обработки объекта как целого.
II. Функции и обмен данными между ними
Пример передачи данных по значению #include
Пример передачи данных по указателю // расчет максим. эл-та массива с его передачей как указателя #include
Пример передачи данных по ссылке //переменная a главной функции и локальная переменная y //указывают на одну и ту же область памяти, поэтому увел. на 1 //значения y приводит к увеличению a в главной функции #include
//Еще пример обмена данными между функциями по адресу (ссылке): #include
!Предупреждения: 1) функции, не имеющие возвращаемых значений, должны объявляться как тип void. Если функции не присвоен никакой тип, компилятор Си считает, что функция имеет тип int. Однако стандарт Си 99 рекомендует объявлять тип int явно; 2) до появления языка в стандарте ANSI Cи типы аргументов в скобках заголовка разрешалось опускать. Но в этом стандарте и в Си 99 рекомендуется объявлять типы аргументов явно. Рекомендация не касается функции main (см. примеры выше).
Рекомендация: Если прототипы функций в программе опускаются, то рекомендуется все их определения поместить прежде, чем функция используется в первый раз. Пример: … int min (int a, int b) {return a < b ? a : b; } … int main () { … printf (“минимум из %d и %d будет %d. n”, 3. 0, 5, min(3. 0, 5)); … }


