Лекции.Орг


Поиск:




Категории:

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

 

 

 

 


Тема: Указатели. Динамические массивы




(4 часа)

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

· Массив элементов заданного типа;

· Функция, возвращающая значение заданного типа;

· Указатель на объект заданного типа.

Указатели

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

Указатель – это адрес памяти. Значение указателя сообщает о том, где размещен объект, но не говорит о самом объекте. Как и всякие переменные, указатели нужно определять и описывать. Символ операции ‘*’ используется для задания “указателя на” объект. Кроме разделителя ‘*’, в определения и описания указателя входят спецификации типов, задающих типы объектов, на которые ссылаются указатели.

Например: int *ptr;

Данное определение следует понимать как “ptr является указателем на целое”. Указатель на тип void совместим с любым указателем. Например, если задано

void *x;

int *y;

то допустимо следующее присваивание y=x;

В общем случае переменная типа указатель описывается так:

тип * переменная_указатель

Двумя наиболее важными операциями, связанными с указателями, является операция обращения по адресу * (иногда называется операцией снятия ссылки или разыменования) и операция определения адреса &.

Операция обращения по адресу * служит для присваивания или считывания значения переменной, размещенной по адресу переменная_указатель, при помощи лево-определенного выражения *переменная_указатель. Например,

*ptr=value;

что обозначает следующее: значение переменной value помещается в участок памяти, адрес которого определяет указатель ptr. Операндом операции разыменования всегда является указатель. Указатель может ссылаться на объекты того типа, который присутствует в определении указателя. Исключением являются указатели, в определении которых использован тип void – отсутствие значения. Такие указатели могут ссылаться на объекты любого типа, однако к ним нельзя применять операцию разыменования, т. е. операцию ‘*’.

Операция value=*ptr; обозначает следующее: переменной value присваивается значение, хранимое в ячейке памяти, адресуемой указателем ptr.

Операция определения адреса & возвращает адрес памяти своего операнда. Операндом должна быть переменная. Операция определения адреса выполняется следующим образом:

адрес =& переменная;

где адрес – это соответствующее выражение, куда помещается адрес, а переменная – имя переменной, определенной выше в программе.

В языке С размер возвращаемого адреса зависит от применяемой модели памяти.

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

Пример:

#include<stdio.h>

void main(){

int *x, *w;

int y, z;

*x=16;

y=-15;

w=&y;

printf(“\nРазмер x=%d”, sizeof(x));

printf(“\nЗначение указателя x=%u”, x);

printf(“\nЗначение по такому адресу=%d”, *x);

printf(“\nАдрес y=%u”, &y);

printf(“\nАдрес z=%u”, &z);

printf(“\nЗначение *w=%d”, *w);

}

Динамические массивы

В соответствии со стандартом языка массив представляет собой совокупность элементов, каждый из которых имеет одни и те же атрибуты (характеристики). Все элементы размещаются в смежных участках памяти подряд, начиная с адреса, соответствующего началу массива, т.е. значению & имя_массива [0].

При традиционном определении массива:

тип имя_массива [ количество_элементов ];

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

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

Формирование массивов с переменными размерами можно организовать с помощью указателей и средств для динамического выделения памяти. Начнем рассмотрение указанных средств с библиотечных функций, описанных в заголовочных файлах alloc.h и stdlib.h стандартной библиотеки (файл alloc.h не является стандартным). В таблице приведены сведения об этих библиотечных функциях. Функции malloc(), calloc() и realloc() динамически выделяют память в соответствии со значениями параметров и возвращают адрес начала выделенного участка памяти. Для универсальности тип возвращаемого значения каждой из этих функций есть void*. Этот указатель (указатель такого типа) можно преобразовать к указателю любого типа с помощью операции явного приведения типа (тип *). Функция free() решает обратную задачу – освобождает память, выделенную перед этим с помощью одной из трех функций calloc(), mailoc() или realloc(). Сведения об этом участке памяти передаются в функцию free() с помощью указателя – параметра типа void*. Преобразование указателя любого типа к типу void * выполняется автоматически, поэтому вместо формального параметра void * можно подставить в качестве фактического параметра указатель любого типа без операции явного приведения типов.

Таблица. Функции для выделения и освобождения памяти

Функция Прототип и краткое описание  
malloc void * malloc (unsigned s); Возвращает указатель на начало области (блока) динамической памяти длиной в s байт. При неудачном завершении возвращает значение NULL.    
calloc void * calloc (unsigned n, unsigned m); Возвращает указатель на начало области (блока) обнуленной динамической памяти, выделенной для размещения n элементов по m байт каждый. При неудачном завершении возвращает значение NULL.  
realloc void * realloc (void * bl, unsigned ns); Изменяет размер блока ранее выделенной динамической памяти до размера ns байт. bl – адрес начала изменяемого блока. Если bl равен NULL (память не выделялась), то функция выполняется как malloc.  
free void * free (void * bl); Освобождает ранее выделенный участок (блок) динамической памяти, адрес первого байта которого равен значению bl  

Следующая программа иллюстрирует на несложной задаче особенности применения функций выделения (malloc) и освобождения (free) динамической памяти. Решается следующая задача: ввести и напечатать в обратном порядке набор вещественных чисел, количество которых заранее не фиксировано, а вводится до начала ввода самих числовых значений. Текст программы может быть таким:

#include <stdio.h>

#include <stdlib.h>

void main (){

/* Указатель для выделяемого блока памяти */

float *t;

int i, n;

printf ("\nn="); /* n - число элементов */

scanf ("%d",&n);

t= (float *)malloc(n*sizeof (float));

for{i=0; i<n; i++) /* Цикл ввода чисел */

{ printf ("x[%d]=",i);

scanf ("%f", fit [i]); }

/* Цикл печати результатов */

for(i=n-l; i>=0; i --){

if(i%2== 0)printf ("\n"); printf ("\tx[%d]=%f",i,t[i];

}free (t); /* Освобождение памяти */}

В программе int n – количество вводимых чисел типа float, t – указатель на начало области, выделяемой для размещения n вводимых чисел. Указатель t принимает значение области, выделяемой для n значений типа float. Обратите внимание на приведение типа (float*) значения, возвращаемого функцией malloc(). Доступ к участкам выделенной области памяти выполняется с помощью операции индексирования: t[i] и t[i-l]. Остальное очевидно из текста программы. Оператор free(t); содержит вызов функции, освобождающей выделенную ранее динамическую память и связанной с указателем t.





Поделиться с друзьями:


Дата добавления: 2016-03-28; Мы поможем в написании ваших работ!; просмотров: 671 | Нарушение авторских прав


Поиск на сайте:

Лучшие изречения:

Не будет большим злом, если студент впадет в заблуждение; если же ошибаются великие умы, мир дорого оплачивает их ошибки. © Никола Тесла
==> читать все изречения...

3134 - | 2817 -


© 2015-2025 lektsii.org - Контакты - Последнее добавление

Ген: 0.012 с.