Сдам Сам

ПОЛЕЗНОЕ


КАТЕГОРИИ







Использование указателей для связи функций





 

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

void swap(int*,int*);

void main(void){

int x=5, y=10;

printf ("Прервичные значения х=%d, y=%d\n",x, y);

swap (&x, &y);

printf ("Новые значения х=%d, y=%d\n", x, y);

}

void swap (int*v, int*z){

int u;

u=*v;

*v=*z; //x=y

*z=u;

}

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

Вызов swap (x,y); swap (&x, &y);

Определение функции swap (int v, int z); swap (int*v, int*z);

Переменные х, y являются локальными в функции main, но мы таким образом можем на них воздействовать в другой функции.

 

Указатели на одномерные массивы

 

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

Если mas [10]- это массив, то имя массива mas это то же самое, что &mas[0] (masó&mas[0]) - это адрес 1-го элемента массива. Оба выражения являются константными выражениями и не меняются на протяжении работы программы. Их можно присваивать переменной типа указатель. Указатель на массив определяется так: тип*, например: int *pm; но чтобы указатель ссылался на массив, необходимо присвоить указателю адрес массива pm=mas;

int mas[10];

int *pm;

pm=mas;

 

Чтобы записать в память в нулевой элемент число 5, обращаемся к элементу массива через указатель: *pm=5; записать в третий элемент число 10: (pm+2)=10;

но можно и наоборот – считать содержимое элемента в какую-либо переменную, например: int y=*(pm+1); ó mas[1].

*pm+4 –к значению из нулевого элемента +4ж

*(pm+4) – обращение к 5-му элементу массива.



 

//пример программы

void main(void){

int dates [4], *pti, index;

float bills [4], *ptf;

pti=dates;

ptf=bills;

for (i=0; i<4; i++)

printf ("указатель +%d: %10u и %10u\n", i, pti+i; ptf+i);

}

Указатель +0: 56014 56026 - начало адреса массивов.

+1: 56016 56030

+2: 56018 56034

+3: 56020 56038

Единицей адресации является байт, но тип int использует два байта, а тип float – четыре. Что произойдет, если «прибавить единицу к указателю?» Компилятор языка СИ прибавит единицу памяти. Для массивов это означает, что мы перейдем к адресу следующего элемента массива, а не следующего байта. Вот почему, мы должны специально оговаривать тип объекта, на который ссылается указатель; одного адреса здесь не достаточно, так как машина должна знать, сколько байтов потребуется для запоминания объекта. (Это справедливо также для указателей на скалярные переменные; иными словами, при помощи операции *pt нельзя получить значение.)

Вывод: прибавляя 1 к указателю, переходим к следующему элементу массива, а не к следующему байту, т.е. смещаемся на длину типа элемента массива (int, float...).

рt pt+1 pt+2 pt+3

 
 

 


dates[0] dates[1] dates[2] dates[3]

dates+2<=>&dates[2]

*(dates+2) <=>dates[2]

*dates+2<=>*(dates)+2

 

//Суммирование элементов массива с использованием указателя.

for(i=0;i<10; i++)

sum+=*(ptm+i);

или

for(i=0;i<10; i++){

sum+=*ptm;

ptm++;

}

или

for(i=0;i<10; i++)

sum+=*ptm++;

 

Указатели на многомерные массивы

 

Если указать имя массива и только первый индекс многомерного массива, то это то же самое, что указать алрес первого элемента массива (1-й элемент 1-й строки). Например:

array[0]ó&array[0][0];

array[1]ó&array[1][0];

После определения указателя int *pm; необходимо присвоить адрес pm=array[0];

чтобы изменить этот адрес, необходимо нарастить указатель на 1 или необходимое число: pm+1; или pm+число;

(pm+5)ó&array[1][0]; указатель меняется последовательно.

(pm+5) – это обращение по адресу

*(pm+5) – это обращение к содержимому

*(pm+5)=2; – это присвоение 2 ячейке с адресом pm+5.

 
0 [0][0] [0][1] [0][2] [0][3] [0][4]
[1][0] [1][1] [1][2] [1][3] [1][4]
       
         

 

int mas[2][2], *pti;

pti=mas[0]; //pti=&mas[0][0]

pti+1<=>&mas[0][1];//так как элементы массива расположены в памяти последовательно и сначала

pti+2<=>&mas[1][0]; // меняется второй индекс.

mas[0]<=> &mas[0][0];

mas[1] <=>&mas[1][0]; //Это важное свойство, потому что можно

//работать с 2-м массивом как с одномерным.

 

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

 

1. Присвоить ему значение адреса

int*px, x=2; px=&x;

 

2. Можно присвоить константу - адрес ячейки с описанием состояния аппаратных средств - абсолютный адрес.

 

3. После присвоения адреса можно применять операцию взятия косвенного адреса.

px=&x; y=*px; //y==x; Приоритет выше чем y операции «присвоение»

*px=10; x=10;

 

4. *px+2 //к значению переменной, адрес которой в px, прибавить 2.

рх++; // рх+1 увеличение адреса на длину типа.

++рх;

 

4. сравнение указателей ==, !=, >=, <=, >, <

 

//Пример программы копирования двух массивов

void main(void) {

char ar1[100], ar2[100];

char *pa1, *pa2;

pa1=&ar1;

pa2=&ar2;

while(pa2<(ar2+sizeof(ar2)))

pa1++=pa2++;}

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

Арифметические операции с указателями ограничены сложением, вычитанием и сравнением. Арифметические операции с указателями объектов типа "указатель на тип type" автоматически учитывают размер этого типа, то есть число байт, необходимое для хранения в памяти объекта данного типа.

При выполнении арифметических операций с указателями предполагается, что указатель указывает на массив объектов. Таким образом, если указатель объявлен как указатель на type, то прибавление к нему целочисленного значения перемещает указатель на соответствующее количество объектов type. Если type имеет размер 10 байтов, то прибавление целого числа 5 к указателю этого типа перемещает указатель в памяти на 50 байт. Разность представляет собой число элементов массива, разделяющих два значения указателей. Например, если ptr1 указывает на третий элемент массива, а ptr2 на десятый, то результатом выполнения вычитания ptr2 - ptr1 будет 7.

Когда с "указателем на тип type" выполняется операция сложения или вычитания целого числа, то результат также будет "указателем на тип type". Если type не является массивом, то операнд указателя будет рассматриваться как указатель на первый элемент "массива типа type" длиной sizeof(type).

Конечно, такого элемента, как "указатель на следующий за последним элементом" не существут , однако указатель может принимать это значение. Если P указывает на последний элемент массива, то значение P+1 допустимо, но неопределено. Использование указателя на элемент вне массива ведет к непредсказуемым результатам работы программы. Контроль за допустимыми значениями указателей возлагается на программиста.









Не нашли то, что искали? Воспользуйтесь поиском гугл на сайте:


©2015- 2018 zdamsam.ru Размещенные материалы защищены законодательством РФ.