printf("Zifra? ");
scanf("%d",&A);
printf("Error %d\n",A).
Если число равно 9, то выполняется оператор printf("OK %d\n",A); и работа цикла заканчивается.
Главной особенностью оператора do... while является тот факт, что тело цикла, заключенное между операторами do и while выполняется хотя бы один раз, т.е. вначале выполняется тело цикла, а затем идет анализ условия.
Таким образом, смысл рассматриваемого оператора заключается в следующем: "Выполняй тело цикла до тех пор, пока истинно условие".
Оператор while... в отличие от do... while вначале анализирует условие, а затем выполняет тело цикла.
Пример.
#include <stdio.h>
main()
{
int A;
A = 0;
while (A != 9)
{
printf("Zifra? ");
scanf("%d",&A);
printf("Error %d\n",A);
}
printf("OK %d\n",A);
}
В данном примере инициализирована переменная A:=0;. Это сделано, потому что вначале идет анализ равна она 9 или нет. Если не равна, то выполняется тело цикла. Смысл рассматриваемого оператора заключается в следующем:
«Пока истинно условие выполняй тело цикла».
Оператор for... используется, когда известно сколько раз необходимо выполнить тело цикла, но этот оператор горазда гибче по сравнению с Паскалем. Рассмотримпример.
#include <stdio.h>
int A;
main()
{
for (A = 1; A <= 5; A++) /* A++ означает A=A-1 */
printf("Zifra %d\n",A);
}
В этом примере A хранит состояние счетчика цикла. Первоначально A:=1. Выполняется оператор printf("Zifra %d\n",A). Далее значение A увеличивается на единицу. Идет анализ A<=5 или нет. Если A больше 5, то цикл заканчивает работу. Если нет, то снова выполняется оператор printf("Zifra %d\n",A).
В следующем примере рассмотрим вариант оператора for..., когда начальное значение переменной больше конечного, а переменная во время работы цикла уменьшается на единицу.
#include <stdio.h>
int A;
main()
{
for (A = 5; A >= 1; A--) /* A-- означает A=A-1 */
printf("Zifra %d\n",A);
}
Существует множество модификаций оператора for..., например:
- пустой оператор - для временной задержки:
for (n=1;n <=10000;n++)
; /* пустой оператор */
- использование различного шага:
for (n=1;n <=230;n=n+10)
- изменение переменных:
for (x=2;n*n <=476;n=5*x++)
Рассмотрим пример, в котором инициализируются две переменные и каждая из которых, изменяется после итерации цикла:
#include <stdio.h>
#define f 30
#define n 19
main()
{
int y,t;
for (y = 1,t=f; y<=16; y++,t+=n) /*t+=n означает t=t+n*/ printf(" %3d %7d\n",y,t);
}
Далее рассмотрим, операторы ветвления (операторы перехода из одной части программы в другую).
Оператор goto позволяет передавать управление на любую строку программы. Для этой цели используется метка. Пример.
#include <iostream.h>
#include <stdio.h>
main()
{
char A;
label_1:/* метка */ printf("? \n");
cin>>A;
if (A != 'y') goto label_1; }
Для прерывания цикла по некоторому условию можно использовать оператор break. Пример.
#include <stdio.h>
#include <iostream.h>
char A;
int I;
main()
{
for (I = 1; I <= 10; I++)
{
printf("? \n");
cin >>A;
i (A == 'y') break;
}
}
Для прерывания итерации цикла и перехода к следующей итерации используется оператор Continue. Пример.
#include <stdio.h>
#include <iostream.h>
char A;
int I;
main()
{
for (I = 1; I <= 10; I++)
{
printf("? \n");
cin >>A;
if (A == 'y') continue;
printf("Работает %c\n",A);
}
}
Для прерывания программы также используются операторы return() и exit().
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.Для связи независимых структур друг с другом.
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.