Skip to the content.

16 сентября 2021

Упражнение 1. Написать программу для вывода первых n чисел Фибоначчи.

Упражнение 2. Написать программу для проверки простоты натурального числа. Число вводится с клавиатуры.

Передача аргументов в функцию в Си

Передача агрумента в функию происходит по значению. Это значит, что в функцию передается копия переменной, которая имеет то же значение. Это значит, что передав аргумент типа int в функцию, мы не сможем изменить ее значение:

#include <stdio.h>

void increment(int a) {
    ++a;
}

int main() {
    int value = 2;
    printf("%d ", value);
    increment(value);
    printf("%d\n", value);
    return 0;
}

Эта программа увеличила значение переменной a, которая существует только внутри функции increment. Значение переменной value в функции main осталось неизменным:

2 2

Мы научимся изменять значение переменной в функции, рассмотрев указатели.

Указатели

Каждой переменной соответствует некоторое место в памяти со своим уникальным адресом. Оператор & позволяет получить адрес в памяти, соответствующий переменной:

int a = 1;
int b = 2;
int c = 3;

printf("%x %d\n", &a, a);
printf("%x %d\n", &b, b);
printf("%x %d\n", &c, c);

В результате выполнения этого кода автор получилось:

61fecc 1
61fec8 2
61fec4 3

(адреса выведены в шеснадцатиричной системе счисления). Единица памяти соответствует одному байту. Видно, что переменные int расположены в памяти с шагом 4 байта (32 бита), что соответствует размеру типа int на компьютере автора.

Упражнение. Воспроизведите этот пример для других типов данных (например, double). Какой интервал между адресами переменных получается в этих случаях?

В Си существуют специальные переменные, которые хранять адрес в памяти, их называют указателями. Объявить указатель можно так:

int a = 5;
int *ptr = &a;

Переменная ptr хранит адрес переменной a. Чтобы получить значение переменной через указатель необходимо использовать оператор разыменовывания *:

int b = *ptr;
printf("%d %d %d\n", a, *ptr, b);
printf("%x %x %x\n", &a, ptr, &b);

Получим:

5 5 5
61fec8 61fec8 61fea4

Выражения &a и ptr соответствуют адресу 61fec8, а выражение &b - адресу 61fea4.

Указатель можно использовать для измерения значения переменной:

int value = 6;
int *vptr = &value;
*vptr = 11;
printf("value = %d\n", value);

Получим:

value = 11

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

void increment(int* a) {
    ++*a;
}

int value = 2;
printf("%d\n", value);
increment(&value);
printf("%d\n", value);

Получим:

2
3

Пример. Функция swap. Одна из часто используемых операций в программировании - обмен значений между двумя переменными. Используя указатели, мы можем написать функцию swap:

void swap(int *a, int *b) {
    int tmp = *b;
    *b = *a;
    *a = tmp;
}

Упражнение. Напишите версию функции swap, которая не использует дополнительные переменных.