Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Понятие указателя






Лабораторная работа №9

Тема:: Указатели в языке программирования С.

Цель работы: изучить указатель как средство доступа к данным. Научиться определять адреса переменных основных типов. Изучить допустимые операции с указателями. Научиться использовать указатели в элементарных задачах программирования.

Теоретическая часть

Понятие указателя

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

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

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

По краткому определению, указатель – это переменная, содержащая адрес другой переменной. Так как указатель содержит адрес переменной (объекта), это дает возможность " косвенного" доступа к этой переменной (объекту) через указатель.

int x=2, y=4; //объявлены переменная целого типа х,

int *ptr1, *ptr2; //указатели на объекты целого типа ptr1, ptr2;

Для понимания работы и назначения указателей рассмотрим упрощенную схему организации памяти компьютера. Память представляет собой массив последовательно пронумерованных или адресованных ячеек, с которыми можно работать по отдельности или связанными кусками. Известно, что различным типам данных отводится определенное количество байтов памяти. Поэтому указатель – это группа ячеек, в которых может храниться адрес. Например, если переменная x имеет тип int, а ptr1 (от латинского pointer – указатель) есть указатель на переменную x, то взятие адреса переменной x осуществляется с помощью унарного (одноместного) оператора &, т.е.

ptr1 = & x; //указатель ptr1 содержит адрес расположения переменной х

//взяли адрес переменной х

ptr2 = & y; //указатель ptr1 содержит адрес расположения переменной х

//взяли адрес переменной y

Приведенная инструкция означает, что переменной ptr1 присваивается адрес ячейки x, а ptr2 адрес ячейки y. Принято считать, что ptr1 указывает на x, а ptr2 на y. Оператор & применяется только к объектам, расположенным в памяти: к переменным, элементам массива. ременная. Унарный оператор & называется еще оператором адресации.

Имена указателям даются в соответствии с правилами, принятыми в языке программирования С для обычных переменных.

Другая унарная операция * называется операцией ссылки по указателю (indirection), или разыменования (dereferencing). Если применить ее к указателю, то получим объект, на который он указывает. Рассмотрим пример. Пусть х и у – целые переменные, а *ptr1 и *ptr2 – указатели на целые переменные. Поставим задачу присвоения переменной у значения переменной х с помощью указателя. Фрагмент С -кода будет следующий:

int x = 2, y = 4;

int *ptr1, *ptr2; // объявили указатели на целые переменные

ptr1 = & x; // взяли адрес переменной х = 2

ptr2 = & y; // взяли адрес переменной y = 4

y = *ptr1; // переменная у стала равной 2

*ptr1 = 0; // переменная х стала равной 0

ptr2=ptr1; // указатель ptr2 содержит адрес переменной х

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

Унарный оператор * есть оператор косвенного доступа. Примененный к указателю он выдает объект, на который данный указатель указывает.

Одноместные (унарные) операции * и & имеют более высокий приоритет для своих операндов, чем арифметические операции.

Для указателей одного типа можно, например, выполнять присваивание без разыменования. Это вытекает из того, что указатели сами по себе являются переменными. Пусть определен еще один указатель типа int, например, ptr2.

Тогда возможно произвести присвоение:

int *ptr, ptr2;

ptr2 = ptr;

После присвоения указатель ptr2 будет указывать на ту же переменную, что и указатель ptr.

В языке С допустимы следующие (основные) операции над указателями: присваивание; получение значения того объекта, на который ссылается указатель (синонимы: косвенная адресация, разыменование, раскрытие ссылки); получение адреса самого указателя; унарные операции изменения значения указателя; аддитивные операции и операции сравнений (отношений).

С помощью унарных операций " ++" и " ––" числовые (арифметические) значения переменных типа указатель меняются по-разному в зависимости от типа данных, с которыми связаны эти переменные. Если указатель связан с типом char, то при выполнении операций " ++" и " ––" его числовое значение изменяется на 1 (единицу). Если указатель связан с типом int, то операции " ++" и " ––" изменяют числовые значения указателей на 2. Указатель, связанный с типами float или long, унарными операциями " ++" и " ––" изменяется на 4. Таким образом, при изменении указателя на единицу указатель " переходит к началу" следующего (или пр едыдущего) поля той длины, которая определяется типом.

Итак, указатель содержит адрес объекта, это дает возможность " косвенного" доступа к этому объекту через указатель. Предположим, что х - переменная, например, типа int, а рх - указатель, созданный неким еще не указанным способом. Унарная операция & выдает адрес объекта, так что оператор

рх = & х;

присваивает адрес х переменной рх; говорят, что рх " указывает" на х. Операция & применима только к переменным и элементам массива, конструкции вида & (х-1) и & 3 являются незаконными. Нельзя также получить адрес регистровой переменной.

Унарная операция * рассматривает свой операнд как адрес конечной цели и обращается по этому адресу, чтобы извлечь содержимое. Следовательно, если y тоже имеет тип int, то

y = *рх;

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

рх = & х; y = *рх;

присваивает y то же самое значение, что и оператор

y = x;

переменные, участвующие во всем этом необходимо описать:

int x, y; int *px;

с описанием для x и y мы уже неоднократно встречались. описание указателя

int *px;

является новым и должно рассматриваться как мнемоническое; оно говорит, что комбинация *px имеет тип int. Это означает, что если px появляется в контексте *px, то это эквивалентно переменной типа int. Фактически синтаксис описания переменной имитирует синтаксис выражений, в которых эта переменная может появляться. Это замечание полезно во всех случаях, связанных со сложными описаниями. Например,

double atof(), *dp;

говорит, что atof() и *dp имеют в выражениях значения типа double.

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

Указатели могут входить в выражения. Например, если px указывает на целое x, то *px может появляться в любом контексте, где может встретиться x. Так оператор

y = *px + 1

присваивает y значение, на 1 большее значения x;

printf(" %d\n", *px)

печатает текущее значение x;

d = sqrt((double) *px)

получает в d квадратный корень из x, причем до передачи функции sqrt значение x преобразуется к типу double.

В выражениях вида

y = *px + 1

унарные операции * и & связаны со своим операндом более крепко, чем арифметические операции, так что такое выражение берет то значение, на которое указывает px, прибавляет 1 и присваивает результат переменной y.

Ссылки на указатели могут появляться и в левой части присваиваний. Если px указывает на x, то

*px = 0

полагает x равным нулю, а

*px += 1

увеличивает его на единицу, как и выражение

(*px)++

Круглые скобки в последнем примере необходимы; если их опустить, то поскольку унарные операции, подобные * и ++, выполняются справа налево, это выражение увеличит px, а не ту переменную, на которую он указывает.

И наконец, так как указатели являются переменными, то с ними можно обращаться, как и с остальными переменными. Если py - другой указатель на переменную типа int, то

py = px

копирует содержимое px в py, в результате чего py указывает на то же, что и px.






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.