double arrow

Определение указателей

Указатели

Простейший пример создания собственной базы данных

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

Пример программы работы с файлом структур:

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

#include<stdio.h>

#include<conio.h>

#include<iostream.h>

struct Sved {

char Fam[30];

float S_Bal;

} zap,zapt;

char Spis[]="Sp.dat";

FILE *F_zap;

FILE* Open_file(char *, char *);

void main (void) {

int i, j, kodR, nom, size = sizeof(Sved);

while(1) {

puts("Sozdanie - 1\nProsmotr - 2\nDobavlenie - 3\nVyhod - 0");

switch(kodR = getch())

{

case '1': case '3':

if(kodR==1) F_zap = Open_file (Spis,"w+");

else F_zap = Open_file (Spis,"a+");

while(2) {

cout << "\n Fam "; cin >> zap.Fam;

if((zap.Fam[0])=='0') break;

cout << "\n Srednij ball: ";

cin >> zap.S_Bal;

fwrite(&zap,size,1,F_zap);

}

fclose(F_zap);

break;

case '2': F_zap = Open_file (Spis,"r+"); nom=1;

while(2) {

if(!fread(&zap,size, 1, F_zap)) break;

printf(" %2d: %20s %5.2f\n", nom++, zap.Fam, zap.S_Bal);

}

fclose(F_zap);

break;

case '0': return; // exit(0);

} // Конец While(1)

} // Конец switch

} // Конец программы

// Нижеприведенная функция служит для того же, что и fopen(), но при

// неудаче выдает на экран ошибку

FILE* Open_file(char *file, char *kod)

{

FILE *f;

if(!(f = fopen(file, kod)))

{

puts("File isn\'t created!");

getch();

exit(1);

}

else return f;

}


Как говорилось выше, машинная память состоит из байт. Все байты в памяти пронумерованы. Адресом байта называется его номер. (Нумерация при этом идет либо в пределах всей машинной памяти, либо (чаще) в пределах выделенной программе области памяти - сегмента). Если переменная (или массив) занимают несколько или много байт, эти байты всегда идут подряд, и адресом переменной считается номер ее первого байта.

При обработке декларации любой переменной, например double x =1.5; компилятор выделяет для переменной участок памяти, размер которого определяется ее типом (double – 8 байт) и инициализирует его указанным значением (если таковое присутствует). Далее все обращения в программе к переменной по ее имени заменяются компилятором на адрес участка памяти, в котором будет храниться значение этой переменной.

Разработчик программы на языке Си имеет возможность определить собственные переменные для хранения адресов участков оперативной памяти. Такие переменные называются указателями.

Итак, указатель – это переменная, которая может содержать адрес некоторого объекта. Простейшая декларация указателя имеет формат:

тип * ID_указателя;

Например: int *a; double *f; char *w;

Здесь тип может быть любым кроме ссылки или битового поля, причем тип может быть к этому моменту только декларирован, но еще не определен (следовательно, в структуре, например, может присутствовать указатель на структуру того же типа).

Символ «звездочка» относится непосредственно к ID указателя, поэтому для того, чтобы декларировать несколько указателей, ее нужно записывать перед именем каждого из них.

Например, в декларации:

int *a, *b, с;

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

Значение указателя равно номеру первого байта участка памяти, на который он ссылается.

Указатели предназначены для хранения адресов областей памяти. В языке Cи имеются три вида указателей – указатели на объект известного типа, указатель типа void и указатель на функцию. Эти три вида отличаются как своими свойствами, так и набором допустимых операций. Указатель не является самостоятельным типом данных, так как всегда связан с каким-либо конкретным типом, т.е. указатель на объект содержит адрес области памяти, в которой хранятся данные определенного типа.

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

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

Указатель может быть константой или переменной, а также указывать на константу или переменную.

С указателями-переменными связаны две унарные операции & и *.

Операция & означает «взять адрес» операнда. Операция * имеет смысл – «значение, расположенное по указанному адресу» (операция разадресации).

Таким образом, обращение к объектам любого типа как операндам операций в языке Cи может производиться:

– по имени (идентификатору);

– по указателю (операция косвенной адресации):

ID _указателя = & ID _объекта; -операция разыменования;

* ID _указателя - операция косвенной адресации.

Говорят, что использование указателя означает отказ от именования адресуемого им объекта.

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

Унарная операция получения адреса & применима к переменным, имеющим имя (ID), для которых выделены участки оперативной памяти. Таким образом, нельзя получить адрес скалярного выражения, неименованной константы или регистровой переменной (типа register).

Отказ от именования объектов при наличии возможности доступа по указателю приближает язык Си по гибкости отображения "объект – память" к языку ассемблера.

Пример 1:

int x, – переменная типа int;

*y; – указатель на объект типа int;

y = &x; – y – адрес переменной x;

*y=1; – косвенная адресация указателем поля x, т.е. по указанному адресу записать 1: x = 1.

Пример 2:

int i, j=8,k=5, *y;

y=&i;

*y=2; // i=2

y=&j;

*y+=i; // j+=i ® j=j+i ® j=j+2=10

y=&k;

k+=*y; // k+=k ® k=k+k = 10

(*y)++; // k++ ® k=k+1 = 10+1 = 11

Указателю-переменной можно присвоить значение другого указателя, либо выражения типа указатель с использованием, при необходимости, операции приведения типа. Приведение типа необязательно, если изменяемый ("стоящий слева" в операции =) указатель имеет тип "void *".

int i,*x;

char *y;

x=&i; // x ® поле объекта int

y=(char *)x; // y ® поле объекта char

y=(char *)&i; // y ® поле объекта char

Значение указателя можно вывести на экран с помощью спецификации %p (pointer), результат выводится в шестнадцатеричном виде.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



Сейчас читают про: