- •Министерство образования Республики Беларусь
- •1. Что такое программа на языке программирования
- •2. Общее знакомство с языком с
- •3. Структура простой программы на языке с
- •4. Что такое программа на языке с
- •5. Представление информации и типы данных в языке с
- •6. Константы
- •7. Переменные
- •8. Элементарный вВод и вывод информации
- •9. Выражения и операции
- •9.1. Арифметические операции
- •9.2. Операция изменения знака
- •9.3. Операции инкремента и декремента
- •9.4. Операция присваивания
- •9.6. Поразрядные логические операции
- •9.8. Логические операции и операции отношения
- •9.9. Условная операция «? :»
- •9.10. Операция последовательного вычисления
- •9.11. Операция определения требуемой памяти в байтах sizeof
- •9.12. Операция приведения типа (type)
- •10. Операторы управления вычислительным процессом
- •10.1. Операторы ветвления if и else
- •10.2. Оператор switch
- •10.3. Оператор цикла while
- •10.4. Оператор цикла do…while
- •10.5. Оператор цикла for
- •10.6. Бесконечные циклы
- •10.7. Другие управляющие средства языка с
- •10.8. Стандартные математические функции
- •11. Вычисление выражений и побочные эффекты
- •11.1. Преобразования типов при вычислении выражений
- •11.2. Побочные эффекты при вычислении выражений
- •12. Массивы
- •12.1. Описание массива
- •12.2. Инициализация массива
- •12.3. Ввод-вывод массива
- •12.4. Двумерные массивы (массивы массивов)
- •13. Указатели
- •14. Адресная арифметика
- •15. Массивы и указатели
- •15.1. Указатели и одномерные массивы
- •15.2. Указатели и двумерные массивы
- •16. Строки
- •17. Массивы строк
- •18. Функции
- •18.1. Определение функции в языке с
- •18.2. Возвращение значений из функции
- •18.3. Формальные и фактические параметры функции
- •18.4. Вызов функции
- •18.5. Объявление и определение функции: прототип функции
- •19. Передача параметров в функции
- •19.1. Способы передачи параметров в функции
- •19.2. Передача параметров в функции в языке с
- •19.3. Передача указателей в функции
- •20. Классы хранения и видимость переменных
- •20.1. Общие положения
- •20.2. Спецификаторы класса памяти
- •20.3. Область видимости функций
- •20.4. Глобальные переменные
- •20.5. Глобальные статические переменные
- •20.6. Локальные переменные
- •20.7. Статические локальные переменные
- •20.8. Регистровые переменные
- •20.9. Выводы
- •21. Организация памяти программы
- •22. Многофайловая компиляция (проекты)
- •23. Передача в функции массивОв
- •23.1. Передача одномерных массивов в функции
- •23.2. Передача двумерных массивов в функции
- •23.3. Передача в функции символьных строк
- •23.4. Возвращение указателей из функций
- •24. Функции с переменным количеством аргументов
- •24.1. Соглашения о вызовах: модификаторы функций
- •24.2. Объявление списка параметров переменной длины
- •25. Передача параметров в функцию main()
- •26. Указатели на функцию
- •27. Стандартные функцИи языка с
- •27.1. Функции для работы со строками
- •27.2. Функции для проверки символов и преобразования данных
- •27.3. Функция быстрой сортировки – gsort()
- •27.4. Функция двоичного поиска – bsearch()
- •28. Работа с файлами
- •28.1. Основные понятия
- •28.2. Основные функции для работы с файлами
- •28.3. Открытие и закрытие файлов
- •28.4. Ввод/вывод символов
- •28.5. Ввод/вывод строк
- •28.6. Форматированный ввод/вывод
- •28.7. Ввод/вывод блоков данных
- •28.8. Другие средства для работы с файлами
- •28.9. Ввод/вывод низкого уровня (префиксный доступ к файлам)
- •29. Типы, определяемые пользователем: Перечисления, структуры и объединения
- •29.1. Переименование типов – оператор typedef
- •29.2. Перечисления (enum)
- •29.3. Основные сведения о структурах
- •29.4. Структурные переменные в памяти компьютера
- •29.5. Доступ к полям структуры
- •29.6. Массивы структур
- •29.7. Структуры и функции
- •29.8. Объединения (union)
- •30. Динамическая память
- •30.1. Понятие динамического объекта
- •30.2 Создание и уничтожение динамических объектов
- •30.3 Динамическое размещение одномерных массивов и строк
- •30.4 Динамическое размещение двумерных массивов
- •30.5. Функции для работы с блоками памяти
- •31. Динамические структуры данных
- •31.1. Понятие структуры данных
- •31.2. Структуры, ссылающиеся на себя
- •31.3. Связанные списки
- •31.5. Очереди
- •Ниже приводятся примеры функций для очереди (структура элемента очереди совпадает со структурой элемента стека в примере выше):
- •32. Препроцессор языка с
- •32.1 Директива включения файлов
- •32.2. Директива определения макрокоманд (макросов)
- •32.3 Директива условной компиляции
- •32.4 Дополнительные директивы препроцессора
23. Передача в функции массивОв
23.1. Передача одномерных массивов в функции
При передаче имени массива в качестве параметра функции как аргумент передается не копия самого массива (это заняло бы слишком много места в стеке), а копия адреса нулевого элемента этого массива (или указатель на начало массива). Иными словами, массивы отличаются от других типов тем, что они не передаются и не могут передаваться по значению.
В программе ниже в func() передается указатель на массив mas:
void main(void) {
int mas[10];
...
func(mas);
...
}
Если в функцию передается указатель на одномерный массив, то в самой функции его можно объявить одним из трех вариантов: как указатель, как массив определенного размера и как массив неопределенного размера.
void func(int *x) { // указатель
...
}
void func(int x[10]) { // массив определенного размера
...
}
void func(int x[]) { // массив неопределенного размера
...
}
Эти три объявления тождественны, потому что каждое из них сообщает компилятору одно и то же: в функцию будет передан указатель на переменную целого типа.
В последнем примере форма объявления массива сообщает компилятору, что в функцию будет передан массив неопределенной длины. Длина массива не имеет для функции никакого значения, потому что в языке С проверка границ массива не выполняется. Эту функцию можно объявить даже так:
void func(int x[50]) {
...
}
Программа все равно будет работать правильно, потому что компилятор не создает массив из 50 элементов, а только подготавливает функцию к приему указателя.
Обратить внимание! Поскольку массив передается как указатель на его начало, то размер массива в объявлении аргумента можно не указывать. Это позволяет одной функцией обрабатывать массивы разной длины.
Раз функции передается адрес массива, значит функция работает с реальным содержимым этого массива и вполне может изменить это содержимое.
void f1(int m) {
m++;
}
void f2(int m[]) {
m[0]++;
}
void main() {
int mas[2] = {1, 1};
f1(mas[0]);
printf("%d\n", mas[0]); // mas[0] осталось равно 1
f2(mas);
printf("%d\n", mas[0]); // mas[0] стало равно 2
}
В f1() в качестве аргумента передается копия элемента mas[0]. Изменение этой копии не приводит к изменению самого массива, т.к. аргумент m является локальной переменной в функции f1(). В функции f2() локальным является адрес массива mas, но не сам массив. Поэтому m[0]++ изменяет сам массив mas (в то же время, например, m++ внутри f2() изменило бы лишь локальный указатель m, но не адрес массива mas).
Для обработки массива, кроме адреса начала массива функция должна знать и количество элементов в массиве. Поэтому, если массив, для обработки которого используется функция, может иметь разный размер, в функцию дополнительно следует передавать и реальную размерность массива (точное число элементов в массиве). Тогда она сможет менять указатель в безопасных пределах и получит полный доступ к любому элементу массива.
Задача. Разработать функцию для нахождения максимального элемента в одномерном массиве целых чисел.
int f_max(int *m, int n) {
int max, i;
max = m[0];
for (i=1; i<n; i++)
if (m[i] > max) max = m[i];
return max;
}
void main() {
int mas[100], n, i, n2, k, *p, max2;
printf(“Введите размерность массива\n”);
scanf(“%d”, &n);
printf(“Введите массив\n”);
for (i=0; i<n; i++)
scanf(“%d”, &mas[i]);
printf(“Максимальный элемент = %d\n”, f_max(mas,n));
// находим максимум во второй половине массива
k = n2 = n / 2; // k – смещение второй половины
if (n&1) n2++; // n2 – количество элементов во второй половине
// при нечетном n средний элемент относим ко второй половине
printf(“Максимальный элемент второй половины = %d\n”,
f_max(mas+k,n2));
// можно и так вызвать функцию: p = mas+k; max2 = f_max(p,n2);
}
Задача. Разработать функцию для нахождения номера минимального элемента и суммы элементов одномерного массива целых чисел.
int func(int *m, int n, int *sum) {
int i, min, n_min;
min = *m; n_min = 0;
*sum = m[0];
for (i=1; i<n; i++) {
if (m[i] < min) {
min = *(m+i); n_min = i; // находим номер минимального
}
*sum += m[i]; // находим сумму элементов
}
return n_min; // возвращаем номер минимального элемента
}
void main() {
int mas[100], n, i, sum;
printf("Введите размерность массива\n");
scanf("%d", &n);
printf("Введите массив\n");
for (i=0; i<n; i++)
scanf("%d", &mas[i]);
printf("Номер минимального = %d\n", func(mas, n, &sum));
printf("Сумма = %d\n", sum);
}
Задача. Разработать функцию для замены всех нулевых элементов массива заданным числом.
void f(int *m, int n, int k) {
int i;
for (i=0; i<n; i++)
if (m[i] == 0)
*(m+i) = 100; // m[i] = 100;
}
void main() {
int mas[100], n, i;
printf("Введите размерность массива\n");
scanf("%d", &n);
printf("Введите массив\n");
for (i=0; i<n; i++)
scanf("%d", &mas[i]);
f(mas, n, 100); // заменить все 0 на 100
printf("Массив после замены\n");
for (i=0; i<n; i++)
printf("%d ", mas[i]);
printf("\n");
}