А. Богатырев - Руководство полного идиота по программированию (на языке Си), страница 5
Описание файла
PDF-файл из архива "А. Богатырев - Руководство полного идиота по программированию (на языке Си)", который расположен в категории "". Всё это находится в предмете "информатика" из 1 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр PDF-файла онлайн
Текст 5 страницы из PDF
Руководство полного идиота<br> по программированию (на языке Си)Вычисленные значения этих выражений соответственно будут присвоены1-ому, 2-ому и 3-ему аргументам (параметрам) из определения функции:int func(a, b, c){/* a = номер 1, b = 2, c = 3 */Первый параметр:a = 33;Второй параметр:b = 77;Третий параметр:c = var + 3;то есть, вычисляя,c = 20;Локальные переменные x и y содержат неопределенные значения,то есть мусор (мы не можем предсказать их значения,пока не присвоим им явным образом какое-либо значение сами).2) Выполняется ТЕЛО функции, то есть вычисления, записанные внутри { ... }в определении функции. Например:x = a + 7;И параметры, и локальные переменные - это ПЕРЕМЕННЫЕ,то есть их можно изменять.b = b + 4;При этом никакие переменные ВНЕ этой функции не изменяются.(Об этом еще раз позже).3) Производится ВОЗВРАТ из функции....return(некое_значение);}Например, это может быть...return(a + 2 * x);}Рассмотрим, что при этом происходит в точке вызова:zz = func(33, 77, var + 3) + 44;(1) Вычеркиваем func(.....)zz = XXXXXXX + 44;(2) Вычисляем значение "некое_значение" в операторе return,и берем КОПИЮ этого значения.Пусть при вычислении там получилось 128.file:///Volumes/WININSTALL/assets/materials_informatiks.html31/6803.06.2015Андрей Богатырев.
Руководство полного идиота<br> по программированию (на языке Си)(3) Подставляем это значение на место вычеркнутого func(.....)У нас получаетсяzz = 128 + 44;(4) АВТОМАТИЧЕСКИ УНИЧТОЖАЮТСЯ локальные переменные и аргументы функции:abcxy- убито- убито- убито- убито- убитоТаких переменных (и их значений) больше нет в природе.(5) Пункт, который мы обсудим позже.(6) Продолжаем вычисление:zz = 128 + 44;Вычисляется вzz = 172;/* оператор присваивания */------------------------------------------------------------------------int func1(int x){printf("func1: x=%d\n", x);x = 77;printf("func1: x=%d\n", x);return x;}/* 1 *//* 2 */void main(){int var, y;var = 111;y = func1(var);/* @ */printf("main: var=%d\n", var); /* 3 */}В данном случае в точке @ мы передаем в функцию func1()ЗНАЧЕНИЕ переменной var, равное 111.Это значит, что при вызове функции будет создана переменная xи ей будет присвоено начальное значение 111x = 111;Поэтому первый оператор printf() напечатает 111.Затем мы изменяем значение переменной x на 77.Мы меняем переменную x, но не переменную var !!!Использовав ЗНАЧЕНИЕ (его копию) из переменной var для x,мы о переменной var забыли - она нас не касается (а мы - ее).Поэтому второй оператор printf() напечатает 77.В переменной же var осталось значение 111,что и подтвердит нам третий оператор printf,который напечатает 111.------------------------------------------------------------------------file:///Volumes/WININSTALL/assets/materials_informatiks.html32/6803.06.2015Андрей Богатырев.
Руководство полного идиота<br> по программированию (на языке Си)ВРЕМЕННОЕ СОКРЫТИЕ ПЕРЕМЕННЫХ=============================int func1(int x){printf("func1: x=%d\n", x);x = 77;printf("func1: x=%d\n", x);return x;}void main(){int x, y;/* f.1 *//* f.2 *//* f.3 *//* f.4 *//* f.5 *//* 1 */x = 111;y = func1(x);/* 2 *//* 3 */printf("main: x=%d y=%d\n", x, y); /* 4 */}А теперь мы и переменную внутри main(), и аргумент функцииfunc1() назвали одним и тем же именем.
Что будет?Будет то же самое, что в предыдущем примере.В момент вызова функции func1() будет создана НОВАЯ переменнаяс именем x, а старая (прежняя) переменная и ее значение будутВРЕМЕННО СПРЯТАНЫ (скрыты).Можно было бы уточнить эти переменные именами функций,в которых они определены:main::xиfunc1::x(но это уже конструкции из языка Си++, а не Си).Выполним программу по операторам:|/* 1*/|/* 2*/|/* 3*/|+-------+.|/* f.1.|/* f.2.|.|/* f.3.|.|.|.|.|.|.|/* f.4.|/* f.5.|.|.|.|.|Отводятся переменные main::x и main::y для целых чисел;main::x = 111;Вызывается func1(111);*/*/Отводится переменная func1::x со значением 111;Печатается 111 из переменной func1::x;*/func1::x = 77; (это не main::x, а другая переменная,ЛОКАЛЬНАЯ для функции func1.Переменную main::x мы сейчас не видим она "заслонена" именем нашей локальнойпеременной.Поэтому мы не можем ее изменить).*/*/Печатает 77 из func1::x;Возвращает значение func1::x , то есть 77.Переменная func1::x уничтожается.Теперь мы снова возвращаемся в функцию main(),где имя x обозначает переменную main::xа не func1::xfile:///Volumes/WININSTALL/assets/materials_informatiks.html33/6803.06.2015Андрей Богатырев.
Руководство полного идиота<br> по программированию (на языке Си)+-------+||/* 3*/|/* 4*/|y = 77;Печатает значения main::x и main::y, то есть111 и 77.Этот механизм сокрытия имен позволяет писать функции main() и func1()разным программистам, позволяя им НЕ ЗАБОТИТЬСЯ о том, чтобы именалокальных переменных в функциях НЕ СОВПАДАЛИ. Пусть совпадают - хуже небудет, механизм упрятывания имен разрешит конфликт.Зато программист может использовать любое понравившееся ему имяв любой функции - хотя бы и x, или i.------------------------------------------------------------------------То же самое происходит с локальными переменными,а не с аргументами функции.int func1(int arg){int x;/* локальная переменная-параметр func1::arg *//* локальная переменнаяfunc1::x */x = arg;printf("func1: x=%d\n", x);x = 77;printf("func1: x=%d\n", x);return x;}void main(){int x, y;/* переменные main::x и main::y */x = 111;y = func1(x);printf("main: x=%d y=%d\n", x, y);}Действует тот же самый механизм временного сокрытия имени x.Вообще же, аргументы функции и ее локальные переменныеотличаются только одним:аргументам автоматически присваиваютсяначальные значения, равные значениям соответствующих выраженийв спискеимя_функции(..., ..., ....)арг1 арг2 арг3в месте вызова функции.То естьОПИСАНИЕ ФУНКЦИИ:int f(int арг1, int арг2, int арг3){int перем1, перем2;.../* продолжение */}ВЫЗОВ:....
f(выражение1, выражение2, выражение3) ...file:///Volumes/WININSTALL/assets/materials_informatiks.html34/6803.06.2015Андрей Богатырев. Руководство полного идиота<br> по программированию (на языке Си)ТО В ТЕЛЕ ФУНКЦИИ ВЫПОЛНИТСЯ (в момент ее вызова):арг1 = выражение1;арг2 = выражение2;арг3 = выражение3;перем1 = МУСОР;перем2 = МУСОР;.../* продолжение */------------------------------------------------------------------------ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ=====================Наконец, существуют переменные, которые объявляются ВНЕ ВСЕХ ФУНКЦИЙ,и существующие все время выполнения программы(а не только то время, когда активна функция, в которой они созданы).Локальные переменные и аргументы УНИЧТОЖАЮТСЯ при выходеиз функции. Глобальные переменные - нет.int x = 12;int globvar;/* ::x - ей можно заранее присвоить константу *//* ::globvar*/int f1(){int x;/* f1::x */x = 77;printf("x=%d\n", x);return x;/* 4 */}int f2(){printf("x=%d\n", x);return 0;}void main(){int x, y;/* 5 *//* main::x */x = 111;printf("x=%d\n", x);printf("glob=%d\n", globvar);/* 1 *//* 2 *//* 3 */y = f1();y = f2();}В данном примере мы видим:- во-первых мы видим ФУНКЦИИ БЕЗ ПАРАМЕТРОВ.
Это нормальная ситуация.- во-вторых тут используются ТРИ переменные с именем "x".Как выполняется программа?/* 1 */main::x = 111;Это локальный x, а не глобальный.Глобальный x попрежнему содержит 12./* 2 */Напечатает значение переменной main::x, то есть 111.Внутри функции main глобальная переменная ::xзаслонена своей собственной переменной x.В данном случае НЕТ СПОСОБА добраться из main к глобальнойfile:///Volumes/WININSTALL/assets/materials_informatiks.html35/6803.06.2015Андрей Богатырев. Руководство полного идиота<br> по программированию (на языке Си)переменной x, это возможно только в языке Си++ по имени ::xК переменной же globvar у нас доступ есть./* 3 */Печатает ::globvar. Мы обнаруживаем, что ее значение 0.В отличие от локальных переменных,которые изначально содержат МУСОР,глобальные переменные изначально содержат значение 0.В рамочку, подчеркнуть./* 4 */При вызове f1()переменная f1::xзаслоняет собой какmain::xтак и::xВ данном случае напечатается 77,но ни ::x ни main::x не будут изменены оператором x = 77.Это изменялась f1::x/* 5 */При вызове f2() история интереснее.Тут нет своей собственной переменной x.Но какая переменная печатается тут ::xилиmain::x ?Ответ: ::xто есть 12.Переменные названы локальными еще и потому,что они НЕВИДИМЫ В ВЫЗЫВАЕМЫХ ФУНКЦИЯХ.Это ОПРЕДЕЛЕНИЕ локальных переменных.(Поэтому не спрашивайте "почему?" По определению)То есть, если мы имеемfunca(){int vara;......funcb();...
/* вызов */...}то из функции funcb() мы НЕ ИМЕЕМ ДОСТУПА К ПЕРЕМЕННОЙ vara.funcb(){int z;z = vara + 1;/* ошибка,vara неизвестна внутри funcb() */}Если, в свою очередь, funcb() вызывает funcc(),то и из funcc() переменная vara невидима.Остановитесь и осознайте.Это правило служит все той же цели - разные функциимогут быть написаны разными программистами, которые могутиспользовать одни и те же имена для РАЗНЫХ переменных,file:///Volumes/WININSTALL/assets/materials_informatiks.html36/6803.06.2015Андрей Богатырев.
Руководство полного идиота<br> по программированию (на языке Си)не боясь их взаимопересечения.Множества имен, использованных в разных функциях, независимыдруг от друга. Имена из одной функции НИКАК не относятсяк переменным с теми же именами ИЗ ДРУГОЙ функции.Вернемся к параграфу КАК ПРОИСХОДИТ ВЫЗОВ ФУНКЦИИи рассмотрим пункт (a). Теперь он может быть описан как(a) Локальные переменные и аргументы вызывающей функции делаются невидимыми.~~~~~~~~~~А при возврате из функции:(5) Локальные переменные и аргументы вызывающей функции снова делаются видимыми.ОДНАКО глобальные переменные видимы из ЛЮБОЙ функции,исключая случай, когда глобальная переменная заслоненаодноименной локальной переменной данной функции.------------------------------------------------------------------------ПРОЦЕДУРЫ=========Бывают функции, которые не возвращают никакого значения.Такие функции обозначаются void ("пустышка").Такие функции называют еще ПРОЦЕДУРАМИ.void func(){printf("Приветик!\n");return; /* вернуться в вызывающую функцию */}Такие функции вызываются ради "побочных эффектов",например печати строчки на экран или изменения глобальных (и только)переменных.int glob;void func(int a){glob += a;}Оператор return тут необязателен, он автоматически выполняетсяперед последней скобкой }Вызов таких функций не может быть использованв операторе присваивания:main(){int z;z = func(7);/* ошибка, а что мы присваиваем ??? */}Корректный вызов таков:main(){func(7);}Просто вызов и все.ЗАЧЕМ ФУНКЦИИ?file:///Volumes/WININSTALL/assets/materials_informatiks.html37/6803.06.2015Андрей Богатырев.