Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lec_cvv.docx
Скачиваний:
8
Добавлен:
01.06.2015
Размер:
110.86 Кб
Скачать

2.2.Арифметические и логические выражения

В языке С используются арифметические операции сложения (+), вычитания (-), умножения (*), деления (/) и деления по модулю (%). Выражение a%b дает остаток от деления a на b (операцию % нельзя использовать для переменных типа float и double).

К операциям отношения и логическим операциям относятся: больше (>), больше или равно (>=), меньше (<), меньше или равно (<=), равно (==), не равно (!=), логическое «И» (&&), логическое «ИЛИ» (||), логическое отрицание (!). Операция !а дает нулевой результат, если а не равно нулю и единичный, если а равно нулю. Нельзя путать операцию сравнения (==) и операцию присваивания (=).

Операции увеличения на единицу (++) и уменьшения на единицу (--) можно записывать как перед переменной, так и после нее. В первом случае значение аргумента изменяется перед, а во втором случае после его использования.

Предусмотрены также операции с битами (разрядами), которые нельзя применять к переменным типа float и double. К таким операциям относятся: поразрядное «И» (&), поразрядное «ИЛИ» (|), поразрядное «Исключающее ИЛИ» (^), сдвиг влево (<<), сдвиг вправо (>>), поразрядная инверсия (~). Примеры:

Пусть а=1011, b=0110, тогда a&b=0010, a|b=1111, a^b=1101, a<<2=1100, b>>1=0011, ~a=0100.

Рассмотренные операции и оператор присваивания используются для построения выражений, которые представляют собой формулы для вычисления значения. Выражение вида а=а+5 можно записывать и таким образом: а+=5. На месте знака + разрешается использовать и символы других бинарных операций (+, -, *, /, %, <<, >>, &, ^, |). Часто используется тернарная операция ?:. В формуле y=x?a:b, y=a, если х принимает истинное (ненулевое) значение, и y=b, если х принимает ложное (нулевое) значение.

Программы Р4-Р7 демонстрируют использование рассмотренных выше операций.

/*Программа Р4. Арифметические операции*/

#include<stdio.h>

main(){

int x, y, ASUM, ARAZ, AUM, ADEL, ADC;

x=30; y=6;

ASUM=x+y;

ARAZ=x-y;

AUM=x*y;

ADEL=x/y;

ADC=x%(y+2); /*определяется остаток от деления х на у*/

printf(“ASUM=%d ARAZ=%d AUM=%d ADEL=%d ADC=%d”,ASUM, ARAZ, AUM, ADEL, ADC);

}

Результат:

ASUM=36 ARAZ=24 AUM=180 ADEL=5 ADC=6

/*Программа Р5. Отношения и логические операции*/

#include<stdio.h>

main(){

int a, b, c;

puts(“введите целые значения a, b, c”);

scanf(“%d%d%d”, &a, &b, &c);

if(a>b&&b>=c) puts(“a>b>=c”);

else if(a==b||c!=0) puts(“a=b или с не равно 0”);

else if(!c) printf(“a<b и c=0\n”);

else printf(“условия не выполняются”);

}

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

Введите целые значения a, b, c

3 5 7

a=b или с не равно 0

/*Программа Р6. Операции увеличения и уменьшения*/

#include<stdio.h>

main(){

int a=0, b=0, c=0, d=0, n=2, m=10;

a=++n; n=2; b=n++; n=2; c=--n; n=2; d=n--;

printf(“a=%d b=%d c=%d d=%d n=%d\n”, a, b, c, d, n);

a+=2; b-=2; c*=2; d%=2; m/=2;

printf(“a=%d b=%d c=%d d=%d m=%d\n”, a, b, c, d, m);

}

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

a=3 b=2 c=1 d=2 n=1

a=5 b=0 c=2 d=0 m=5

/*Программа Р7. Демонстрация тернарной операции*/

#include<stdio.h>

main(){

int y, s[50], i;

puts(“введите целое значение у”);

scanf(“%d”, &y);

for(i=1; i<50; i++) {s[i]=i;

printf(“%5.2d%c”, s[i], (i%y==0||i==50-1)?’\n’:’ ‘););

} /*вывод в цикле for на экран 49 элементов массива s по у чисел в строке*/

}

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

Введите целое значение у

10

01 02 03 04 05 06 07 08 09 10

11 12 13 14 15 16 17 18 19 20

21 22 23 24 25 26 27 28 29 30

31 32 33 34 35 36 37 38 39 40

41 42 43 44 45 46 47 48 49

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

- char и short преобразуются в int; float преобразуется в double;

- если один из операндов двойной точности, то другие преобразуются к двойной точности и результат будет двойной точности;

- в противном случае, если один из операндов long, то другие преобразуются к long и результат будет long;

- в противном случае, если один из операндов unsigned, то другие преобразуются к unsigned и результат будет unsigned;

- в противном случае операнды должны быть типа int и результат будет int.

Преобразования типов происходят и при присваивании: значение из правой части преобразуется к типу левой. При передаче переменной функции тоже происходят соответствующие преобразования.

2.3.Приоритеты и порядок вычислений.

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

() [] ->

! - ++ -- (тип) – операции выполняются справа налево

* & (* и & адресные операции) sizeof

* / %

+ -

<< >>

< <= > >=

== !=

&

^

:

&&

|| – операция выполняется справа налево

?: – операция выполняется справа налево

= += -= и т.д.

, (операция запятая)

2.4.Операторы организации циклов

В языке С 3 оператора организации циклов: for, while, do-while. Их формальная запись:

for(выражение1; выражение2; выражение3) тело цикла

while(выражение) тело цикла

do тело цикла while(выражение)

Тело цикла составляет либо один оператор, либо любое подмножество операторов, заключенных в фигурные скобки. Каждый оператор в языке С оканчивается точкой с запятой. Любое из 3-х выражений в цикле for может отсутствовать, однако точка с запятой должна оставаться.

В теле цикла могут использоваться операторы break и continue. Первый обеспечивает немедленный выход из цикла. Второй вызывает прекращение очередной и начало следующей итерации. Операция «запятая» чаще всего используется в операторе for. Пара выражений, разделенных запятой, вычисляется слева направо. Таким образом в операторе for можно в каждой из частей помещать по несколько выражений, например, для параллельной обработки 2-х индексов.

2.5.Операторы организации переходов.

Это операторы if-else, switch, goto. Их формальная запись выглядит так:

1) if(выражение) оператор1; else оператор2;

2) switch(выражение){

case константа1: вариант1;…;

case константа N: вариант N;

default: вариант N+1;}

3) goto метка;

В операторе if слово else может отсутствовать. Если вместо одного необходимо использовать несколько операторов, то они заключаются в фигурные скобки. Переключатель switch позволяет выбрать одну из нескольких альтернатив. Если default отсутствует, а все результаты сравнения отрицательны, то ни один вариант не выполняется. Для прекращения последующих проверок после выбора варианта используется оператор break, обеспечивающий немедленный выход из switch.

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

Примеры:

/*Программа Р8. Демонстрация переключателей*/

#include<stdio.h>

main(){

int y, a, b;

char znak;

printf(“\t введите значения а, операция (+, -, *, /, %), b\n\n”);

scanf(“%d%c%d”, &a, &znak, &b); /*ввод с клавиатуры значений a, b, znak*/

switch(znak){

case ‘+’: y=a+b; break;

case ‘-’: y=a-b; break;

case ‘*’: y=a*b; break;

case ‘/’: y=a/b; break;

case ‘%’: y=a%b; break;

default: printf(“недопустимая операция”); break;}

if(znak==’+’ || ‘-‘ || ‘*’ || ’/’ || ‘%’)

printf(“a %c b=%d”, znak, y);

}

Результаты выполнения программы:

Введите значения а, операция (+, -, *, /, %), b

48%9

a % b=3

Программа Р9 позволяет найти позиции единиц в коде ASCII соответствующего символа. Например, этот код для цифры 4 равен 52 (двоичный код 110100). Позиции нумеруются справа налево, и самая правая из них считается нулевой. Таким образом в коде цифры 4 единицы будут во 2-м, 4-м и 5-м разрядах. Выход из программы осуществляется после ввода символа $.

/*Программа Р9. Демонстрация циклов while и for*/

#include<srdio.h>

#define MASK ‘\001’ /*в коде маски MASK единица будет только в одном младшем разряде*/

main(){

int a, i;

while((a=getchar())!=’$’){

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

if(a & MASK) printf(“единица в %d разряде”, i);

a>>1;} /*код целого числа сдвигается вправо на единицу; если в крайнем разряде единица, то включается функция printf() после оператора if*/

a=getchar(); /*если убрать эту строку, то будут вводиться коды клавиши ВВОД*/

}

}

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

4

Единица в 2 разряде

Единица в 4 разряде

Единица в 5 разряде

P

Единица в 4 разряде

Единица в 5 разряде

Единица в 6 разряде

$

Следующая программа Р10 выводит введенную строку в обратном порядке и выделяет из полученной строки все цифры.

/*Программа Р10. Демонстрация операторов do-while, break, continue и операции «,»*/

#include<stdio.h>

main(){

int i, j, c, k=0;

char s[50], sn[50];

printf(“введите строку\n”);

do{

scanf(“%s”, s);

for(i=0, j=strlen(s)-1; i<j; i++, j--){ /*strlen() библиотечная функция, определяющая длину строки s; в цикле for одновременно изменяются 2 управляющих параметра i и j, используется операция «,»*/

c=s[i]; s[i]=s[j]; s[j]=c;}

printf(“%s\n”, s);}

while(s[0]==’0’); /*если строка s заканчивается нулем, то повторить цикл do*/

for(i=0; i<strlen(s); i++){

if(s[i]==’@’) break;

if(s[i]<’0’ || s[i]>’9’) continue;

sn[k++]=s[i]; /*занесение очередной цифры в строку sn*/

sn[k]=’\0’; /*записывается признак конца строки, иначе на экран могут выводиться ненужные символы*/

printf(“цифры в строке s – %s”, sn);

}

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

Введите строку

Дом_56, квартира_147

741_аритравк, 65_мод

Цифры в строке s – 74165

3.ФУНКЦИИ В ЯЗЫКЕ С

3.1.Общие сведения

Программы на языке С обычно состоят из большого числа функций (подпрограмм), которые в основном имеют малые размеры и могут находиться как в одном, так и в нескольких файлах. Рассмотрим программу Р11, которая выполняет те же действия, что и Р10, но представлена в виде функции main() и 2-х вызываемых функций reverse() – для поворота строки s и сс() – для выделения цифр из строки s. Все 3 функции будут находиться в разных файлах, поэтому в функции main() появляются строки вида #include.

/*Программа Р11. Демонстрация функций */

#include<stdio.h>

main(){

int i, j, c, k=0;

char s[50], sn[50];

printf(“введите строку\n”);

do{

scanf(“%s”, s);

reverse(s); /*вызов функции reverse()*/

printf(“%s\n”, s);} /*вывод на экран повернутой строки*/

while(s[0]==’0’); /*если строка s заканчивается нулем, то повторить цикл do*/

cc(s, sn); /*вызов функции cc()*/

printf(“цифры в строке s – %s”, sn); /*выводится на экран строка sn до тех пор, пока не встретится признак ее конца “\0”*/

}

#include “reverse.c”

#include “cc.c”

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

Введите строку

Дом_56, квартира_147

741_аритравк, 65_мод

Цифры в строке s – 74165

/*Пример функции reverse(), находящейся в файле reverse.c*/

reverse(s)

char a[];

{

int i, j, c;

for(i=0, j=strlen(a)-1; i<j; i++, j--){ c=a[i]; a[i]=a[j]; a[j]=c;} /*строка a поворачивается еа 180 градусов*/

}

/*Пример функции cc(), находящейся в файле cc.c. Функция сс() выделяет цифры из строки s */

cc(s, sn)

char s[], sn[];

{

int i, k=0;

for(i=0; i<strlen(s); i++){

if(s[i]==’@’) break; /*строка s анализируется до первого введенного символа «@»*/

if(s[i]<’0’ || s[i]>’9’) continue;

sn[k++]=s[i]; /*занесение очередной цифры в строку sn*/

sn[k]=’\0’; /*В строке sn запоминаются цифры из строки s, в последнюю позицию строки sn записывается признак ее конца*/

}

Команда препроцессора #include “имя файла” подставляет содержимое файла с указанным именем. При другом варианте команды #include<имя файла> поиск файла идет только в стандартных местах.

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

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

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

Приведем пример программы Р12 и функции vv(), выдающей не целые значения.

/*Программа Р12. Вызов функции, выдающей не целые значения*/

#include<stdio.h>

main(){

double x=1.0, y=1.0, z=1.0, vv();

while(x>=0.0 && (z>0.1 || z<-0.1)){printf(“значение f=%f\n”, vv(x, y, z));

scanf(“%1f%1f%1f”, &x, &y, &z); } /*в цикле while проверяется возможность вычисления значения выражения в функции vv(); если выражение вычислить нельзя, то программа заканчивает работу*/

puts(“конец работы программы”);

}

#include “vv.c”

/*функция vv(), находится в файле vv.c, выдает не целые значения*/

double vv(x, y, z)

double x, y, z;

{

double f, sqrt(); /*библиотечную функцию sqrt() (извлечение квадратного корня) необходимо объявить как double*/

f=sqrt(x)+y/z;

return(f);

}

Результаты выполнения программы:

Значение f=2.000000

5 6 9

Значение f=2.902735

9 6 5

Значение f=4.200000

0 0 0

Конец работы программы

Функцию нужно объявить как double vv(), если этого не сделать, то возвращаемое значение имеет тип int или char. Объявление типа должно появиться в строке с именем функции и в вызывающей программе.

3.2.Классы переменных и область действия

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

Автоматические переменные по отношению к функциям являются внутренними. Их существование начинается при входе в программу (функцию) и заканчивается при выходе из нее. Для их объявления можно использовать ключевое слово auto.

Статические переменные (ключевое слово static) относятся к 3-му классу и могут быть внутренними и внешними. Внутренние статические переменные, как и автоматические, локальны по отношению к отдельной функции, однако они продолжают существовать после того как функция заканчивает работу. Другими словами, они являются собственной постоянной памятью для функции. Внешние статические переменные известны внутри оставшейся части исходного файла после того, как они в нем объявлены, однако в других файлах они не известны.

Регистровые переменные (ключевое слово register) интенсивно используются. Они могут помещаться во внутренние регистры процессора (если возможно), что приводит к более быстрой программе. Для регистровой переменной нельзя взять адрес, они могут быть только автоматическими либо формальными параметрами функции.

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

Массивы можно инициализировать, поместив в описании список требуемых значений, заключенных в фигурные скобки и разделенных запятыми. Для символьных массивов можно использовать строку вида char s[]=”Персональная ЭВМ”;. Если размер массива любого типа пропущен, то транслятор определяет его длину.

Ниже приведен пример текста программы Р17 с соответствующими подпрограммами, иллюстрирующий использование внешних и статических переменных, а также явную инициализацию. Функция main() находится в файле р17.с, а вызываемые функции pri0 и pri1 – в файле pri.c.

/*Программа Р17. Использование внешних и статических переменных*/

#include<stdio.h>

int x, y, f; /*объявление внешних переменных*/

static int a=3, b; /*объявление внешних статических переменных a, b целого типа, инициализация переменной а*/

main(){

void pril(void); /*объявление функции не возвращающей значение*/

puts(“введите значения x, y”);

scanf(“%d%d”, &x, &y); /*ввод значений внешних переменных*/

pri0(); /*обращение к функции pri0()*/

printf(“\tf=%d\n”, f); /*вывод на экран значения переменной f, вычисленного в функции pri0()*/

pri1(); /*обращение к функции pri1()*/

}

#include “pri.c”

/*Программа pri.c, содержащая функции pri0() и pri1()*/

pri0()

{

extern int x, y, f; /*описание внешних переменных x, y, f*/

extern int a, b; /*описание внешних переменных a, b, являющихся статическими*/

puts(“введите значение b”);

scanf(“%d”, &b);

printf(“программа pri0: a=%d; b=%d; x=%d; y=%d. \n\n”, a, b, x, y ); /*вывод значений внешних переменных, а, х и у получили значения вне этого файла, b получила значение в этом файле*/

if(a>b) f=x*y;

else f=x%y; /*вычисления f для примера*/

return(f);

}

void pri1(void); /*функция pri1()*/

{

printf(“\nпрограмма pri1: a+b=%d.\n”, a+b); /*выводится значение a+b для примера*/

}

Результаты выполнения программы Р17:

Введите значения ч, у

4 9

Введите значение b

6

Программа pri0: a=3; b=6; x=4; y=9.

f=4

программа pri1: a+b=9

Следующая программа Р16 иллюстрирует использование автоматических и регистровых переменных. Вызываемая функция inic находится в одном файле с Р16, а функция stat – нет.

/*Программа Р16. Использование автоматических и регистровых переменных; пример инициализации массива*/

#include<stdio.h>

main(){

int s[5]={2, 4, 8, 16, 32};

register a, b; /*объявление регистровых переменных*/

a=b=1;

stat(a, b); /*обращение к функции stat()*/

a=1; b=2;

stat(a, b);

inic(s);

}

#include “stat.c”

inic(s)

int s[];

{

int a; /*объявление локальной переменной а целого типа, она действует только в функции inic()*/

for(a=-2; a<=2; a++) printf(“инициализированное значение %d: – %d;\n”, a+3, s[a+2]);

}

stat(a, b)

{

static int x; /*статическая целая переменная х существует только в функции stat()*/

auto int c; /*автоматическая целая переменная с существует только в функции stat()*/

if(a==b){x=10; c=10;}

printf(“x=%d; c=%d.\n”, x, c);

x+=x; /*переменной х присваивается значение х+х*/

c+=c;

printf(“после приращения: x=%d; c=%d.\n”, x, c);

}

Результаты выполнения программы Р16:

х=10; с=10.

после приращения: х=20; с=20.

х=20; с=1.

После приращения: х=40; с=2.

Инициализированное значение 1: – 2;

Инициализированное значение 2: – 4;

Инициализированное значение 3: – 8;

Инициализированное значение 4: – 16;

Инициализированное значение 5: – 32;

3.3.Рекурсивные функции.

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

/*Программа Р15. Демонстрация рекурсивной функции nod()*/

#include<stdio.h>

main(){ /*Функции main() и nod() находятся в одном файле*/

int a, b;

puts(“введите первое и второе числа”);

scanf(“%d%d”, &a, &b);

printf(“наибольший общий делитель: $d\n”, nod(a, b));

}

nod(a, b)

{

int c;

if(b>a) c=nod(a, b);

else if(b<=0) c=a;

else c=nod(b, a%b);

return(c);

}

Результаты выполнения программы Р15:

Введите первое и второе числа

164 44

Наибольший общий делитель: 4

3.4.Макропроцессор

Предусмотрена возможность расширения языка с использованием макропроцессора (препроцессора). Команда: #define идентификатор подстановка – вызывает замену в тексте программы «идентификатор» на «подстановку». Если в «подстановке» есть длинные определения, продолжающиеся в следующей строке, то в конце очередной строки ставится символ «\». Допустима макроподстановка с аргументами.

Команда: #ifdef идентификатор – проверяет, определен ли в данный момент указанный идентификатор. За любой из этих команд может следовать произвольное число строк текста, возможно, содержащих инструкцию #else и заканчивающуюся строкой #endif. Если проверяемое условие истинно, то строки между #else и #endif игнорируются. Если проверяемое условие не выполняется, то игнорируются все строки между проверкой и #else, а если последней нет, то #endif.

Команда: #undef идентификатор – приводит к тому, что указанный идентификатор начинает считаться неопределенным, т.е. не подлежащим замене.

В программах Р31-Р33 иллюстрируются правила использования макроподстановок. Вводятся новые инструкции вывода на печать.

/*Программа Р31. Демонстрация работы препроцессора*/

#include<stdio.h>

#define print FILE*fopen(), *lst; lst=fopen(“prn”, “w”) /*выполняется замена строки FILE*fopen(), *lst; lst=fopen(“prn”,”w”) на слово print*/

#define write fprintf /*выполняется замена слова fprintf на слово write*/

#define read3(v1, v2, v3) scanf(“%d%d”, &v1, &v2, &v3) /*замена scanf(“%d%d”, &v1, &v2, &v3) на строку read3(v1, v2, v3) */

#define f(a, b, e, u) for(a=b; a<=e; a+=u)

#define begin { /*замена открывающейся фигурной скобки на слово begin */

#define end }

main()

begin /*макроподстановка*/

int i, b, e, u;

print; /*макроподстановка*/

write(lst, “демонстрационная программа\n”); /*макроподстановка*/

printf(“\tВведите значения: \n\tb – начальное значение; \n\te – конечное значение; \n\tu – приращение. \n”);

read3(b, e, u); /*макроподстановка*/

f(i, b, e, u); /*макроподстановка f вместо for; i – управляющая переменная цикла; b и е – начальное и конечное значения управляющей переменной i; u – приращение управляющей переменной i*/

write(lst, “номер цикла – %d\n”, i); /*вывод значений управляющей переменной цикла*/

end /*макроподстановка*/

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

Демонстрационная программа

Введите значения:

b – начальное значение

e – конечное значение

u – приращение

1 7 2

Номер цикла – 1

Номер цикла – 3

Номер цикла – 5

Номер цикла – 7

/*Программа Р32. Демонстрация работы препроцессора 2*/

#include<stdio.h>

#define print FILE*fopen(), *lst; lst=fopen(“prn”, “w”) /*выполняется замена строки FILE*fopen(), *lst; lst=fopen(“prn”,”w”) на слово print*/

#define write fprintf /*выполняется замена слова fprintf на слово write*/

#define read3(v1, v2, v3) scanf(“%d%d”, &v1, &v2, &v3) /*замена scanf(“%d%d”, &v1, &v2, &v3) на строку read3(v1, v2, v3) */

#define f(a, b, e, u) for(a=b; a<=e; a+=u)

#define begin { /*замена открывающейся фигурной скобки на слово begin */

#define end }

main()

begin /*макроподстановка*/

int i, b, e, u;

print; /*макроподстановка*/

#ifdef write /*проверяется, определен ли идентификатор write*/

#undef write /*идентификатор write начинает считаться неопределенным*/

#endif /*конец команды ifdef условной трансляции*/

write(lst, “раз, два, три\n”); /*текст напечатан не будет*/

fprintf(lst, “\t ИЗМЕНЕННАЯ ПРОГРАММА\n”);

#ifndef write /*проверяется не определен ли идентификатор write*/

#define write fprintf /*реализуется соответствующая макроподстановка*/

#endif /*конец команды ifndef условной трансляции*/

printf(“\tВведите значения: \n\tb – начальное значение; \n\te – конечное значение; \n\tu – приращение. \n”);

read3(b, e, u); /*макроподстановка*/

f(i, b, e, u); /*макроподстановка f вместо for; i – управляющая переменная цикла; b и е – начальное и конечное значения управляющей переменной i; u – приращение управляющей переменной i*/

write(lst, “номер цикла – %d\n”, i); /*вывод значений управляющей переменной цикла*/

end /*макроподстановка*/

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

ИЗМЕНЕННАЯ ПРОГРАММА

Введите значения:

b – начальное значение

e – конечное значение

u – приращение

1 7 2

Номер цикла – 1

Номер цикла – 3

Номер цикла – 5

Номер цикла – 7

/*Программа 33. Демонстрация работы препроцессора 3*/

#include<stdio.h>

#define print FILE*fopen(), *lst; lst=fopen(“prn”, “w”) /*выполняется замена строки FILE*fopen(), *lst; lst=fopen(“prn”,”w”) на слово print*/

#define write fprintf /*выполняется замена слова fprintf на слово write*/

#define read3(v1, v2, v3) scanf(“%d%d”, &v1, &v2, &v3) /*замена scanf(“%d%d”, &v1, &v2, &v3) на строку read3(v1, v2, v3) */

#define f(a, b, e, u) for(a=b; a<=e; a+=u)

#define text(t) printf(“\tВведите значения:\n\tb – начальное значение;\n\te – конечное значение;\n\tu – приращение.\n”); read(b, e, u); f(i, b, e, u) write(lst, t) /*вместо строки, начинающейся с printf, используется строка text(t)*/

#define begin { /*замена открывающейся фигурной скобки на слово begin */

#define end }

main()

begin /*макроподстановка*/

int i, b, e, u;

print; /*макроподстановка*/

write(lst, “Демонстрационная программа\n”);

text(“город Москва\n”);

end /*макроподстановка*/

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

Демонстрационная программа

Введите значения:

b – начальное значение

e – конечное значение

u – приращение

1 3 1

Город Москва

Город Москва

Город Москва

4.МАССИВЫ И ОПЕРАЦИИ С АДРЕСАМИ

Указатели – это переменные, содержащие адреса других переменных. Унарная операция & дает адрес переменной, поэтому оператор y=&x; присваивает адрес х переменной у. Переменная у должна иметь целый тип (int или long). Операцию & можно применять только к переменным и элементам массива. Унарная операция * трактует свой операнд как адрес некоторого объекта и использует этот адрес для выборки содержимого, поэтому оператор z=*y; присваивает z значение переменной, записанной по адресу у. Если y=&x; z=*y;, то z=x.

Ссылки как и переменные необходимо объявлять, например, int *y;. Подобное объявление говорит, что комбинация *y имеет тип int.

Указатели могут встречаться и в выражениях. Например, если у – указатель на целое, то *у может появиться там же, где и соответствующая переменная.

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

Объявление int a[5] определяет массив из 5-ти элементов a[0], a[1], a[2], a[3], a[4]. Если *у объявлена как int *y;, то оператор y=&a[0] присваивает у адрес элемента a[0]. Если у указывает на очередной элемент а, то у+1 указывает на следующий элемент. Поскольку само имя массива есть адрес его нулевого элемента, то присваивание y=&a[0] можно записать в другом виде: у=а. Тогда a[i] можно записать как *(a+i). С другой стороны, если у – указатель, то следующие 2 записи: y[i] и *(y+i) – эквивалентны. Таким образом, любой массив и индексное выражение можно записать как указатель и смещение и наоборот.

Однако между именем массива и указателем есть одно различие. Указатель – это переменная, так как у=а или у++ – допустимые операции. Имя же массива – константа, поэтому конструкции вида а=у, а++, z=&a использовать нельзя. Если имя массива передается функции, то оно есть местоположение его начала. Внутри вызванной функции это имя определяет переменную, которую можно использовать как любую другую переменную (снимаются указанные выше ограничения).

Двумерный массив – это фактически одномерный массив, элементы которого тоже массивы. Так, char a[10][20]; – соответствующее объявление. Элементы 2-хмерного массива хранятся по строкам, т.е. чаще всего изменяется самый правый индекс. Обращение к 9-му элементу 5-й строки массива а запишется так: a[9][5]. Аналогичным образом определяются массивы большей размерности.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]