Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Рацеев С.М. Программирование на языке Си.pdf
Скачиваний:
369
Добавлен:
23.03.2016
Размер:
1.65 Mб
Скачать

Вычисление разности указателей. Можно вычислять раз-

ность двух указателей.

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

7.5. Указатели с типом void

Рассмотрим особенности указателей, имеющие тип void. Чтобы присвоить значению указателя с типом void значение другого указателя, то в данном случае не требуется приведения типов:

char c; int a; double x; void *p;

p = &c; p = &a; p = &x;

Таким образом, к указателю с типом void можно присвоить значение указателя любого типа. При этом чтобы использовать операцию *, необходимо явное приведение типа:

double x; void *p; p = &x;

*(double *)p = 0.5; printf("%f\n", *(double *)p);

Также чтобы применять арифметические операции, необходимо явное приведение типа:

int a[5] = {1, 2, 3, 4, 5}; void *p;

p = a;

((int *)p)++; printf("%d\n", *(int *)p);

94

7.6. Модификатор const

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

const int i = 10;

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

имя_функции (const int *a, const int n)

Если происходит попытка изменить значение аргумента, который был объявлен с модификатором const, тогда компилятор выдаст предупреждение либо сообщение об ошибке.

7.7. Массивы переменного размера

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

95

Чтобы создать динамический массив, необходимо указать функции calloc() тип элементов массива и их количество. Например, если требуется динамический массив a из 100 элементов типа double, тогда необходимо выполнить следующее:

double *a; /* указатель на динамический массив */ /* блок из 100 элементов типа double: */

a = (double *)calloc(100, sizeof(double));

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

Создать динамический массив также можно при помощи функции malloc():

double *a;

/* блок из 100 элементов типа double:*/ a = (double *)malloc(100 * sizeof(double));

В отличие от функции calloc(), элементы выделенной области памяти не обнуляются.

Если динамический массив a после работы с ним больше не нужен, то выделенную под него память можно освободить функци-

ей free(): free(a);

Ниже приводится пример создания динамического массива.

#include<stdio.h>

#include<stdlib.h>

/* вывод элементов массива на экран */ void Print(const int *a, const int n)

{

int i;

for (i = 0; i < n; i++) printf("%d ", a[i]);

printf("\n");

96

}

int main( )

{

int *a,

/* адрес первого элемента динамического массива */

size,

/* размер динамического массива a */

i;

/* счетчик */

scanf("%d", &size); /* вводим размер массива с клавиатуры */ a = (int *)calloc(size, sizeof(int)); /* выделяем память под массив */ if (a == NULL)

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

{

/* заполняем элементы массива произвольными числами */ for (i = 0; i < size; i++)

a[i] = rand()%10; Print(a, size);

free(a); /* освобождаем память, выделенную под массив */

}

return 0;

}

Если во время работы с динамическим массивом необходимо изменить его размер, то в этом случае поможет функция realloc():

void *realloc(void *p, size_t size)

Функция realloc() заменяет на size размер объекта, на который указывает указатель p. Для той части, размер которой равен наименьшему из старого и нового размеров, содержимое не изменится. Если новый размер больше старого, тогда дополнительного пространства не инициализируется, в этом случае функция realloc() возвращает указатель на новое место памяти. Если же памяти запрашиваемого объема нет, тогда функция realloc() возвращает значение NULL, причем *p при этом не изменяется.

#include<stdio.h>

#include<stdlib.h>

97

void Print(const int *a, const int n)

{

int i;

for (i = 0; i < n; i++) printf("%d ", a[i]);

printf("\n");

}

int main( )

{

int *a,

/* адрес первого элемента динамического массива */

size,

/* размер динамического массива a */

new_size , /* новый размер массива a */

i,

/* счетчик */

*tmp;

scanf("%d", &size); /* вводим размер массива с клавиатуры */ a = (int *)calloc(size, sizeof(int)); /* выделяем память под массив */ if (a == NULL)

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

{

for (i = 0; i < size; i++) a[i] = rand()%10;

Print(a, size);

new_size = 2 * size; /* новый размер массива a */ tmp = (int *)realloc(a, new_size * sizeof(int));

if (tmp != NULL)

{

a = tmp;

for (i = size; i < new_size; i++) a[i] = rand()%10;

Print(a, new_size);

}

free(a);

}

return 0;

}

98