Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Структура программы на языке Си

Каждая программа на языке Си – это последовательность препроцессорных директив, описаний и определений глобальных объектов и функций. Препроцессорные директивы управляют преобразованием текста программы до ее компиляции. Определения вводят функции и объекты. Объекты необходимы для представления обрабатываемых данных. Функции определяют потенциально возможные действия программы. Описания уведомляют компилятор о свойствах и именах тех объектов и функций, которые определены в других частях программы.

Структуру программы на языке Си можно определить следующим образом:

директивы_препроцессора

int main (void)

{

определения_объектов;

исполняемые_операторы;

}

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

1. препроцессорная директива обычно размещается в одной строке.

2. все директивы начинаются с символа #.

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

После выполнения обработки в тексте программы не остается ни одной препроцессорной директивы. Теперь программа представляет собой набор описаний и определений.

В программе всегда должна присутствовать функция с именем main. Именно эта функция является главной функцией программы, без которой программа не может быть выполнена. Имя этой функции для всех программ одинаково и не может выбираться произвольно.

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

 

Пример:

Вычислить объем цилиндра высотой h и радиусом r.

#include<stdio.h>

#include<conio.h>

int main(void)

{

int r, h; float v, pi = 3.14159;

clrscr();

printf(“Enter r = ”);

scanf(“%d”, &r);

printf(“Enter h = ”);

scanf(“%d”, &h);

if(h>0 && r>0)

{

v = pi*h*r*r;

printf(“ V = %f”, v);

}

else

printf(“Error!!! ”);

getch();

return 0;

}

 

Лекция № 6

 

Написал Дмитрий
25.11.2008
Условный оператор if Основные операторы языка Си можно условно разделить на 3 группы: 1. операторы выбора; 2. операторы циклов; 3. операторы переходов. Условный оператор if, относящий к операторам выбора, имеет 3 формы. Первая форма – сокращенная: if(выражение_условие) операторы_дествия; Рисунок 8. Блок схема сокращенной формы условного оператора   где в качестве выражения_условия могут использоваться арифметические выражения, отношения и логические выражения. Действие выполняется только в случае истинности (т.е. при ненулевом значении) выражения_условия.   Пример: if(x < 0) y = -x;   Кроме сокращенной формы, существует полная форма условного оператора if: if(выражение_условие) операторы_действия_1; else операторы_действия_2;   Рисунок 9. Блок схема полной формы условного оператора   Здесь в случае истинности выражения_условия выполняется только действие_1 или блок действий_1, при нулевом значении выражения_условия выполняется только действие_2.   Пример: if(x > 0) y = x; else y = -x;   Часто встречается необходимость использовать конструкцию if-else-if или вложенный условный оператор: if(выражение_условие_1) операторы_действия_1; else if(выражение_условие_2) операторы_действия_2; … else операторы_действия;   Рисунок 10. Блок схема вложенной формы условного оператора   В этой форме выражения_условия операторов if проверяются сверху вниз. Как только какое-либо из условий принимает значение «истинно», выполняется действие, следующий за этим условным оператором, а вся остальная часть конструкции будет проигнорирована.   Пример: if(x > 0) y = x; else if(x < 0) y = -x; else y = 0;   Не стоит забывать о некорректной записи вложенных связок с участием условного оператора:   if (x > 0) z = y / x; if (y < 0) z = x + y; else z = x - y;   В такой форме непонятно, к какому из операторов if относится else. В языке Си оператор elseассоциируется с ближайшим if в соответствующем блоке. В последнем примере else относится к if (y<0).   Таблица 8 Примеры с использованием условного оператора  
Пример 1 [программа pr_4] Пример 2 [программа pr_5]
#include <stdio.h> #include <conio.h> #include <math.h>   int main(void) { float x, y, z; clrscr(); printf(" x = "); scanf("%f", &x); printf(" y = "); scanf("%f", &y); if(x!=2 && (x+y)/(2-x)>=0 && (x-y)>0) { z = sqrt((x+y)/(2-x))*sin(y) - log(x-y); printf(" z = %.2f", z); } else printf("Error!"); getch(); return 0; } #include <stdio.h> #include <conio.h>   int main(void) { int x, y; clrscr(); printf(" x = "); scanf("%d", &x); if(x) y = 1; else y = 0; printf("y = %d", y); if(!x) y = 1; else y = 0; printf(" y = %d", y); getch(); return 0; }

 

Оператор множественного выбора switch

Основным средством для организации мультиветвления служит оператор- переключатель switch. Основная форма оператора:

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

{

case константа_1:

действия_1;

break;

case константа_2:

действия_2;

break;

case константа_N:

действия_N;

break;

default:

действия;

}

Сначала вычисляется выражение в скобках за ключевым словом switch. Затем просматривается список меток (case константа_1 и так далее) до тех пор, пока не находится метка, соответствующая значению вычисленного выражения. Далее происходит выполнение соответствующей последовательности действий, следующих за двоеточием. Если же значение выражения не соответствует ни одной из меток оператора switch, то выполняется последовательность действий, следующая за ключевым словом default. Допускается конструкция switch, когда слово default и соответствующая последовательность конструкция операторов может отсутствовать.

Когда в последовательности операторов встречается ключевое слово break, то выполнение оператораbreak приводит к выходу из оператора switch и переходу к следующему оператору программы. Наличие оператора break необязательно.

 

Пример [программа pr_6, pr_7]:

#include <stdio.h> #include <conio.h>   int main(void) { int x; float y; clrscr(); printf("x = "); scanf("%d", &x); switch(x) { case 4: y = 1.0/(x-2); break; case 8: y = x*2.0; break; default: y = x/2.0; } printf(" y = %.2f ", y); getch(); return 0; } Рисунок 11. Блок схема оператора выбора switch

 

 

Лекция № 7

 

Написал Дмитрий
25.11.2008
Циклы Циклы необходимы, когда нам надо проверить некоторые действия несколько раз, как правило, пока выполняется некоторое условие. В языке Си известно три оператора цикла: for(параметрический), while(с предусловием) и do-while(с постусловием). Основная форма цикла for имеет следующий вид: for(выражение_1; выражение_2; выражение_3) операторы_действия; или for(инициализация; проверка условия; шаг цикла) операторы_действия; Рисунок 12. Блок схема цикла for   В простейшем форме инициализация или выражение_1 используется для присвоения начального значения параметру цикла. Проверка условия или выражение_2 – обычно условное или арифметическое выражение, которое определяет, когда цикл должен быть завершен. Изменение-шаг или выражение_3 обычно используется для изменения параметра цикла каждый раз при повторении цикла. Эти три раздела заголовка цикла должны быть разделены точкой с запятой. Выполнение цикла происходит до тех пор, пока условное выражение истинно. Как только условие становится ложным, начинает выполняться следующий за циклом for оператор. Любое из трех выражений в операторе for могут отсутствовать, но разделяющие их символы «; - точка с запятой» должны присутствовать всегда. Если отсутствует выражение_2, то считается, что оно истинно и нужны специальные средства для выхода из цикла.   Пример [программа pr_8, pr_9]: Вариант 1 printf(“x y ”); for(x=0; x<11; x++) { y = x*x; printf(“%d %d ”, x, y); } Вариант 2 printf(“x y ”); for(x=0; x<11; x++) printf(“%d %d ”, x, x*x); Вариант 3 printf(“x y ”); for(x=0; x<11; printf(“%d %d ”, x, x*x), x++);   Следующий оператор цикла в языке Си – это цикл while. Основная форма имеет следующий вид: while(выражение_условие) операторы_действия; Рисунок 13. Блок схема цикла while   Где оператор может быть простым, составным или пустым оператором. Выражение_условие, как и во всех других операторах, является просто выражением. Цикл выполняется до тех пор, пока условие принимает значение истинно. Когда же условие примет значение ложно, программа передаст управление следующему оператору программы. Так же как и в цикле for в цикле while сначала проверяется условие, а затем выполняется действие. Таким образом, для заведомо ложного выражения_условия тело цикла не выполнится ни разу. Это называется цикл с предусловием.   Пример: printf(“x y ”); x = 0; while(x<11) { y = x*x; printf(“%d %d ”, x, y); x++; }   В цикле do-while условие проверяется в конце оператора цикла. Основная форма оператора do-whileследующая: do { операторы_действия; }while(выражение_условие); Рисунок 14. Блок схема цикла do-while   В цикле do-while тело цикла всегда выполняется по крайне мере один раз. В конце цикла всегда должен стоять разделитель «; - точка с запятой».   Пример: printf(“x y ”); x = 0; do { y = x*x; printf(“%d %d ”, x, y); x++; }while(x<11);   Фигурные скобки необязательны, если внутри них находится один оператор. Тем не менее они чаще ставятся для лучшей читаемости программы. Оператор do-while называется оператором цикла с постусловием. Какое бы условие ни стояло в конце оператора, набор операторов в фигурных скобках один (первый) раз выполнится обязательно. В циклах for и while оператор может не выполняться ни разу.   Пример: Требуется угадать число из промежутка от 0 до 100, загаданное генератором случайных чисел   #include<stdio.h> #include<conio.h> #include<stdlib.h> #include<time.h>   int main(void) { int s, x; int n = 0; randomize(); clrscr(); s = random(100)+1; do { printf(“Введите число от 1 до 100”); scanf(“%d”, &x); n++; if (s < x) printf(“Загаданное число меньше ”); if (s > x) printf(“Загаданное число больше ”); } while(s - x); //или while (s!= x); printf(“Вы угадали число! ”); printf(“Затратили на угадывание %d попыток ”, n); getch(); return 0; }   Когда один цикл находится внутри другого, то говорят, что это вложенные циклы. Часто встречаются вложенные циклы, например, при заполнении таблиц или работе с массивами.   Пример: a = 0; for(i = 0; i < 10; i ++) for(j = 0; j < 10|; j++) a++;   Оператор break имеет два применения. Первое – окончание case в операторе switch. Второе – немедленное окончание цикла. Когда оператор break встречается внутри оператора цикла, то происходит немедленный выход из цикла и переход к выполнению оператора, следующего за оператором цикла.   Пример: for(i = 1;; i++) { printf(“Квадрат %d равен %d ”, i, i*i); if (i*i >= 16) break; }   Еще один полезный оператор – оператор continue. Если оператор continue встретился в операторе цикла, то он передает управление на начало следующей итерации цикла. В циклах while и do-while – на проверку условий, а цикле for – на приращение. Этот оператор необходим, если вы хотите закончить текущую итерацию цикла и не выполнять оставшиеся операторы, а сразу перейти к следующей итерации цикла.   Пример: for(i = 1; i <20; i++) { if (i == 14) continue; printf(“%d”, i); }     Рекуррентная формула Достаточно часто при программировании циклов встречаются задачи, для которых не определено количество итераций, но на условие выхода из цикла наложено некоторое условие, по которому и осуществляется завершение цикла. Использование таких циклов часто применяется при решении задач, которые вычисляются по некоторой рекуррентной формуле. Формулы:   Пример [программа pr_10]: #include <math.h> #include <stdio.h> #include <conio.h>   int main(void) { int n; float x, s, f; do { clrscr(); printf("x = "); scanf("%f", &x); } while(x>1 || x<-1);   /* Вариант 1*/ for(n=1, s=1, f=0; fabs(s)>=1E-5;f+=(s*=-x/n), n++);   /* Вариант 2*/ for(n=1, s=1, f=0; fabs(s)>=1E-5;n++) f+=(s*=-x/n);   /* Вариант 3*/ for(n=1, s=1, f=0; fabs(s)>=1E-5;n++) { s*=-x/n; f+=s; }   printf(" f = %f ", f); getch(); return 0; }

 

 

Лекция № 8

 

Написал Lekka
14.11.2008
Указатели В языке Си, кроме базовых типов, разрешено вводить и использовать производные типы, каждый из которых получен на основе более простых типов. Стандарт языка определяет три способа получения производных типов: 1. указатель на объект заданного типа; 2. массив элементов заданного типа; 3. функция, возвращающая значение заданного типа. Указатель – это объект, значением которого является адрес других объектов: переменных, массивов, функций. Описание указателя имеет следующий вид: тип *имя_указателя; Переменная в программе – это объект, имеющий имя и значение. По имени можно обратиться к переменной и получить ее значение. С точки зрения машинной реализации имя переменной соответствует адресу того участка памяти, который для нее выделен, а значение переменной – содержимому этого участка памяти. Соотношение между именем и адресом условно показано на рисунке 15. Рисунок 15. Соотношение между именем и адресом Чтобы получить адрес переменной в явном виде, в языке Си применяют унарную операцию &. Выражение &X позволяет получить адрес участка памяти, выделенного на машинном уровне для переменной Х. Операция & применима только к объектам, имеющим имя и размещение в памяти. Ее нельзя применять к выражениям, константам, регистровым переменным или внешним объектам. На рисунке 16 хорошо проиллюстрирована связь между именами, адресами и значениями переменных. Будем предполагать, что в программе используется следующая последовательность определений с инициализацией.   Пример: char ch = ‘A’; int date = 2008; float summa = 2.015E-5;   В соответствии с приведенным рисунком переменные размещены в памяти, начиная с байта, имеющего шестнадцатеричный адрес 1А2В. Целые переменные занимаю по 2 байта, вещественные с плавающей точкой – 4 байта, символьные – 1 байт. Адреса имеют целочисленные беззнаковый значения и их можно обрабатывать как целые величины. Имея возможность с помощью операции & определять адрес переменной или другого объекта программы, нужно уметь его сохранять, преобразовывать и передавать. Для этого и предназначен указатель, который может, как хранить адрес некоторого объекта, так и неравное никакому адресу значение, принимаемое за нулевой адрес. Для его обозначения определена специальная константа NULL. Рисунок 16. Разные типы данных в памяти компьютера В определениях и описаниях указателей применяется разделитель *, который является в этом случае знаком унарной операции косвенной адресации. Иначе называемой операцией разыменования или операцией раскрытия ссылки или обращения по адресу. Операндом операции разыменования всегда является указатель. Результат этой операции – тот объект, который адресует указатель операнд.   Пример [программа pr_11]: int X, Y, Z, *p; // определения переменных и указателя p = &Z; // указателю p присвоить адрес переменной Z X = 2, Y = 3; *p = X+Y; // записать значение выражения X+Y в участок памяти, на который ссылается указатель p Операции над указателями В языке Си допустимы следующие основные операции над указателями: 1. присваивание.   Пример: int x, *p, *pp; p = &x; pp = NULL; pp = p;   2. получение значения того объекта, на который ссылается указатель:   Пример: int x = 2, y, *p; p = &x; y = *p; printf(“y = %d *p = %d ”, y, *p);   3. получение адреса самого указателя:   Пример: int x, *p; p = &x; printf(“p = %p &p = %p ”, p, &p);   4. унарные операции изменения значения указателя:   Пример: int x, *p; p = &x; p++; // при изменении указателя на 1, он «переходит к началу» // следующего поля той длины, которая определяется типом.   5. арифметические операции:   Пример: int x, *p; p = &x; *p = *p+3;   6. операции сравнения:   Пример: int x = 2, *p; p = &x; if(p!=NULL) *p = 10;   7. логические операции:   Пример: int x = 2, *p, *pp = NULL; p = &x; if(!pp && p) *pp = *p;   Правила работы с указателями Так как указатель является специальным объектом, работающим напрямую с ячейкой памяти и косвенно с ее значением, то на работу с указателем накладывается ряд ограничений: 1. Указатель может ссылаться на объекты того типа, который присутствует в определении самого указателя. Исключением являются указатели типа void (отсутствие значения). Такие указатели могут ссылаться на объекты любого типа, однако к ним нельзя применять операцию разыменования (то есть операцию *). 2. Арифметические операции применимы только к значениям объектов, на которые ссылаются указатели. Два указателя нельзя суммировать, вычитать, умножать, делить и т.д. 3. При изменении значения указателя с помощью операций инкремент или декремент, требуется точно знать, на какую область памяти будет ссылаться указатель после изменения своего значения. Эти операции работают корректно только при обработке массивов. 4. Сравнивать указатели можно только с другими указателями того же типа или с константой NULL. 5. Размер ячейки памяти, которая выделяется под указатель при его определении, в зависимости от версии компилятора равна 2 (в большинстве случаев) или 4 байтам.   Указатель на указатель Из выше сказанного следует, что указатели чаще всего применяются при работе с массивами. В языке Си возможна ситуация, когда указатель указывает на указатель. В этом случае описание будет иметь следующий вид: тип **имя_указателя_на_указатель; Объект pp имеет тип указатель на указатель на объект типа int. Соответственно, чтобы получить целочисленное значение переменной, на которую указывает pp, надо в выражении использовать **pp. На рисунке 17 демонстрируется механизм работы указателя и указателя на указатель.   Пример: #include <stdio.h> #include <conio.h> int main() { int i, *p, **pp; i = 7; p = &i; pp = &p; clrscr(); printf(“i = %d p = %p pp = %p ”, i, p, pp); *p++; printf(“i = %d p = %p pp = %p ”, i, p, pp); **pp = 12; printf(“i = %d p = %p pp = %p ”, i, p, pp); getch(); return 0; } Рисунок 17. Механизм работы указателя и указателя на указатель После того как указатель был объявлен, но до того, как ему было присвоено значение, указатель содержит неизвестное значение. Работа с таким указателем опасна, если в программе появилась предупреждение-ошибка “Null pointer assignment”, ищите использованный, но неинициализированный указатель.

 

 

Лекция № 9

 

Написал Lekka
07.11.2008
Массивы Массив – это набор данных, объединенных общим типом и именем и различающихся порядковым номером (индексом). Математическим понятием массива является матрица и ее частные случаи: вектор-столбец и вектор-строка. Общий вид определения массива: тип имя_массива [ количество_элементов ];   Пример: int a[5]; // массив с именем array из 5 целых элементов int b[2][3]; // массив с именем b из 6 элементов   В соответствии с синтаксисом языка Си существуют только одномерные массивы, однако элементы одномерного массива могут, в свою очередь, быть массивами (рисунки 18 - 19).   Пример [программа pr_12]: #include <stdio.h> #include <conio.h> main() { int a[5], b[2][3], i, j; clrscr(); printf(" Array: "); for(i=0; i<5; i++) printf("&a[%d] = %p ", i, &a[i]); printf(" Matrix: "); for(i=0; i<2; i++) { for(j=0; j<3; j++) printf("&b[%d][%d] = %p ", i, j, &b[i][j]); printf(" "); } printf(" Press any key... "); getch(); return 0; }   Рисунок 18. Результат выполнения программы   a. Представление одномерного массива в памяти компьютера б. Представление двумерного массива в памяти компьютера   Рисунок 19. Представление массивов в памяти компьютера   Ограничений на размерность массивов, то есть на число индексов, теоретически нет. Количество элементов всегда целое число. Однако стандарт языка Си требует, чтобы размерность не превышала диапазона, предусмотренного целым типом, и размером оперативной памяти, с которой работает программа.   Инициализация массивов Существует огромное количество способов инициализации массивов, следующих видов: 1. При определении массивов возможна их инициализация, то есть присваивание начальных значений их элементам с указанием количества элементов массива.   Пример: int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; float m1[2][2] = {0.1, 0.2, 0.3, 0.4}; float m2[2][2] = {{0.1, 0.2}, {0.3, 0.4}};   2. При определении массивов возможна их инициализация, то есть присваивание начальных значений их элементам без указания количества элементов массива. В данном случае компилятор вычисляет длину массива по количеству начальных значений, перечисленных в скобках.   Пример: int array[] = {1, 2, 3, 4, 5}; // массив длиной 5 элементов float m[][2] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6}; // матрица размерностью 3х2   3. Ввод начальных значений с помощью присваивания.   Пример: int array[5]; float m[2][2]; array[0] = 1, array[1] = 1, array[2] = 1, array[3] = 1, array[4] = 1; m[0][0] =0.1, m[0][1] =0.2, m[1][0] =0.3, m[1][1] =0.4;   4. Ввод начальных значений с клавиатуры без помощи цикла.   Пример: int array[5]; float m[2][2]; scanf(“%d%d%d%d%d”, &array[0], &array[1], &array[2], &array[3], &array[4]); scanf(“%f%f%f%f”, &m[0][0], &m[0][1], &m[1][0], &m[1][1]);   5. Ввод начальных значений с клавиатуры с помощью цикла.   Пример: int array[5], i, j; float m[2][2]; for(i=0; i<5; i++) scanf(“%d”, &array[i]);   for(i=0; i<2; i++) for(j=0; j<2; j++) scanf(“%f”, &m[i][j]);   6. Ввод начальных значений с помощью генератора случайных чисел (через цикл);   Пример: int array[5], i, j; float m[2][2]; randomize(); for(i=0; i<5; i++) array[i] = -10 + random(21); for(i=0; i<2; i++) for(j=0; j<2; j++) m[i][j] = -10.0 + random(201)/10.0;   7. Ввод начальных значений с помощью указателя (через цикл)   Примеры [программа pr_13, pr_14, pr_15]]:
Для одномерного массива Для двумерного массива
int array[5], i, *p;   for(p=&array[0]; p<=&array[4]; p++) scanf(“%d”, p);   for(i=0; i<5; i++) scanf(“%d”, array+i);     for(i=0; i<5; i++) *(array+i) = -10 + random(21); float m[2][2], *p; int i, j;   for(p=&m[0][0]; p<=&array[1][1]; p++) scanf(“%f”, p);   for(i=0; i<2; i++) for(j=0;j<2;j++) scanf(“%f”, m[i]+i);   for(i=0; i<2; i++) for(j=0;j<2;j++) *(m[i]+j) = -10 + random(21);

 

<== предыдущая лекция | следующая лекция ==>
Выражения. Функция форматированного ввода | Сортировки массивов
Поделиться с друзьями:


Дата добавления: 2014-01-20; Просмотров: 2176; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.022 сек.