Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Все лекции программирование

.pdf
Скачиваний:
25
Добавлен:
13.03.2016
Размер:
1.94 Mб
Скачать

Пример

#include <stdio.h> int main(void)

{

int x[100]; int t;

for(t=0; t<10; t++) *(x+t) = t;

for(t=0; t<10; t++) printf("%3d %10p\n", *(x+t), x+t); return 0;

}

c:\>Example.exe

0001AFA4C

1001AFA50

2001AFA54

3001AFA58

4001AFA5C

5001AFA60

6001AFA64

7001AFA68

8001AFA6C

9001AFA70

Преобразование типа указателя

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

#include <stdio.h>

int main(void)

{

unsigned int x = 2882400172, y=0; unsigned char *p=0;

printf("Pointers x: %p, p: %p, y: %p\n", &x,p,&y); p = (unsigned char *) &x;

y = *p;

printf("Pointers x: %p, p: %p, y: %p\n", &x,p,&y); printf("Pointers x: %p, p: %p, y: %p\n", &x+1,p+1,&y+1); printf("(int) Var: %x\n", x);

printf("(char) Var: %x %x %x %x\n", *p, *(p+1),*(p+2),*(p+3)); printf("Pointers p: %p %p %p %p\n", p, (p+1),(p+2),(p+3)); printf("(char) Var y: %x!\n", y);

printf("(int) Pointer y: %p!\n", &y); printf("x=%u and y=%u\n", x,y); return 0;

}

c:\>Example.exe

Pointers x: 0037FD90, p: 00000000, y: 0037FD98 Pointers x: 0037FD90, p: 0037FD90, y: 0037FD98 Pointers x: 0037FD94, p: 0037FD91, y: 0037FD9C (int) Var: abcdefac

(char) Var: ac ef cd ab

Pointers p: 0037FD90 0037FD91 0037FD92 0037FD93 (char) Var y: ac!

(int) Pointer y: 0037FD98! x=2882400172 and y=172

Многоуровневая адресация

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

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

#include <stdio.h>

int main(void)

{

int x, *p, **q; x = 10;

p = &x; q = &p;

printf("%d", **q); return 0;

}

c:\>Example.exe

10

Пример

#include <stdio.h>

 

 

int main(void)

 

 

{

 

 

int a[3][4],i,j;

 

 

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

 

 

for(j=0;j<4;j++) {

 

 

a[i][j]=i*4+j;

c:\>Example.exe

 

}}

 

0->0037FAB0 1->0037FAB4 2->0037FAB8 3->0037FABC

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

4->0037FAC0 5->0037FAC4 6->0037FAC8 7->0037FACC

for(j=0;j<4;j++) {

8->0037FAD0

9->0037FAD4 10->0037FAD8 11->0037FADC

printf("%3d->%p ", a[i][j], &a[i][j]);

 

 

}

0->0037FAB0 1->0037FAB4 2->0037FAB8 3->0037FABC

printf("\n");

4->0037FAC0

5->0037FAC4 6->0037FAC8 7->0037FACC

}

8->0037FAD0

9->0037FAD4 10->0037FAD8 11->0037FADC

 

printf("\n"); for(i=0;i<3;i++) { for(j=0;j<4;j++) {

printf("%3d->%p ", *((int *)a+i*4+j), ((int *)a+i*4+j));

}

printf("\n");

}

return 0;

}

Функции динамического

распределения

Указатели используются данных. Динамическое данных во время своего

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

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

Память, выделяемая в C функциями динамического распределения данных, находится в т.н. динамически распределяемой области памяти (heap). Динамически распределяемая область памяти – это свободная область памяти, не используемая программой, операционной системой или другими программами. Размер динамически распределяемой области памяти заранее неизвестен, но как правило в ней достаточно памяти для размещения данных программы. Хотя размер динамически распределяемой области памяти очень большой, все же она конечна и может быть исчерпана.

Основу системы динамического распределения в С составляют функции malloc() и free(). Эти функции работают совместно. Функция malloc() выделяет память, а free() – освобождает ее.

Функция malloc()

Прототип функции malloc() следующий:

void *malloc(size_t количество_байтов);

Здесь количество_байтов – размер памяти, необходимой для размещения данных. Функция malloc() возвращает указатель типа void *, поэтому его можно присвоить указателю любого типа. При успешном выполнении malloc() возвращает указатель на первый байт непрерывного участка памяти, выделенного в динамически распределяемой области памяти. Если в динамически распределяемой области памяти недостаточно свободной памяти для выполнения запроса, то память не выделяется и malloc() возвращает нуль.

При выполнении следующего фрагмента программы выделяется непрерывный участок памяти объемом 1000 байтов:

char *p;

p = malloc(1000); /* выделение 1000 байтов */

После присвоения указатель p ссылается на первый из 1000 байтов выделенного участка памяти.

Функции malloc() и free()

Поскольку динамически распределяемая область памяти не бесконечна, при каждом размещении данных необходимо проверять, состоялось ли оно. Если malloc() не смогла по какой-либо причине выделить требуемый участок памяти, то она возвращает нуль. В следующем примере показано, как выполняется проверка успешности размещения:

p = malloc(100); if(!p) {

printf("Нехватка памяти.\n");

}

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

void free(void *p);

Здесь р – указатель на участок памяти, выделенный перед этим функцией malloc(). Функцию free() ни в коем случае нельзя вызывать с неправильным аргументом, это мгновенно разрушит всю систему распределения памяти.

Динамическое выделение

памяти для массивов

Довольно часто возникает необходимость выделить память динамически, используя malloc(), но работать с этой памятью удобнее так, будто это массив, который можно индексировать. В этом случае нужно создать динамический массив. Сделать это несложно, потому что каждый указатель можно индексировать как массив.

#include <stdlib.h>

int main(void)

{

char *s;

s = malloc(80); if(!s) {

printf("Memory is empty.\n"); exit(1);

}

scanf("%s",s); printf(s); free(s);

return 0;

}

Динамическая память для

многомерного массива

#include <stdlib.h> int main(void)

{

int (*p)[10]; int i, j;

p = (int (*)[10]) malloc(100*sizeof(int)); if(!p) {

printf("Memory is empty.\n"); exit(1);

}

printf("The Table of Multiplication\n"); for(j=0; j<10; j++)

for(i=0; i<10; i++) p[i][j] = (j+1)*(i+1);

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

for(i=0; i<10; i++) printf("%4d ", p[i][j]); printf("\n");

}

free(p); return 0;

}

Лекция 8. Функции