Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Бичков - Основи сучасного програмування.doc
Скачиваний:
81
Добавлен:
07.03.2016
Размер:
3 Мб
Скачать
☆

Void sum(char *msg,...)

{

int total=0;

va_list ap;

int arg;

va_start(ap,msg);

while((arg=va_arg(ap,int))!=0) {

total+=arg;

}

printf(msg,total);

va_end(ap);

}

int main(void) {

sum("Сума 1+2+3+4 є %d\n",1,2,3,4,0);

return 0;

}

6.4. Рекурсія

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

printd(n) /*print n in decimal

*(recursive)*/

int n;

{

int i;

if(n<0) {

putchar('-');

n=-n;

}

if((i=n/10)!=0)

printd(i);

putchar(n%10+'0');

}

Коли функція викликає себе рекурсивно, то при кожному звертанні утворюється новий набір усіх автоматичних змінних. Таким чином, у printd(123) перша функція printd має n=123. Вона передає 12 другій printd, а коли та повертає керування їй, друкує 3. Точно так само друга printd передає 1 третій, яка її друкує, а потім друкує 2.

6.5. Параметри функції main

Функція main може мати такі параметри:

main(int arg c,char*argv[], char*envp[])

Тут argc – кількість параметрів, що передаються у функцію main, має тип int; arg v – масив покажчиків на тип char:char*argv[].

Кожен покажчик містить адресу наступного аргументу. Значення arg c завжди >1, оскільки обов'язковим параметром є ім'я файла вихідної С-програми

main(int arg c,char*arg v)

{printf("ім’я файла – %s',argv[0]);

return 0;

}

де envp – масив покажчиків на тип char:char*envp[]. Він містить змінні оточення операційної системи. Для роботи зі змінними оточення використовуються функції

char*getenv(char*varname) та void putenv (char*var).

Функція getenv дає можливість отримати значення в списку змінних оточення, putenv добавляє в список змінних оточення рядок. Наприклад, функція char*s=getenv(PATH).

Рядок var має бути конструкцією вигляду varname=string. Наприклад:

char*s='PATH=e:\bc\my\';

putenv(s);

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

main(int argc,char*argv,char*envp)

{for(int i=0;i<argc;i++);

printf("%s\n',argv[i]);

return 0;

}

6.6. Лiтернi покажчики та функцiї

Покажчик на тип char можна ініціалізувати символьними рядками:

char*pc='abc';

Аналогічно можна ініціалізувати масив елементів типу char:

char c[ ]={'a','b','c'};

Тоді

pc[0]==c[0]=='a', pc[1]==c[1]=='b', pc[2]==c[2]=='c'.

Однак перше та друге визначення мають відмінність. Вона полягає в тому, що рядкова константа обов’язково містить 0-символ. Тому pc[3]=='\0'. Це потрібно враховувати при роботі з функціями, які працюють із рядками. Такі функції можуть містити конструкцію

while(*s!='\0')s++;

Тоді при передаванні імені масиву на вхід функції може бути не знайдено 0-символ, і функція спрацює некоректно. Наприклад:

Void strcpy(char*s,char*t)

{int i=0

while(s[i]=t[i]!='\0')i++;

}

Цю функцію можна записати й так:

void strcpy(char*s,char*t)

{while(*s++=*i++);}

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

[<спец. типу>](*iм'я)(<список типiв параметрiв>)

Проілюструємо це двома програмами:

1

double (*f)(int);

extern double f1(int),f2(int);

main()

{

int n;double s;

scanf("%d",&n);

if(n>0)f=f1; else f=f2;

for(i=0;i<100;i++)

s+=(*f)(i);

}

2

extern int f1(int),f2(int);

extern void work(int,int(*)(int));

{main()

work(1,f1);

work(2,f2);

}

6.7. Час життя та область дії.

Оголошення та визначення

Час життя – це проміжок часу існування об'єкта в процесі виконання програми. Він буває глобальним і локальним. Глобальний – коли об'єкт існує протягом усього часу виконання програми. Локальний – коли об'єкт існує на деякому проміжку, що включається до часу виконання програми.

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

Під оголошенням функції розумітимемо конструкцію, у якій задається лише прототип функції та (необов'язково) специфікація класу пам'яті. Наприклад:

float s=5;

float f(float);

s=s+f(1);

У другому рядку лише оголошується функція f, тіло якої визначається в іншому місці програми (напр., нижче за текстом).

Під визначенням змінної розумітимемо конструкцію, обробка якої викликає виділення пам'яті. Наприклад:

int i=0;

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

int i;

i=4;

//...

{

static int i=5;

}

Розглянемо рядок програми int i; Як його інтерпретувати з погляду оголошення чи визначення змінної i? Це може бути як оголошення, так і визначення. Якщо в програмі більше не зустрічається оголошення чи визначення змінної i, то це буде визначенням. Воно супроводжується виділенням пам'яті та ініціалізацією нулем, якщо цей рядок коду знаходиться на зовнішньому рівні. Якщо в іншому міс­ці програми знаходиться визначення змінної i, то вказана конструк­ція є оголошенням:

файл1 файл2

int i; int i=5;

…

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

main()

{ …

{

float f(int,int);

i++;

…};

};

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

…..

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]