1.6. Препроцессор

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

Директива #define.

Директива #define может появляться в любом месте программы, а даваемое ею определение имеет силу от места до конца программы.

#include <iostream.h>

#include <stdio.h>

#define TRI 3

#define OTWET TRI*TRI

#define OT printf("ОТВЕТ равен %d.\n",OTWET)

#define jd cin >>C;

main( )

{

int C;

OT;

jd;

}

После выполнения программы получится:

ОТВЕТ равен 9

В первой строке программы TRI - это макроопределение и оно равно 3, где 3 - строка замещения.

Во второй строке макроопределение OTWET имеет строку замещения TRI*TRI и т.д. Каждая строка состоит из трех частей. Первой стоит директива #define, далее идет макроопределение. Макроопределение не должно содержать внутри себя пробелы. И, наконец, идет строка (называемая "строкой замещения"), которую представляет макроопределение. Когда препроцессор находит в программе одно из макроопределений, он заменяет его строкой замещения. Этот процесс прохождения от макроопределения до заключительной строки замещения называется "макрорасширением".

Директива #include.

Когда препроцессор "распознает" директиву #include, он ищет следующее за ней имя файла и включает его в текущую программу. Директива бывает в двух видах:

#include<stdio.h> имя файла в угловых скобках

#include "my.h" имя файла в двойных кавычках

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

Директивы: #undef, #ifdef, #else, #endif

Эти директивы позволяют приостановить действие более ранних определений.

Директива #undef отменяет самое последнее определение поименованного макроопределения.

#define TRI 3

#define F 5

#undef TRI /* TRI теперь не определен */

#define F 10 /* F переопределен как 10 */

#undef F /* F снова равен 5 */

#undef F /* F теперь не определен */

Рассмотрим еще пример.

#ifdef OTW

#include "otw.h" /* выполнится, если OTW определен */

#define ST 10

#else

#include "w.h" /* выполнится, если OTW не определен */

#define ST 20

#endif

Директива ifdef сообщает, что если последующий идентификатор OTW определяется препроцессором, то выполняются все последующие директивы вплоть до первого появления #else или #endif. Когда в программе есть #else, то программа от #else до #endif будет выполняться, если идентификатор не определен.

1.7 Программы. Функции

Как мы рассматривали раньше, программа на Си имеет корневой сегмент, начинающийся с директив препроцессора и ключевого слова main.

Далее идет собственно программа, начинающаяся с открывающейся фигурной скобки { и заканчивающаяся закрывающейся фигурной скобкой }.

Часто используемые участки программы выделяются в функции. Каждая функция также начинается с директив препроцессора и имени и скобок { }.

Рассмотрим пример программы рисования лестницы.

#include <stdio.h>

main()

{

printf("|----|\n");

printf("|----|\n");

printf("|----|\n");

}

А теперь напишем эту программу с использованием функции Lestniza.

#include <stdio.h>

Lestniza(void)

{

printf("|----|\n");

}

main()

{

Lestniza();

Lestniza();

Lestniza();

}

Как видно из программы, обращение к функции осуществляется три раза. Для преодоления этого недостатка переработаем программу и введем формальные и фактические аргументы:

#include <stdio.h>

int C;

Lestniza(int B)/* B - формальный аргумент */

{

int A;

for (A = 1; A <= B; A++)

printf("|----|\n");

}

main()

{

Lestniza(3); /* 3 -фактический аргумент */

}

В данной функции B является формальным аргументом (конечная величина оператора for to). Для присвоение ей конкретного значения используется фактический аргумент, который передается функции при ее вызове в основной программе.

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

Рассмотрим функции, возвращающее свое значение на примере возведения числа в квадрат.

#include <stdio.h>

float Kwadrat(float A)

{

return A * A;

}

float B;

main()

{

printf("? \n");

scanf("%f",&B);

printf("Kwadrat = %8.2f\n",Kwadrat(B));

}

Как видно из примера - имя функции Kwadrat - она вычисляет квадрат числа. В строке printf("Kwadrat = %8.2f\n",Kwadrat(B)); эта функция вызывается - на вход подается значение (введенное число), а в результате получаем результат - квадрат числа, который возвращается в программу по команде return.

Рассмотрим еще один вариант работы с функцией, возвращающей значение без команды return.

#include <stdio.h>

Kwadrat(float A, float *B)

{

*B = A * A;

}

float C, D;

main()

{

printf("? \n");

scanf("%f",&C);

Kwadrat(C,&D);

printf("Kwadrat = %8.2f\n",D);

}


1.8. Указатели

Указатель - это переменная, содержащая адрес данных, а не их значение. Указатель используется:

1.Для связи независимых структур друг с другом.

2.Для динамического распределения памяти.

3.Для доступа к различным элементам структуры.

Рассмотрим следующую программу:

#include <stdio.h>

main()

{

int Z,*Y;

Y =&Z;

Z = 100;

printf("Прямое значение Z: %d\n", Z);

printf("Значение Z, полученное через указатель: %d\n",*Y);

printf(" Адрес Z через получение адреса: %p\n",&Z);

printf("Адрес Z через указатель: %p\n", Y);

}

В данном примере Y указатель на целую переменную и содержит ее адрес. В свою очередь & позволяет получить адрес по которому размещено значение переменной Z. В этой программе:

- адрес переменной Z присваивается Y;

- целое значение 100 присваивается Z;

- оператор &, позволяет получить адрес,

по которому размещено значение Z.

Результат работы программы:

Прямое значение Z: 100

Значение Z, полученное через указатель: 100

Адрес Z через получение адреса: 85B3:0FDC

Адрес Z через указатель: 85B3:0FDC

Указатели также используются для оптимального распределения памяти.

Рассмотрим пример указателя на число типа char.

#include <stdio.h>

#include <alloc.h>

#include <string.h>

#include <stdlib.h>

#include <process.h>

int main(void)

{

char *str; /* указатель на символьную переменную */

str = (char *)malloc(10);

strcpy(str, "Hello");

printf("String is %s\n", str);

free(str);

return(0);

}

Вначале по команде char *str; создан тип str, который является указателем на переменную типа char(* обозначает "указатель"). По команде str = (char *)malloc(10); выделяем 10 байт памяти под переменную str(типа строка). По команде strcpy(str, "Hello"); осуществляется - "записать в область памяти, на которую указывает str, строку символов "Hello". По команде printf("String is %s\n", str); осуществляется "напечатать на экране то, на что указывает str. Команда free(str); освобождает память, на которую указывает str.

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

#include <stdio.h>

#include <string.h>

#include <alloc.h>

#include <process.h>

struct Student { /* запись Student */

char Fio[30]; /* поле записи Fio */

int Gruppa; /* поле записи Gruppa */

}; /* конец записи */

struct Student *A;

main()

{

if ((A =(Student *) malloc(sizeof(Student))) == NULL)

{

printf("Нет памяти\n");

exit(1);

}

strcpy(A[1].Fio, "Ivanov");

A[1].Gruppa=385;

printf("Fio1 %s\n Gruppa %d\n", A[1].Fio, A[1].Gruppa);

strcpy(A[2].Fio, "Petrow");

A[2].Gruppa=386;

printf("Fio2 %s\n Gruppa %d\n", A[2].Fio, A[2].Gruppa);

free(A);

}

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

Пусть poit является указателем на структуру и что elem элемент, определенный структурным шаблоном. Тогда point->elem определяет элемент, на который выполняется ссылка. Рассмотрим предыдущий пример.

struct Student { /* запись Student */

char Fio[30]; /* поле записи Fio */

int Gruppa; /* поле записи Gruppa */

}; /* конец записи */

Student *poin;

Сейчас к полям структуры мы можем обращаться несколькими способами. Эквивалентные обращения:

Student.Gruppa=236;

poin->Gruppa=236;

Отметим одну важную особенность указателей в Си. Транслятор автоматически учитывает тип указателя в арифметических действиях над ним. Например если i есть указатель на целую (т.е. двухбайтную) переменную, то действие типа i++ означает, что указатель получает приращение не один, а два байта, т.е. будет указывать на следующую переменную или элемент массива. По этой причине указатель можно использовать вместо индексов массива. Например если A - указатель на массив целого типа, то вместо A[i] можно писать *(A+i). Более того, использование указателей вместо индексов позволяет компилятору создавать более компактный и быстрый код.


Информация о работе «Основы C»
Раздел: Информатика, программирование
Количество знаков с пробелами: 200759
Количество таблиц: 5
Количество изображений: 11

Похожие работы

Скачать
20474
0
0

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

Скачать
5443
0
0

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

Скачать
8522
1
2

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

Скачать
11185
0
0

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

0 комментариев


Наверх