Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
shpory_si.docx
Скачиваний:
33
Добавлен:
25.09.2019
Размер:
205.61 Кб
Скачать

23. Указательные выражения. Адресная арифметика.

Указательные выражения

К указателям можно применить операцию присваивания. Указатели одного и того же типа могут использоваться в операции присваивания, как и любые другие переменные.

Пример:

{

int x = 10;

int *p, *g; // объявление указателя

p = &x; // установка указателя p на переменную x

g = p; // указатель g тоже указывает на x

printf("p = %d", p); // вывод на экран содержимого p (вывод адреса)

printf("\n g = %d", g); // вывод адреса

printf("\n x = %d", x, "*g = %d", *g); /* вывод на экран величины x и величины, находящейся по адресу указателя g */

}

В языке С допустимо прмсвоить указателю любой адрес памяти. Однако, если объявлен указатель на целое число (int *p;), а по адресу, которому присвоен данному указателю, находится переменная x типа float, то при компиляции программы будет выдано сообщение об ошибке в строке p = &x. Эту ошибку можно исправить, преобразовав указатель на int к типу указателя на float явным преобразованием типа:

p = (int*)&x;

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

Адресная арифметика

Над указателями можно выполнять унарные операции: инкремент и декремент. При выполнении операций ++ и -- значение указателя увеличивается или уменьшается на длину типа, на который ссылается используемый указатель.

Пример:

int *ptr, a[10];

ptr=&a[5];

ptr++; // равно адресу элемента a[6]

ptr--; // равно адресу элемента a[5]

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

Пример:

int *ptr1, *ptr2, a[10];

int i=2;

ptr1=a+(i+4); // равно адресу элемента a[6]

ptr2=ptr1-i; // равно адресу элемента a[4]

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

Пример:

int *ptr1, *ptr2, a[10];

int i;

ptr1=a+4;

ptr2=a+9;

i=ptr1-ptr2; // равно 5

i=ptr2-ptr1; // равно -5

Значения двух указателей на одинаковые типы можно сравнивать в операциях ==, !=, <, <=, >, >= при этом значения указателей рассматриваются просто как целые числа, а результат сравнения равен 0 (ложь) или 1 (истина).

Пример:

int *ptr1, *ptr2, a[10];

ptr1=a+5;

ptr2=a+7;

if (prt1>ptr2) a[3]=4;

В данном примере значение ptr1 меньше значения ptr2 и поэтому оператор a[3]=4 не будет выполнен.

24. Связь массивов и указателей

Принято, что имя массива – адрес памяти, начиная с которого расположен массив, т.е. адрес первого элемента массива.

Идентификатор массива является константным указателем на его нулевой элемент. Например, для массива имя – это тоже самое, что &b[0], а к i-тому элементу массива можно обратиться, используя выражение *(b+i).

Для того, чтобы получить значение 6 элемента массива а, можно записать a[5] или *(a+5). Можно описать указатель, присвоить ему адрес начала массива и работать с массивом через указатель.

Следующий фрагмент программы копирует все элементы массива a в массив b:

int a[100], b[100];

int *pa = a; // или int *p = &a[0]

int *pb = b;

for (int i=0; i<100; i++)

*pb++ = *pa++; // или pb[i] = pa[i]

Для доступа к элементу многомерного массива указываются все его индексы *(matr[i]+j) или

*(*(matr[i])+j). Это возможно, поскольку matr[i] является адресом начала строки массива.

Связь массивов и указателей

В языке Си имя массива трактуется как указатель-константа на массив. Пусть в программе объявлен массив:

int X[10];

В таком случае Х является указателем на нулевой элемент массива в памяти компьютера. В связи с этим является истинным отношение

X==&X[0]

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

Имя[индекс] тождественно *(имя+индекс)

Например, для описанного выше массива Х взаимозаменяемы следующие обозначения элементов:

X[5], или *(Х+5), или *(5+Х).

В языке Си операция [ играет роль знака операции сложения адреса массива с индексом элемента.

  1. Функции динамического распределения памяти.

calloc

Функция            Выделяет оперативную память.

Синтаксис          #include <stdlib.h

                   void * calloc(size_t nitems, size_t size);

Файл, содержащий   stdlib.h,alloc.

прототип

Описание calloc обеспечвает доступ к динамической области памяти. Динамическая область памяти доступна для динамического распределения блоков памяти переменной длины. Многие структуры   данных, например, деревья и списки, используют распределение динамической области памяти.

calloc выделяет блок памяти размером nitems x size.

Блок обнуляется. Если вы хотите выделить блок, размер которого превышает 64К то нужно использовать функцию farcalloc.

Возвращаемое calloc возвращает указатель на выделенный блок.

значение calloc возвращает NULL, если недостаочно памяти для выделения  нового  блока, или nitems или size равны 0.

Пример:

#include<stdio.h>

#include<alloc.h>

#include<string.h>

int main(void)

{

char *str = NULL;

/* выделить память для строки */

str = calloc(10,sizeof(char));

if(str)

{

/* скопировать в строку "Hello" */

strcopy(str,"Hello");

/* вывести строку */

printf("Строка : %s\n",str);

/* освободить память */

free(str);

}

else

printf("Недостаточно памяти\n");

}

  return(0);

}

malloc

Функция.Выделяет память.

Синтаксис          #include<stdlib.h>

                   #include<alloc.h>

                   void *malloc(size_t size);

Файл, содержащий   stdlib.h и alloc.h прототип

Описание

Функция обеспечивают выделение блока памяти, размером size байт. Она позволяет программе выделять память по необходимости и столько, сколько нужно.

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

Возвращаемое

Функция malloc возвращает указатель на блок выде значени ленной памяти. Если для размещения блока недостаточно памяти,  функция  malloc  возвращает   NULL.

Содержимое  блока   остается   неизменным.   Если аргумент size равен 0, то функция возвращает NULL.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]