Все лекции программирование
.pdfПример
#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. Функции