Меню
Разработки
Разработки  /  Информатика  /  Презентации  /  Прочее  /  Основы алгоритмизации и программирования. Указатели

Основы алгоритмизации и программирования. Указатели

Презентация использовалась на занятиях профессионального модуля в ОПК СТИ НИТУ МИСиС

21.12.2017

Содержимое разработки

Тема 3 Разработка сложных программных продуктов   Лекция 3.4. Указатели .

Тема 3

Разработка сложных программных продуктов

Лекция 3.4.

Указатели .

Литература Основная: Подбельский В.В., Фомин С.С. Программирование на языке Си: Учеб. пособие. – М.: Финансы и статистика, 2004. Дополнительная: С/ C ++ Структурное программирование. Практикум. Программирование на языке высокого уровня. Питер, 2004. Юркин А. Задачник по программированию. Гриф МО. Учебное пособие, Питер, 2002. Шмидт Г. Самоучитель Си++. СПб.: БХВ – Петербург, 2004.

Литература

Основная:

Подбельский В.В., Фомин С.С. Программирование на языке Си: Учеб. пособие. – М.: Финансы и статистика, 2004.

Дополнительная:

С/ C ++ Структурное программирование. Практикум. Программирование на языке высокого уровня. Питер, 2004.

Юркин А. Задачник по программированию. Гриф МО. Учебное пособие, Питер, 2002.

Шмидт Г. Самоучитель Си++. СПб.: БХВ – Петербург, 2004.

Вопросы: 1. Адреса и указатели. 2. Операции над указателями. 3. Применение указателей.

Вопросы:

1. Адреса и указатели.

2. Операции над указателями.

3. Применение указателей.

1. Адреса и указатели

1. Адреса и указатели

Указатель – это переменная, значением которой является адрес объекта конкретного типа.  Если в некоторый момент времени адрес объекта неизвестен или переменная – указатель еще не получила значения, то такой переменной придается значение специальной константы NULL , не равное никакому адресу («нулевой» адрес). Указатели, как и любые переменные программы, должны быть объявлены. В объявление указателя входит указание типа объекта, на который ссылается указатель, признак (символ * ) того, что переменная является указателем, имя указателя.

Указатель – это переменная, значением которой является адрес объекта конкретного типа.

Если в некоторый момент времени адрес объекта неизвестен или переменная – указатель еще не получила значения, то такой переменной придается значение специальной константы NULL , не равное никакому адресу («нулевой» адрес).

Указатели, как и любые переменные программы, должны быть объявлены. В объявление указателя входит указание типа объекта, на который ссылается указатель, признак (символ * ) того, что переменная является указателем, имя указателя.

Примеры объявления указателей: int * f ; /*указатель на объект целого типа*/ float * a ,* b ; /*указатели на объекты вещественного типа*/ 1.Обычный указатель (кроме указателя типа void ) может ссылаться на объекты только того типа, который указан при объявлении. 2. После объявления значение указателя не определено (соответствует NULL ) . Получение адресной информации осуществляется с помощью унарной операции & . Например, адрес переменной

Примеры объявления указателей:

int * f ; /*указатель на объект целого типа*/

float * a ,* b ; /*указатели на объекты вещественного типа*/

1.Обычный указатель (кроме указателя типа void ) может ссылаться на объекты только того типа, который указан при объявлении.

2. После объявления значение указателя не определено (соответствует NULL ) .

Получение адресной информации осуществляется с помощью унарной операции & . Например, адрес переменной " А " формируется на основе выражения

&А

Это выражение в ходе выполнения программы позволяет определить адрес участка памяти, выделенного переменной А .

2. Операции над указателями

2. Операции над указателями

Применительно к указателям в языке Си допустимы операции: 1. Присваивание; 2. Разыменование; 3. Унарные операции сложения и вычитания; 4. Аддитивные операции; 5. Операции сравнения; 6. Получение адреса самого указателя.

Применительно к указателям в языке Си допустимы операции:

1. Присваивание;

2. Разыменование;

3. Унарные операции сложения и вычитания;

4. Аддитивные операции;

5. Операции сравнения;

6. Получение адреса самого указателя.

Операция присваивания Предполагает, что справа от знака присваивания стоит: Другой указатель, который имеет конкретное значение; Константа NULL ; Адрес объекта того же типа, что и указатель слева.  Примеры записи операции присваивания: с= d ; Предполагается, что переменные с и d являются указателями одного типа. После этой операции оба указателя обеспечивают доступ к одному участку памяти. c = NULL ; c=&a; // Указателю присваивается значение адреса Если указателю одного типа требуется присвоить значение указателя другого типа, то применяют приведение типов: int * k ; float * z ; k =( int ) z ; // преобразование перед присваиванием

Операция присваивания

Предполагает, что справа от знака присваивания стоит:

  • Другой указатель, который имеет конкретное значение;
  • Константа NULL ;
  • Адрес объекта того же типа, что и указатель слева.

Примеры записи операции присваивания:

с= d ;

Предполагается, что переменные с и d являются указателями одного типа. После этой операции оба указателя обеспечивают доступ к одному участку памяти.

c = NULL ;

c=&a; // Указателю присваивается значение адреса

Если указателю одного типа требуется присвоить значение указателя другого типа, то применяют приведение типов:

int * k ;

float * z ;

k =( int ) z ; // преобразование перед присваиванием

Операция разыменования (обращения по адресу, раскрытия ссылки) Позволяет обратиться к соответствующему объекту (переменной). Эта операция является унарной. Операция разыменования обозначается символом звездочки . Выражение * f соответствует объекту, на который указывает указатель

Операция разыменования (обращения по адресу, раскрытия ссылки)

  • Позволяет обратиться к соответствующему объекту (переменной). Эта операция является унарной.
  • Операция разыменования обозначается символом звездочки . Выражение * f соответствует объекту, на который указывает указатель " f ".
  • Выражение * f имеет все "права" переменной, например оператор * f =0 означает занесение нуля в тот участок памяти, адрес которого хранится в переменной – указателе " f ".
  • Разыменовывание указателя, соответствующего NULL , недопустимо.

Две эквивалентные группы операторов int b ; float f , a ; f = a + b ; и int b; float f, a, *c; с=& f ; // указателю с присваивается адрес переменной f * c = a + b ; // значение суммы заносится в участок // памяти по адресу, равному значению указателя с

Две эквивалентные группы операторов

int b ;

float f , a ;

f = a + b ;

и

int b;

float f, a, *c;

с=& f ; // указателю с присваивается адрес переменной f

* c = a + b ; // значение суммы заносится в участок

// памяти по адресу, равному значению указателя с

Унарные операции  сложения ++ и вычитания – – Позволяют увеличить или уменьшить значение указателя на величину, равную длине участка памяти, занимаемого соответствующим типом данных. Тем самым обеспечивается переход к началу участка памяти для соседней переменной. В частности, переменные типа char занимают в памяти участок длиной в 1 байт, переменные типа int – два байта, переменные типа long int и float – 4 байта, переменные double – 8 байт, long double – 10 байт.

Унарные операции сложения ++ и вычитания – –

Позволяют увеличить или уменьшить значение указателя на величину, равную длине участка памяти, занимаемого соответствующим типом данных. Тем самым обеспечивается переход к началу участка памяти для соседней переменной.

В частности, переменные типа char занимают в памяти участок длиной в 1 байт, переменные типа int – два байта, переменные типа long int и float – 4 байта, переменные double – 8 байт, long double – 10 байт.

Аддитивные операции В полном объеме эти операции не разрешены. Переменные типа указатель нельзя суммировать , но к переменной типа указатель можно добавлять целую величину k . При этом указатель увеличивается на величину k * r , где r – длина участка в байтах, занимаемого соответствующей переменной. Так при добавлении к указателю переменной типа float величины, равной трем, указатель увеличится на значение 3*4 = 12 байт. Аналогично изменяется значение указателя при вычитании из его значения целой величины . Операция вычитания применима к указателям одного типа. Из значения одного указателя можно вычитать значение другого указателя. Результатом операции является целая величина со знаком. Значение результата формируется в

Аддитивные операции

В полном объеме эти операции не разрешены. Переменные типа указатель нельзя суммировать , но к переменной типа указатель можно добавлять целую величину k . При этом указатель увеличивается на величину k * r , где r – длина участка в байтах, занимаемого соответствующей переменной. Так при добавлении к указателю переменной типа float величины, равной трем, указатель увеличится на значение 3*4 = 12 байт.

Аналогично изменяется значение указателя при вычитании из его значения целой величины .

Операция вычитания применима к указателям одного типа. Из значения одного указателя можно вычитать значение другого указателя. Результатом операции является целая величина со знаком. Значение результата формируется в "масштабе" соответствующего типа данных. Например, при вычитании указателей двух соседних величин типа int результат будет равнее единице, а не двум, хотя переменные этого типа занимают два байта.

Операции сравнения  (, =, ==, != )  Применимы только при сопоставлении указателей одного типа или при сравнении указателя с константой NULL .

Операции сравнения (, =, ==, != )

Применимы только при сопоставлении указателей одного типа или при сравнении указателя с константой NULL .

Операция получения адреса Позволяет получить адрес указателя. Указатель является переменной, поэтому и к нему применима операция получения адреса. Например, следующий фрагмент программы позволит отобразить значение адреса указателя float * a ; printf (

Операция получения адреса

Позволяет получить адрес указателя. Указатель является переменной, поэтому и к нему применима операция получения адреса. Например, следующий фрагмент программы позволит отобразить значение адреса указателя

float * a ;

printf ("\ n адрес указателя % p ", & a );

Отображение указателей и адресов производится с использование спецификации р – представление шестнадцатеричных чисел.

Отображение результатов вычитания указателей осуществляется с использованием спецификации d для целых чисел.

3. Применение указателей

3. Применение указателей

Применение указателей при работе с массивами В языке Си при традиционном объявлении массива его имя становится указателем на начало области памяти, выделенной под массив, т.е. имя массива без индексов является указателем на первый элемент, т.е. элемент с нулевым индексом этого массива. В частности: float r[10], *pn1; pn1=r; pn 1=& r [0]; В этом фрагменте программы два последних оператора эквиваленты.

Применение указателей при работе с массивами

В языке Си при традиционном объявлении массива его имя становится указателем на начало области памяти, выделенной под массив, т.е. имя массива без индексов является указателем на первый элемент, т.е. элемент с нулевым индексом этого массива.

В частности:

float r[10], *pn1;

pn1=r;

pn 1=& r [0];

В этом фрагменте программы два последних оператора эквиваленты.

Элементы массива в памяти располагаются последовательно друг за другом, поэтому, изменяя указатель на величину, равную длине элемента массива, можно переходить к соседним элементам. Имя массива интерпретируется как указатель – константа, следовательно, к нему не применимы операции изменения значений, оно не может стоять слева от знака присваивания. Фрагмент программы для подсчета среднего значения элементов массива с применением указателей float r[10],s, *pn1; for (pn1=&r[0], s=0; pn1 s /=10;

Элементы массива в памяти располагаются последовательно друг за другом, поэтому, изменяя указатель на величину, равную длине элемента массива, можно переходить к соседним элементам.

Имя массива интерпретируется как указатель – константа, следовательно, к нему не применимы операции изменения значений, оно не может стоять слева от знака присваивания.

Фрагмент программы для подсчета среднего значения элементов массива с применением указателей

float r[10],s, *pn1;

for (pn1=&r[0], s=0; pn1

s /=10;

В приведенном примере тело цикла отсутствует (за оператором for стоит символ

В приведенном примере тело цикла отсутствует (за оператором for стоит символ ";"), все действия по подсчету суммы записаны в заголовке цикла.

Выражения:

pn 1= &r[0]

обеспечивает установку указателя на первый (т.е. нулевой) элемент массива;

s +=* pn 1

суммирование элементов массива;

pn 1++

изменение указателя для перехода к следующему элементу массива (фактическое приращение указателя происходит не на единицу, а на 4, так как каждый элемент в памяти занимает 4 байта).

Операция индексирования r[ i ] эквивалентна *( r + i ) , где r – имя массива, i – выражение целого типа. Для многомерных массивов правило остается такое же. Например, z 22[ n ] [ m ] [ k ] эквивалентно *( z 22[ n ] [ m ] + k ) и далее *(*(*( z 22+ n )+ m )+ k ) .

Применение указателей в параметрах функции Схема вызова функции с помощью передачи параметров по значению не позволяет непосредственно возвращать из функции несколько результатов. Существует косвенная возможность изменения значений переменных в вызывающей программе на основе применения указателей: 1. В качестве фактических параметров при обращении к функции задаются адреса объектов вызывающей программы; 2. В функции с помощью разыменования указателей обеспечивается доступ к соответствующему объекту вызывающей программы, в том числе, это позволяет изменять значение объекта программы.

Применение указателей в параметрах функции

Схема вызова функции с помощью передачи параметров по значению не позволяет непосредственно возвращать из функции несколько результатов.

Существует косвенная возможность изменения значений переменных в вызывающей программе на основе применения указателей:

1. В качестве фактических параметров при обращении к функции задаются адреса объектов вызывающей программы;

2. В функции с помощью разыменования указателей обеспечивается доступ к соответствующему объекту вызывающей программы, в том числе, это позволяет изменять значение объекта программы.

Рассмотрим программу с функцией, возвращающей: среднее значение  moj =( x 1 + x 2 + …+ x n )/ n ; оценку дисперсии:  disp =( x 1 2 + x 2 2 + … + x n 2 )/ n – moj 2 ; стандартизованное значение элементов массива  x i =( x i – moj )/ disp 0,5 .

Рассмотрим программу с функцией, возвращающей:

среднее значение

moj =( x 1 + x 2 + …+ x n )/ n ;

оценку дисперсии:

disp =( x 1 2 + x 2 2 + … + x n 2 )/ n – moj 2 ;

стандартизованное значение элементов массива

x i =( x i – moj )/ disp 0,5 .

#include  #include  #include   void mdis(double *a, int n, double *m, double *b) {  int j;  double *aa, sig1;  for (*m=0, *b=0,j=0; j  *m=*m/n;  *b=*b/n;  *b=*b-pow(*m,2.0);  sig1=sqrt(*b);  for (aa=a; aa  *aa=(*aa-*m)/sig1, aa++); }

#include

#include

#include

void mdis(double *a, int n, double *m, double *b)

{

int j;

double *aa, sig1;

for (*m=0, *b=0,j=0; j

*m=*m/n;

*b=*b/n;

*b=*b-pow(*m,2.0);

sig1=sqrt(*b);

for (aa=a; aa

*aa=(*aa-*m)/sig1, aa++);

}

void main()  {  int i, n; double b[10], moj, disp,r;  n=10;  for (i=0; i   {    r=rand()/(pow(2.0,15.0)-1);    b[i]=-log(r);    printf(

void main()

{

int i, n; double b[10], moj, disp,r;

n=10;

for (i=0; i

{

r=rand()/(pow(2.0,15.0)-1);

b[i]=-log(r);

printf("%7.3lf", b[i]);

}

mdis(&b[0], n, &moj, &disp);

printf("\n");

for (i=0; i

printf("\nmo= %10.5lf sko= %10.5lf\n", moj, disp);

}

Для возведения величины x в степень y используется стандартная функция pow ( x , y ) ,  здесь хотя бы одно число следует записать как вещественное. Для вычисления корня квадратного – функция sqrt ( x ) . Применение математических функций требует подключения библиотеки с заголовочным файлом math . h . Для получения случайного числа - функция rand() , которая требует подключения заголовочного файла stdlib.h . Расчет среднего значения, оценки дисперсии и стандартизованных значений элементов массива оформлен в виде пользовательской функции mdis . Эта функция описана до начала основной программы, поэтому нет необходимости объявлять ее прототип в основной программе. Пользовательская функция в качестве формальных параметров содержит: Указатель на массив величин типа double ; Размер массива int n ; Указатели на переменные double  *m, double *b .

Для возведения величины x в степень y используется стандартная функция pow ( x , y ) , здесь хотя бы одно число следует записать как вещественное.

Для вычисления корня квадратного – функция sqrt ( x ) .

Применение математических функций требует подключения библиотеки с заголовочным файлом math . h .

Для получения случайного числа - функция rand() , которая требует подключения заголовочного файла stdlib.h .

Расчет среднего значения, оценки дисперсии и стандартизованных значений элементов массива оформлен в виде пользовательской функции mdis . Эта функция описана до начала основной программы, поэтому нет необходимости объявлять ее прототип в основной программе.

Пользовательская функция в качестве формальных параметров содержит:

  • Указатель на массив величин типа double ;
  • Размер массива int n ;
  • Указатели на переменные double *m, double *b .
Разыменование указателей внутри функции обеспечивает занесение результатов в соответствующие области памяти, объявленные в основной программе для фактических параметров moj и disp . Для пересчета значений элементов массива в функции осуществляется установка указателя на первый элемент массива, переданного в качестве формального параметра. Перебор элементов массива производится с применением указателя, что обеспечивает изменение значений элементов массива, объявленного в основной программе. Функция возвращает

Разыменование указателей внутри функции обеспечивает занесение результатов в соответствующие области памяти, объявленные в основной программе для фактических параметров moj и disp .

Для пересчета значений элементов массива в функции осуществляется установка указателя на первый элемент массива, переданного в качестве формального параметра. Перебор элементов массива производится с применением указателя, что обеспечивает изменение значений элементов массива, объявленного в основной программе.

Функция возвращает "пустое" значение – тип функции void , поэтому обращение к функции записано в виде выражения – оператора. Оператор return не указан, компилятор добавит его самостоятельно.

Фактические параметры при обращении к функции:

- адрес первого элемента массива;

- количество элементов массива;

- адреса переменных для среднего значения &moj и оценки среднеквадратического отклонения &disp .

Применение указателей на функции Необходимость применения указателей на функции связана с передачей параметра – имени функции в другую функцию или с возвратом значения – имени функции. Подобно имени массива наиболее часто в качестве указателя на функцию применяется идентификатор функции. Этот идентификатор задается при определении или описании прототипа функции, т.е. имя и указатель на функцию являются синонимами, но в обычном контексте термин указатель не применяется, принято говорить об имени функции. В таком виде указатель на функцию является константой, поэтому изменять его нельзя.

Применение указателей на функции

Необходимость применения указателей на функции связана с передачей параметра – имени функции в другую функцию или с возвратом значения – имени функции.

Подобно имени массива наиболее часто в качестве указателя на функцию применяется идентификатор функции. Этот идентификатор задается при определении или описании прототипа функции, т.е. имя и указатель на функцию являются синонимами, но в обычном контексте термин указатель не применяется, принято говорить об имени функции. В таком виде указатель на функцию является константой, поэтому изменять его нельзя.

Для применения указателя на функцию вводят специальную переменную. Объявление переменной – указателя на функцию производится отдельно от определения и от прототипа функции с помощью конструкции вида: тип (* имя указателя )( спецификация параметров ); где тип – определяет тип возвращаемого функцией значения; имя указателя – выбранный программистом идентификатор; спецификация параметров – определяет состав и типы параметров функции. Пример объявления переменной – указателя на функцию float (* uk 1)( float , int ); Здесь указатель имеет имя uk 1 (обязательно записывается в круглых скобках), функция имеет два параметра (типа float и int ), возвращаемое функцией значение имеет тип float .

Для применения указателя на функцию вводят специальную переменную. Объявление переменной – указателя на функцию производится отдельно от определения и от прототипа функции с помощью конструкции вида:

тип (* имя указателя )( спецификация параметров );

где тип – определяет тип возвращаемого функцией значения;

имя указателя – выбранный программистом идентификатор;

спецификация параметров – определяет состав и типы параметров функции.

Пример объявления переменной – указателя на функцию

float (* uk 1)( float , int );

Здесь указатель имеет имя uk 1 (обязательно записывается в круглых скобках), функция имеет два параметра (типа float и int ), возвращаемое функцией значение имеет тип float .

В отличие от имени функции, указатель на функцию является переменной, следовательно, этой переменной можно присваивать значения адресов других функций (значения других указателей). Но при этом тип присваиваемого указателя обязательно должен совпадать с типом указателя, стоящего в левой части оператора присваивания. Варианты обращения к функции: Обычным образом:  имя_функции ( список параметров ) Обращением по указателю на функцию указатель_на_функцию ( список параметров ) Обращением по указателю с его разыменованием, при этом указатель обязательно записывается в круглых скобках (* указатель )( список параметров )

В отличие от имени функции, указатель на функцию является переменной, следовательно, этой переменной можно присваивать значения адресов других функций (значения других указателей). Но при этом тип присваиваемого указателя обязательно должен совпадать с типом указателя, стоящего в левой части оператора присваивания.

Варианты обращения к функции:

Обычным образом:

имя_функции ( список параметров )

Обращением по указателю на функцию

указатель_на_функцию ( список параметров )

Обращением по указателю с его разыменованием, при этом указатель обязательно записывается в круглых скобках

(* указатель )( список параметров )

Иллюстрация способов обращения к функции … void f1(float x) {  printf(

Иллюстрация способов обращения к функции

…

void f1(float x)

{

printf("\nf1=%6.2f",10*sin(x));

}

void f2(float x)

{

printf ("\nf2=7.4",2*cos(x));

}

void main()

{

void (*u1)(float);/ / *u1 указатель на функцию

 …  f 1( y ); // обычный вызов функции  u 1= f 1; // настройка указателя на функцию f 1  u 1( y ); // вызов функции f1 по указателю //вызов функции f1 с разыменованием указателя  (* u 1)( y );  u 1= f 2; // настройка указателя на функцию f 2  u 1( y ); // вызов функции f2 по указателю //вызов функции f2 с разыменованием указателя (* u 1)( y ); }

…

f 1( y ); // обычный вызов функции

u 1= f 1; // настройка указателя на функцию f 1

u 1( y ); // вызов функции f1 по указателю

//вызов функции f1 с разыменованием указателя

(* u 1)( y );

u 1= f 2; // настройка указателя на функцию f 2

u 1( y ); // вызов функции f2 по указателю

//вызов функции f2 с разыменованием указателя (* u 1)( y );

}

Задание к практическому занятию. Составить программу, состоящую из основной функции и функции пользователя. Основная функция обеспечивает: - формирование двумерного массива чисел из n -х строк и m столбцов, значения n  m  х ij  = -(1/3) ln ( r ). Числа r в диапазоне от 0 до 1 формируются с помощью датчика случайных чисел, реализуемого функцией int rand (void) из библиотеки stdlib.h , которая формирует случайные числа в диапазоне от 0 до 2 15 – 1; - вывод результатов формирования массива; - обращение к функции пользователя ; - отображение преобразованного массива и значения минимального элемента в массиве. Функция пользователя обеспечивает: - поиск минимального значения в массиве и передачу его значения в основную функцию; - преобразование элементов массива, путем вычитания из значений элементов минимальной величины.

Задание к практическому занятию.

Составить программу, состоящую из основной функции и функции пользователя. Основная функция обеспечивает:

- формирование двумерного массива чисел из n -х строк и m столбцов, значения n m х ij = -(1/3) ln ( r ). Числа r в диапазоне от 0 до 1 формируются с помощью датчика случайных чисел, реализуемого функцией int rand (void) из библиотеки stdlib.h , которая формирует случайные числа в диапазоне от 0 до 2 15 – 1;

- вывод результатов формирования массива;

- обращение к функции пользователя ;

- отображение преобразованного массива и значения минимального элемента в массиве.

Функция пользователя обеспечивает:

- поиск минимального значения в массиве и передачу его значения в основную функцию;

- преобразование элементов массива, путем вычитания из значений элементов минимальной величины.

-80%
Курсы дополнительного образования

Создание динамических веб-страниц с помощью PHP и MySQL

Продолжительность 72 часа
Документ: Cвидетельство о прохождении курса
4000 руб.
800 руб.
Подробнее
Сохранить у себя:
Основы алгоритмизации и программирования. Указатели (292 KB)

Комментарии 0

Чтобы добавить комментарий зарегистрируйтесь или на сайт