• Главная
  • Карта сайта
Не найдено

аргументи функції

  1. Виклики за значенням і за посиланням
  2. Виклик за посиланням
  3. Виклик функцій з допомогою масивів

tag. -> зміст

| <<< | >>>

Якщо функція повинна приймати аргументи, то в її оголошенні слід декларувати параметри, які приймуть значення цих аргументів. Як видно з оголошення наступної функції, оголошення параметрів стоять після імені функції.

/ * Повертає 1, якщо символ c входить в рядок s; і 0 в іншому випадку. * / Int is_in (char * s, char c) {while (* s) if (* s == c) return 1; else s ++; return 0; }

Функція is_in () має два параметри: s і d. Якщо символ c входить в рядок s, то ця функція повертає 1, в іншому випадку вона повертає 0.

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

Виклики за значенням і за посиланням

У мовах програмування є два способи передачі значень подпрограмме. Перший з них - виклик за значенням. При його застосуванні в формальний параметр підпрограми копіюється значення аргументу. У такому разі зміни параметра на аргумент не впливають.

Другим способом передачі аргументів підпрограми є виклик за посиланням. При його застосуванні в параметр копіюється адреса аргументу. Це означає, що, на відміну від виклику за значенням, зміни значення параметра призводять до точно таким же змінам значення аргументу.

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

Проаналізуйте наступну програму:

#include <stdio.h> int sqr (int x); int main (void) {int t = 10; printf ( "% d% d", sqr (t), t); return 0; } Int sqr (int x) {x = x * x; return (x); }

У цьому прикладі в параметр х копіюється 10 - значення аргументу для sqr (). Коли виконується присвоювання х = х * х, модифікується тільки локальна змінна х. А значення змінної t, використаної в якості аргументу при виклику sqr (), як і раніше залишається рівним 10. Тому виведено буде наступне: 100.10.

Пам'ятайте, що саме копія значення аргументу передається в функцію. А то, що відбувається всередині функції, не впливає на значення змінної, яка була використана при виклику в якості аргументу.

Виклик за посиланням

Хоча в С для передачі параметрів застосовується виклик за значенням, можна створити виклик і по посиланню, передаючи не саме аргумент, а покажчик на нього [1] . Так як функції передається адреса аргументу, то її внутрішній код в змозі змінити значення цього аргументу, який би, між іншим, за межами самої функції.

Покажчик передається функції так, як і будь-який інший аргумент. Звичайно, в такому випадку параметр слід декларувати як один з типів покажчиків. Це можна побачити на прикладі функції swap (), яка міняє місцями значення двох цілих змінних, на які вказують аргументи цієї функції:

void swap (int * x, int * y) {int temp; temp = * x; / * Зберегти значення за адресою x * / * x = * y; / * Помістити y в x * / * y = temp; / * Помістити x в y * /}

Функція swap () може виконувати обмін значеннями двох змінних, на які вказують х і y, тому що передаються їх адреси, а не значення. Усередині функції, використовуючи стандартні операції з покажчиками, можна отримати доступ до вмісту змінних і провести обмін їх значень [2] .

Пам'ятайте, що swap () (або будь-яку іншу функцію, в якій використовуються параметри у вигляді покажчиків) необхідно викликати разом з адресами аргументів [3] . Наступна програма показує, як треба правильно викликати swap ():

#include <stdio.h> void swap (int * x, int * y); int main (void) {int i, j; i = 10; j = 20; printf ( "i і j перед обміном значеннями:% d% d \ n", i, j); swap (& i, & j); / * Передати адреси змінних i і j * / printf ( "i і j після обміну значеннями:% d% d \ n", i, j); return 0; } Void swap (int * x, int * y) {int temp; temp = * x; / * Зберегти значення за адресою x * / * x = * y; / * Помістити y в x * / * y = temp; / * Помістити x в y * /}

І ось що вивела ця програма:

i і j перед обміном значеннями: 10 20 i і j після обміну значеннями: 20, 10

У програмі змінної i присвоюється значення 10, а змінної j - значення 20. Потім викликається функція swap () з адресами цих змінних. (Для отримання адреси кожної з змінних використовується унарний оператор &.) Тому в swap () передаються адреси змінних i і j, а не їх значення.

На замітку Мова C ++ за допомогою параметрів-посилань дає можливість повністю автоматизувати виклик за посиланням. А в мові С параметри-посилання не підтримується

Виклик функцій з допомогою масивів

Детально про масивах розповідалося в розділі 4 . У цьому ж розділі розповідається про передачу масивів функцій в якості аргументів. Це питання розглядається тому, що ця операція є винятком по відношенню до звичайної передачі параметрів, виконуваної шляхом виклику за значенням [4] .

Коли в якості аргументу функції використовується масив, то функції передається його адресу. В цьому і полягає виняток стосовно правилом, яке свідчить, що при передачі параметрів використовується виклик за значенням. У разі передачі масиву функції її внутрішній код працює з реальним вмістом цього масиву і цілком може змінити цей вміст. Проаналізуйте, наприклад, функцію print_upper (), яка друкує свій строковий аргумент на верхньому регістрі:

#include <stdio.h> #include <ctype.h> void print_upper (char * string); int main (void) {char s [80]; printf ( "Введіть рядок символів:"); gets (s); print_upper (s); printf ( "\ ns тепер на верхньому регістрі:% s", s); return 0; } / * Друкувати рядок на верхньому регістрі. * / Void print_upper (char * string) {register int t; for (t = 0; string [t]; ++ t) {string [t] = toupper (string [t]); putchar (string [t]); }}

Ось що буде виведено в разі фрази "This is a test." (Це тест):

Введіть рядок символів: This is a test. THIS IS A TEST. s тепер у верхньому регістрі: THIS IS A TEST.

Правда, ця програма не працює з символами кирилиці.

Після виклику print_upper () вміст масиву s в main () перетворюється на символи верхнього регістру. Якщо вам це не потрібно, програму можна написати таким чином:

#include <stdio.h> #include <ctype.h> void print_upper (char * string); int main (void) {char s [80]; printf ( "Введіть рядок символів:"); gets (s); print_upper (s); printf ( "\ ns змінювалася:% s", s); return 0; } Void print_upper (char * string) {register int t; for (t = 0; string [t]; ++ t) putchar (toupper (string [t])); }

Ось який на цей раз вийде фраза "This is a test.":

Введіть рядок символів: This is a test. THIS IS A TEST. s не змінилася: This is a test.

На цей раз вміст масиву не змінилося, тому що всередині print_upper () не змінювалися його значення.

Класичним прикладом передачі масивів у функції є стандартна бібліотечна функція gets (). Хоча gets (), яка знаходиться у вашій стандартній бібліотеці, і складніша, ніж пропонована вам версія xgets (), але за допомогою функції xgets () ви зможете отримати уявлення про те, як працює gets ().

/ * Спрощена версія стандартної бібліотечної функції gets (). * / Char * xgets (char * s) {char ch, * p; int t; p = s; / * Xgets () повертає покажчик s * / for (t = 0; t <80; ++ t) {ch = getchar (); switch (ch) {case '\ n': s [t] = '\ 0'; / * Завершує рядок * / return p; case '\ b': if (t> 0) t--; break; default: s [t] = ch; }} S [79] = '\ 0'; return p; }

Функцію xgets () слід викликати з покажчиком char *. Їм, звичайно ж, може бути ім'я символьного масиву, яке за визначенням є покажчиком char *. На самому початку програми xgets () виконується цикл for від 0 до 80. Це не дасть вводити з клавіатури рядка, що містять більше 80 символів. При спробі введення більшої кількості символів відбувається повернення з функції. (У цій функції gets () такого обмеження немає.) Так як в мові С немає вбудованої перевірки кордонів, програміст повинен сам подбати, щоб в будь-якому масиві, використовуваному при виклику xgets (), містилося не менше 80 символів. Коли знаки розміщені клавіатури, вони відразу записуються в рядок. Якщо користувач натискає клавішу <Backspase>, то лічильник t зменшується на 1, а з масиву видаляється останній символ, введений перед натисканням цієї клавіші. Коли користувач натисне <ENTER>, в кінець рядка запишеться нуль, тобто ознака кінця рядка. Так як масив, використаний для виклику xgets (), модифікується, то при поверненні з функції в ньому будуть перебувати введені користувачем символи.

Так як масив, використаний для виклику xgets (), модифікується, то при поверненні з функції в ньому будуть перебувати введені користувачем символи

[1] Звичайно, при передачі покажчика буде застосований виклик за значенням, і сам покажчик всередині функції ви змінити не зможете. Однак для того об'єкта, на який вказує цей покажчик, все станеться так, ніби цей об'єкт був переданий по посиланню. У деяких мовах програмування (наприклад, в Алгол-60) були спеціальні засоби, що дозволяють уточнити, як слід передавати аргументи: по посиланню або за значенням. Завдяки наявності покажчиків в С механізм передачі параметрів вдалося уніфікувати. Параметри, які не є масивами, в С завжди викликаються тільки за значенням, але все, що в інших мовах ви можете зробити з об'єктом, отримавши посилання на нього (тобто його адресу), ви можете зробити, отримавши значення покажчика на цей об'єкт (тобто знову ж таки, його адреса). Так що в мові С завдяки властивій йому уніфікації передачі параметрів ніяких проблем не виникає. А ось в інших мовах труднощі, пов'язані з відсутністю ефективних засобів роботи з покажчиками, зустрічаються досить часто.

[2] Звичайно, завдання, яке вирішується цією програмою, здається очевидною. Ну хіба представляє труднощі написати на будь-якому процедурному мовою, наприклад, на Алгол-60, процедуру, яка обмінює значення своїх параметрів. Адже так просто написати: procedure swap (x, y); integer х, y; begin integer t; t: = x; x: = y; y: = t end. Але ця процедура не працює належним чином, хоча виклик значень тут відбувається по посиланню! Причому відразу знайти тестовий приклад, який демонструє хибність цієї процедури, вдається далеко не всім. Адже в разі виклику swap (i, j) все працює правильно! А що буде в разі виклику swap (i, a [i])? Та й чи можна на Алгол-60 взагалі написати необхідну процедуру? Якщо ви схиляєтеся до негативної відповіді, то це показує, наскільки все-таки необхідні покажчики в розвинених мовах програмування. Якщо все ж ви знаєте правильну відповідь, то зверніть увагу на те, що необхідна процедура, хоча і не довга, але все ж містить свого роду програмістський фокус!

[3] Звичайно, це просто програмістський жаргон. Насправді, звичайно, аргументами є саме адреси змінних, а не самі змінні. Просто в цьому випадку для стислості викладу програмісти "вдають", що начебто й справді відбувається передача значень за посиланням.

[4] Адже при виклику за значенням довелося б копіювати весь масив!

зміст

| <<< | >>>

А що буде в разі виклику swap (i, a [i])?
Та й чи можна на Алгол-60 взагалі написати необхідну процедуру?
Провайдеры:
  • 08.09.2015

    Batyevka.NET предоставляет услуги доступа к сети Интернет на территории Соломенского района г. Киева.Наша миссия —... 
    Читать полностью

  • 08.09.2015
    IPNET

    Компания IPNET — это крупнейший оператор и технологический лидер на рынке телекоммуникаций Киева. Мы предоставляем... 
    Читать полностью

  • 08.09.2015
    Boryspil.Net

    Интернет-провайдер «Boryspil.net» начал свою работу в 2008 году и на данный момент является одним из крупнейших поставщиков... 
    Читать полностью

  • 08.09.2015
    4OKNET

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

  • 08.09.2015
    Телегруп

    ДП «Телегруп-Украина» – IT-компания с 15-летним опытом работы на рынке телекоммуникационных услуг, а также официальный... 
    Читать полностью

  • 08.09.2015
    Софтлинк

    Высокая скоростьМы являемся участником Украинского центра обмена трафиком (UA — IX) с включением 10 Гбит / сек... 
    Читать полностью