Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Demon's Souls |#15| Dragon God
Demon's Souls |#14| Flamelurker
Demon's Souls |#13| Storm King
Demon's Souls |#12| Old Monk & Old Hero

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Богатырев А. Весь текст 120.46 Kb

Руководство полного идиота по программированию на C

Предыдущая страница Следующая страница
1 2 3 4  5 6 7 8 9 10 11

(2)     Хранить текущую длину в элементе str[0],
        а буквы - в str[1] ... итд.
        Плохо тем, что в str[0] можно хранить лишь числа от 0 до 255,
        и если строка длиннее - то такой подход неприменим.

(3)     Не хранить длину НИГДЕ, а ввести символ-признак конца строки.
        Теперь в

        func(str);      /* ОДИН аргумент - сам массив */

        передается только сам массив, а его текущая длина может быть
        при нужде вычислена при помощи некоей функции, вроде такой:

int strlen(char s[]){                   /* функция от массива букв            */
        int counter = 0;                /* счетчик и одновременно индекс      */

        while(s[counter] != '\0')       /* пока не встретился признак конца текста */
                counter++;              /* посчитать символ                   */
        return counter;                 /* сколько символов, отличных от '\0' */
}

        Тут никаких ограничений нет. Именно этот подход и был избран
        в языке Си, хотя в принципе можно самому пользоваться и другими.
        На самом деле в языке есть такая СТАНДАРТНАЯ функция strlen(s)
        (вам не надо писать ее самому, ее уже написали за вас).
---------------------------------------------------------------------------

ИНИЦИАЛИЗАЦИЯ ГЛОБАЛЬНОГО МАССИВА
=================================
Массив, заданный вне каких-либо функций, можно проинициализировать
константными начальными значениями:

int array[5]   = { 12, 23, 34, 45, 56 };

char string[7] = { 'П', 'р', 'и', 'в', 'е', 'т', '\0' };

Если размер массива указан БОЛЬШЕ, чем мы перечислим элементов,
то остальные элементы заполнятся нулями (для int) или '\0' для char.

int array[5] = { 12, 23, 34 };

Если мы перечислим больше элементов, чем позволяет размер массива -
это будет ошибкой.

int a[5] = { 177, 255, 133 };

Операция индексации массива a[] дает:

при n           значение выражения a[n] есть
---------------------------------------------------------------------------

-1              не определено (ошибка: "индекс за границей массива")
0               177
1               255
2               133
3               0
4               0
5               не определено (ошибка)
      * 13_FUNCS.txt *

КАК ПРОИСХОДИТ ВЫЗОВ ФУНКЦИИ
============================

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

        /* ОПРЕДЕЛЕНИЕ ФУНКЦИИ func(). */
        /* Где func - ее имя. Назвать мы ее можем как нам угодно. */

        int func(int a, int b, int c){
                int x, y;

                ...
                x = a + 7;
                ...
                b = b + 4;
                ...

                return(некое_значение);
        }

Здесь
        a, b, c    - аргументы функции (параметры)
        x, y       - локальные переменные

Точка вызова - находится внутри какой-то другой
функции, например функции main()

main(){

        int zz, var;
        ...
        var = 17;
        zz = func(33, 77, var + 3) + 44;
        ...
}

Когда выполнение программы доходит до строки

        zz = func(33, 77, var + 3) + 44;

1) Происходит ВЫЗОВ ФУНКЦИИ func()

        (a)     Этот пункт мы увидим ниже.

        (b)     Создаются переменные с именами a, b, c, x, y;

        (c)     Переменным-аргументам присваиваются начальные значения,
                которые берутся из точки вызова.
                В точке вызова перечислен список (через запятую) выражений (формул):

                        func(выражение1, выражение2, выражение3)

                Вычисленные значения этих выражений соответственно будут присвоены
                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.

        (3) Подставляем это значение на место вычеркнутого func(.....)
            У нас получается

                zz = 128 + 44;

        (4) АВТОМАТИЧЕСКИ УНИЧТОЖАЮТСЯ локальные переменные и аргументы функции:

                a       - убито
                b       - убито
                c       - убито
                x       - убито
                y       - убито

        Таких переменных (и их значений) больше нет в природе.

        (5) Пункт, который мы обсудим позже.

        (6) Продолжаем вычисление:

                zz = 128 + 44;

        Вычисляется в

                zz = 172;       /* оператор присваивания */

---------------------------------------------------------------------------

int func1(int x){
        printf("func1: x=%d\n", x);     /* 1 */
        x = 77;
        printf("func1: x=%d\n", x);     /* 2 */
        return x;
}

void main(){
        int var, y;

        var = 111;
        y = func1(var);                 /* @ */

        printf("main: var=%d\n", var);  /* 3 */
}

В данном случае в точке @ мы передаем в функцию func1()
ЗНАЧЕНИЕ переменной var, равное 111.
Это значит, что при вызове функции будет создана переменная x
и ей будет присвоено начальное значение 111

        x = 111;

Поэтому первый оператор printf() напечатает 111.

Затем мы изменяем значение переменной x на 77.
Мы меняем переменную x, но не переменную var !!!
Использовав ЗНАЧЕНИЕ (его копию) из переменной var для x,
мы о переменной var забыли - она нас не касается (а мы - ее).

Поэтому второй оператор printf() напечатает 77.
В переменной же var осталось значение 111,
что и подтвердит нам третий оператор printf,
который напечатает 111.

---------------------------------------------------------------------------

ВРЕМЕННОЕ СОКРЫТИЕ ПЕРЕМЕННЫХ
=============================

int func1(int x){                       /* f.1 */
        printf("func1: x=%d\n", x);     /* f.2 */
        x = 77;                         /* f.3 */
        printf("func1: x=%d\n", x);     /* f.4 */
        return x;                       /* f.5 */
}

void main(){
        int x, y;                       /* 1 */

        x = 111;                        /* 2 */
        y = func1(x);                   /* 3 */

        printf("main: x=%d y=%d\n", x, y);  /* 4 */
}

А теперь мы и переменную внутри main(), и аргумент функции
func1() назвали одним и тем же именем. Что будет?

Будет то же самое, что в предыдущем примере.

В момент вызова функции func1() будет создана НОВАЯ переменная
с именем x, а старая (прежняя) переменная и ее значение будут
ВРЕМЕННО СПРЯТАНЫ (скрыты).

Можно было бы уточнить эти переменные именами функций,
в которых они определены:

        main::x

           и

        func1::x

(но это уже конструкции из языка Си++, а не Си).

Выполним программу по операторам:

|/* 1    */      Отводятся переменные main::x и main::y для целых чисел;
|/* 2    */      main::x = 111;
|/* 3    */      Вызывается func1(111);
|
+-------+
.       |/* f.1  */      Отводится переменная func1::x со значением 111;
.       |/* f.2  */      Печатается 111 из переменной func1::x;
.       |
.       |/* f.3  */      func1::x = 77; (это не main::x, а другая переменная,
.       |                                ЛОКАЛЬНАЯ для функции func1.
.       |                                Переменную main::x мы сейчас не видим -
.       |                                она "заслонена" именем нашей локальной
.       |                                переменной.
.       |                                Поэтому мы не можем ее изменить).
.       |
.       |/* f.4  */      Печатает 77 из func1::x;
.       |/* f.5  */      Возвращает значение func1::x , то есть 77.
.       |                Переменная func1::x уничтожается.
.       |
.       |                Теперь мы снова возвращаемся в функцию main(),
.       |                где имя x обозначает переменную main::x

+-------+
|
|/* 3    */      y = 77;
|/* 4    */      Печатает значения main::x и main::y, то есть
|                111 и 77.

Этот механизм сокрытия имен позволяет писать функции main() и func1()
разным программистам, позволяя им НЕ ЗАБОТИТЬСЯ о том, чтобы имена
локальных переменных в функциях НЕ СОВПАДАЛИ. Пусть совпадают - хуже не
будет, механизм упрятывания имен разрешит конфликт.
Зато программист может использовать любое понравившееся ему имя
в любой функции - хотя бы и x, или i.

---------------------------------------------------------------------------

То же самое происходит с локальными переменными,
а не с аргументами функции.

int func1(int arg){     /* локальная переменная-параметр func1::arg */
        int x;          /* локальная переменная          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) ...

ТО В ТЕЛЕ ФУНКЦИИ ВЫПОЛНИТСЯ (в момент ее вызова):

        арг1 = выражение1;
        арг2 = выражение2;
        арг3 = выражение3;

        перем1 = МУСОР;
        перем2 = МУСОР;

        ...
        /* продолжение */

---------------------------------------------------------------------------

ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ
=====================

Наконец, существуют переменные, которые объявляются ВНЕ ВСЕХ ФУНКЦИЙ,
и существующие все время выполнения программы
(а не только то время, когда активна функция, в которой они созданы).

Локальные переменные и аргументы УНИЧТОЖАЮТСЯ при выходе
из функции. Глобальные переменные - нет.

int x = 12;             /* ::x - ей можно заранее присвоить константу */
int globvar;            /* ::globvar                                  */

int f1(){
        int x;          /* f1::x */

        x = 77;
        printf("x=%d\n", x);            /* 4 */
        return x;
Предыдущая страница Следующая страница
1 2 3 4  5 6 7 8 9 10 11
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 
Комментарии (6)

Реклама