Розуміння функцій C: параметри, значення, що повертаються, і область видимості

1

Більшість мов програмування дозволяють розбити громіздкий код, що довго виконується на акуратні іменовані фрагменти. Ці фрагменти називаються функціями. Вони дозволяють повторно використовувати код замість того, щоб переписувати ту саму логіку знову і знову. Функція приймає вхідні дані, відомі як параметри, і видає результат. У C можна передавати стільки параметрів, скільки необхідно. Компілятору не важливим є порядок оголошення функцій у вихідному файлі, головне — щоб він знав ім’я функції до того, як спробує її виконати.

Ми коротко торкалися цієї теми з функцією rand. Це найпростіша можлива функція. Вона нічого не приймає та повертає ціле число.

`

Рядок int rand() повідомляє компілятору, що rand – це функція. Вона не приймає параметрів та повертає ціле число. У цій конкретній версії немає локальних змінних. Якби вони були, вони розташовувалися б відразу після фігурної дужки {. C дозволено оголошувати змінні будь-де після {. Вони існують до тих пір, поки не буде досягнута відповідна дужка, що закриває }. Потім вони зникають. Поки вони живі, локальні змінні зберігаються в системному стеку.

Зверніть увагу на відсутність крапки з комою після rand(). Якщо ви випадково поставите її, компілятор видасть безліч безглуздих повідомлень про помилки. Навіть якщо параметрів немає, дужки є обов’язковими. Без них ви не оголошує функцію, а просто оголошує ціле число.

Оператор return і кілька точок виходу

Оператор return критично важливий для будь-якої функції, яка повертає результат. Він встановлює значення, що повертається, і негайно завершує виконання функції. Ви можете розмістити кілька операторів return в одній функції, щоб створити кілька точок виходу.

Якщо ви забудете оператор return у функції, яка повинна повертати значення, функція завершиться при досягненні дужки, що закриває. Вона поверне випадкове, «сміттєве» значення. Більшість сучасних компіляторів попередять вас, якщо ви забудете повернути конкретне значення. C підтримує повернення будь-якого типу: int, float, char, struct та інших.

Існує кілька правильних способів виклику функції rand. Найпоширеніший – привласнення:

`

Тут змінна x набуває значення, що повертається rand. Ви повинні увімкнути дужки під час виклику, навіть якщо параметрів немає. Без них x отримає адресу пам’яті функції rand. Це рідко є тим, що ви мали намір зробити.

Ви можете також викликати її всередині умови:

`

Або просто проігнорувати результат:

`

В останньому випадку функція виконується, але значення, що повертається, відкидається. Можливо, вам не варто робити це з rand, але багато функцій використовують значення, що повертається як код помилки. Якщо ви знаєте, що помилка неможлива, відкидання коду допустиме.

Обробка void-повернень

Іноді вам нічого не потрібно повертати. Для цього використовується тип повернення ‘void’.

`

Ця функція виводить текст, але не повертає жодного значення. Ви викликаєте її так:

`

Знову увімкніть дужки. Якщо ви опустите їх, функція не буде викликана. Вона скомпілюється коректно на багатьох системах, але нічого не зробить.

Параметри та застарілий стиль коду на C

Опції C можуть приймати параметри будь-якого типу. Ось функція, яка обчислює факторіал числа:

`

Параметр i передається як ціле число. Щоб передати кілька параметрів, розділяйте їх комами.

`

Мова C еволюціонувала. Ви час від часу зустрічатимете старий код, написаний у «старому стилі». Він виглядає так:

`

Ви маєте вміти читати цю стару нотацію. Вона виконується так само. Це просто інший синтаксис. Ви повинні використовувати новий стиль, відомий як ANSI C, де типи оголошуються в списку параметрів. Використовуйте старий стиль тільки якщо ви знаєте, що відправляєте код комусь із не-ANSI компілятором.

Чому це важливо для звичайних користувачів

Ви можете не писати функції C щодня. Але розуміння того, як вони працюють, змінює ваше уявлення про програмне забезпечення. Щоразу, коли ви натискаєте кнопку у веб-додатку, функція, швидше за все, обробляє цей клік, перевіряє параметри та повертає статус. Якщо ви бачили «runtime error» (помилка часу виконання) або «stack overflow» (переповнення стека), ви стикалися з межами цих механізмів.

Відмінність між передачею значення та передачею посилання (адреси пам’яті) є поширеним джерелом помилок. У високорівневих мовах часто приховано. У C це очевидно. Знання того, що rand без дужок повертає адресу, а не число, заощаджує годинник налагодження.

Дискусія про старий стиль проти нового стилю в основному врегульована для нових проектів. ANSI C є стандартом. Але застарілі кодові бази існують. Вміння читати int add(i,j) int i; int j; запобігає застряванню на коді, який виглядає неправильно, але працює ідеально. Це питання грамотності.

Чи справді стек має для вас значення? Якщо ваша програма зненацька падає, трасування стека — це ваша єдина підказка. Зникнення локальних змінних при досягненні дужки, що закриває, — це не баг. Це особливість. Вона робить використання пам’яті передбачуваним.

Немає ідеального способу написання коду. Є тільки спосіб, що компілюється, та спосіб, який не компілюється. Зберігайте дужки. Слідкуйте за операторами return. І не припускайте, що компілятор врятує вас від своїх синтаксичних помилок. Він не врятує.