Blog literacki, portal erotyczny - seks i humor nie z tej ziemi
LEKCJA 15. Jak posługiwać się funkcjami.
________________________________________________________________
W trakcie tej lekcji dowiesz się więcej o:
* funkcjach i prototypach funkcji;
* przekazywaniu argumentów funkcji;
* współpracy funkcji ze wskaźnikami.
_______________________________________________________________
Aby przedstawić działanie operatorów logicznych opracujemy
własną funkcję Demo() i zastosujemy ją w programie przykładowym
[najważniejszy fragment].
int Demo(int Liczba)
{
int MaxNr=15;
for (; MaxNr>=0; MaxNr--)
{
if ((Liczba>>MaxNr)&1)
printf("1");
else
printf("0");
}
return 0; //Funkcja nie musi nic zwracac
}
Funkcja przesuwa liczbę o kolejno 15, 14, 13 itd. bitów w prawo
i sprawdza, czy 16, 15, 14 bit jest jedynką, czy zerem. Iloczyn
logiczny z jedynką ( 0000000000000001 ) gwarantuje nam, że wpływ
na wynik operacji będzie miał tylko ten jeden bit (patrz wyżej -
jak działają operatory logiczne).
[P042.CPP]
# include
int Demo(int Liczba)
{
int MaxNr=15;
for (; MaxNr>=0; MaxNr--)
if ((Liczba>>MaxNr)&1) printf("1");
else printf("0");
return 0;
}
char odp;
int main()
{
int X, Y;
clrscr();
printf("\nPodaj dwie liczby calkowite od -32768 do +32767\n");
printf("\nLiczby X i Y rozdziel spacja");
printf("\nPo podaniu drugiej liczby nacisnij [Enter]");
printf("\nLiczby ujemne sa w kodzie dopelniajacym");
printf("\nskrajny lewy bit oznacza znak 0-Plus, 1-Minus");
for(;;)
{
printf("\n");
scanf("%d %d", &X, &Y);
printf("\nX:\t"); Demo(X);
printf("\nY:\t"); Demo(Y);
printf("\n~Y:\t"); Demo(~Y);
printf("\nX&Y:\t"); Demo(X&Y);
printf("\nX|Y:\t"); Demo(X|Y);
printf("\nX^Y:\t"); Demo(X^Y);
printf("\nY:\t"); Demo(Y);
printf("\nY>>1:\t"); Demo(Y>>1);
printf("\nY<<2:\t"); Demo(Y<<2);
printf("\n\n Jeszcze raz? T/N");
odp=getch();
if (odp!='T'&& odp!='t') break;
}
return 0;
}
Jeśli operacje mają być wykonywane nie na bitach a na logicznej
wartości wyrażeń:
|| oznacza sumę (LUB);
&& oznacza iloczyn (I);
! oznacza negację (NIE).
Przykłady:
(x==0 || x>5) - x równa się 0 LUB x większy niż 5;
(a>5 && a!=11) - a większe niż 5 I a nie równe 11;
(num>=5 && num!=6 || a>0)
num nie mniejsze niż 5 I num nie równe 6 LUB a dodatnie;
Wyrażenia logiczne sprawdzane instrukcją if MUSZĄ być ujęte w
nawiasy okrągłe.
Do wytworzenia wartości logicznej wyrażenia może zostać użyty
operator relacji: < <= == >= > != . Jeśli tak się nie
stanie, za wartość logiczną wyrażenia przyjmowane jest:
1, PRAWDA, TRUE, jeśli wartość numeryczna wyrażenia jest różna
od zera.
0, FAŁSZ, FALSE, jeśli wartość numeryczna wyrażenia jest równa
zero.
Porównaj:
if (a<=0) ...
if (a) ...
if (a+b) ...
Konwersja - przykłady.
C++ dysponuje wieloma funkcjami wykonującymi takie działania,
np:
itoa() - Integer TO Ascii - zamiana liczby typu int na łańcuch
znaków ASCII;
ltoa() - Long int TO Ascii - zamiana long int -> ASCII;
atoi() - zamiana Ascii -> int;
atol() - zamiana Asdii -> long int .
Wszystkie wymienione funkcje przekształcając liczby na łańcuchy
znaków potrzebują trzech parametrów:
p1 - liczby do przekształcenia;
p2 - bufora, w którym będą przechowywać wynik - łańcuch ASCII;
p3 - podstawy (szesnastkowa, dziesiętna itp.).
Jeśli chcemy korzystać z tych funkcji, powinniśmy dołączyć plik
nagłówkowy z ich prototypami - stdlib.h (STandarD LIBrary -
standardowa biblioteka). A oto przykład.
[P043.CPP]
# include "stdio.h"
# include "stdlib.h"
main()
{
int i;
char B10[10], B2[20], B16[10]; //BUFORY
for (i=1; i<17; i++)
printf("%s %s %s\n",
itoa(i, B10[i], 10),
itoa(i, B2[i], 2),
itoa(i, B16[i], 16));
return 0;
}
[Z]
________________________________________________________________
1. Opracuj program testujący działanie funkcji atoi().
________________________________________________________________
KILKA SŁÓW O TYPACH DANYCH i KONWERSJI W C/C++ .
Przed przystąpieniem do obszernego zagadnienia "funkcje w C"
krótko zasygnalizujemy jeszcze jedno zjawisko. Wiesz z
pewnością, że wykonywane na liczbach dwójkowych mnożenie może
dać wynik o długości znacznie większej niż mnożna i mnożnik. W
programach może się poza tym pojawić konieczność np. mnożenia
liczb zmiennoprzecinkowych przez całkowite. Jak w takich
przypadkach postępuje C++ ?
Po pierwsze:
C/C++ może sam dokonywać konwersji, czyli zmiany typów danych
naogół zgodnie z zasadą nadawania zmiennej "mniej pojemnego"
rodzaju typu zmiennej "bardziej pojemnego" rodzaju przed
wykonaniem operacji;
Po drugie:
my sami możemy zmusić C++ do zmiany typu FORSUJĄC typ świadomie
w programie.
W przykładzie poniżej podając w nawiasach żądany typ zmiennej
forsujemy zmianę typu int na typ float.
[P044.CPP]
# include "stdio.h"
void main()
{
int a=7;
printf("%f", (float) a);
}
Konwersja typów nazywana bywa także "rzutowaniem" typów (ang.
type casting). A oto kilka przykładów "forsowania typów":
int a = 2;
float x = 17.1, y = 8.95, z;
char c;
c = (char)a + (char)x;
c = (char)(a + (int)x);
c = (char)(a + x);
c = a + x;
z = (float)((int)x * (int)y);
z = (float)((int)x * (int)y);
z = (float)((int)(x * y));
z = x * y;
c = char(a) + char(x);
c = char(a + int(x));
c = char(a + x);
c = a + x;
z = float(int(x) * int(y));
z = float(int(x) * int(y));
z = float(int(x * y));
z = x * y;
FUNKCJE BIBLIOTECZNE I WŁASNE W JĘZYKU C/C++ .
Pojęcie funkcji obejmuje w C/C++ zarówno pascalowe procedury,
jak i basicowe podprogramy. Funkcji zdefiniowanych w C++ przez
prducenta jest bardzo dużo. Dla przykładu, funkcje arytmetyczne,
które możesz wykorzystać do obliczeń numerycznych to np.:
abs() - wartość bezwzględna,
cos() - cosinus, sin() - sinus, tan() - tangens,
asin(), atan(), acos(), - funkcje odwrotne ARCUS SINUS...
funkcje hiperboliczne: sinh(), cosh(), tanh(),
wykładnicze i logarytmiczne:
exp() - e^x
log() - logarytm naturalny,
log10() - logarytm dziesiętny.
Jeśli skorzystasz z systemu Help i zajrzysz do pliku math.h
(Help | Index | math.h), znajdziesz tam jeszcze wiele
przydatnych funkcji.
Funkcja może, ale nie musi zwracać wartość do programu -
dokładniej do funkcji wyższego poziomu, z której została
wywołana. W ciele funkcji służy do tego instrukcja return.
Użytkownik może w C++ definiować własne funkcje. Funkcja może
być bezparametrowa. Oto przykład bezparametrowej funkcji,
zwracającej zawsze liczbę całkowitą trzynaście:
int F_Trzynascie()
{
return 13;
}
Poprawne wywołanie naszej funkcji w programie głównym miałoby
postać:
int main()
{
......
int X;
........ // Funkcja typu int nie musi byc deklarowana.
X = F_Trzynascie();
......
}
Jeśli funkcja musi pobrać jakieś parametry od programu (funkcji
wyższego poziomu, wywołującej)? Zwróć uwagę, że program główny w
C/C++ to też funkcja - main(). Przykład następny pokazuje
definicję funkcji obliczającej piątą potęgę pobranego argumentu
i wywołanie tej funkcji w programie głównym.
Przykład:
int F_XdoPiatej(int argument)
{
int robocza; //automatyczna wewnetrzna zmienna funkcji
robocza = argument * argument;
robocza = robocza * robocza * argument;
return (robocza);
}
int main()
{
int Podstawa, Wynik, a, b;
... /* Funkcja nie jest deklarowana przed uzyciem */
Wynik = F_XdoPiatej(Podstawa);
.....
a = F_XdoPiatej(b);
.....
return 0;
}
Zwróć uwagę, że definiując funkcję podajemy nazwę i typ
ARGUMENTU FORMALNEGO funkcji - tu: argument. W momencie
wywołania na jego miejsce podstawiany jest rzeczywisty bieżący
argument funkcji.
Aby zapewnić wysoką dokładność obliczeń wymienione wyżej funkcje
biblioteczne sqrt(), sin() itp. "uprawiają" arytmetykę na
długich liczbach typu double. Funkcję taką przed użyciem w swoim
programie MUSISZ ZADEKLAROWAĆ. Przykład:
[P045.CPP]
main()
{
double a, b;
double sqrt(); // tu skasuj deklaracje funkcji sqrt()
// a otrzymasz bledny wynik !
clrscr();
printf("Podaj liczbe\n");
scanf("%lf", &a);
b = sqrt(a);
printf("\n %Lf", (long double) b);
getch();
return 0;
}
PROTOTYPY FUNKCJI, czyli jeszcze o deklaracjach funkcji.
Prototyp funkcji to taka deklaracja, która:
* została umieszczona na początku programu poza funkcją main(),
* zawiera deklarację zarówno typu funkcji, jak i typów
argumentów.
Przykład prototypu (funkcja2.cpp):
double FUNKCJA( double X, double Y);
main()
{
double A=0, B=3.14;
printf("Wynik działania funkcji: \n");
printf("%lf", FUNKCJA(A,B));
return 0; }
double FUNKCJA(double X, double Y)
{
return ((1+X)*Y);
}
Prototyp mógłby równie dobrze wyglądać tak:
double FUNKCJA(double, double);
nazwy parametrów formalnych nie są istotne i można je pominąć.
Jeśli prototyp funkcji wygląda tak:
int Funkcja(int, char*, &float)
oznacza to, że parametrami funkcji są wskaźniki do zmiennych,
bądź referencje do zmiennych. Przy rozszyfrowywaniu takiej
"abrakadabry" warto wiedzieć, że
char* oraz char *
int& oraz int &
ma w tym przypadku identyczne znaczenie.
W C++ wolno nie zwracać wartości funkcjom typu void. To dlatego
właśnie często rozpoczynaliśmy programy od
void main()
Skutek praktyczny: Jeśli w ciele funkcji typu void występuje
instrukcja return (nie musi wystąpić) to instrukcja ta nie może
mieć argumentów.
Oto przykład prototypu, definicji i wywołania funkcji typu void:
[P046.CPP]
#include
#include
void RYSUJPROSTOKAT( int Wys, int Szer, char Wzorek);
void main()
{
clrscr();
RYSUJPROSTOKAT(5, 20, ''); // klocek ASCII 176 - [Alt]-[176]
getch();
RYSUJPROSTOKAT(15, 15, ''); //[Alt]-[177]
getch();
}
void RYSUJPROSTOKAT( int Wys, int Szer, char Wzorek)
{
int i, j; // automatyczne zmienne wewnętrzne funkcji
for(i=1; i<=Wys; i++)
{
for(j=1; j<=Szer; j++) printf("%c",Wzorek);
printf("\n");
}
}
Prototypy wszystkich funkcji standardowych znajdują się w
plikach nagłówkowych *.H (ang. Header file).
Skutek praktyczny:
JEŚLI DOŁĄCZYSZ DO PROGRAMU STOSOWNE PLIKI NAGŁÓWKOWE *.h,możesz
ZREZYGNOWAĆ Z DEKLARACJI FUNKCJI. Dodając do programu wiersz:
#include
dołączający plik zawierający prototyp funkcji sqrt(), możesz
napisać program tak:
#include
#include
main()
{
double a, b;
clrscr();
printf("Podaj liczbe\n");
scanf("%lf", &a);
b = sqrt(a);
printf("\n %Lf", (long double) b);
getch();
return 0;
}
PRZEKAZYWANIE PARAMETRÓW DO FUNKCJI.
W C++ często przekazuje się parametry do funkcji przy pomocy
wskaźników. Aby prześledzić co dzieje się wewnątrz funkcji wpisz
i uruchom podany niżej program przykładowy. Najpierw
skonstruujemy sam program a następnie zmodyfikujemy go w taki
sposób, abyś mógł sobie popodglądać cały proces. Przy pomocy
funkcji printf() każemy wydrukować kolejne stany zmiennych, stan
programu i funkcji, a funkcja getch() pozwoli Ci obejrzeć to
"krok po kroku". Mogłoby się wydawać, że program poniżej
skonstruowany jest poprawnie...
void FUNKCJA( int ); //Prototyp, deklaracja funkcji
void main()
{
int Zmienna; //Zmienna funkcji main, rzeczywisty argument
clrscr();
Zmienna = 7;
FUNKCJA( Zmienna); //Wywolanie funkcji
printf("%d", Zmienna); //Wydruk wyniku
}
void FUNKCJA( int Argument) //Definicja funkcji
{
Argument = 10 * Argument + Argument;
}
FUNKCJA() jest jak widać trywialna. będzie zamieniać np. 2 na
22, 3 na 33 itp. tylko w tym celu, by łatwo było stwierdzić, czy
funkcja zadziałała czy nie.
Rozbudujmy program tak by prześledzić kolejne stadia.
[P047.CPP]
void FUNKCJA( int ); //Prototyp
int Zmienna;
void main()
{
clrscr();
printf("Stadium: \tZmienna Argument");
printf("\nStadium 1\t%d\tnie istnieje\n", Zmienna);
Zmienna = 7;
printf("Stadium 2\t%d\tnie istnieje\n", Zmienna );
FUNKCJA( Zmienna);
printf("Stadium 3\t%d", Zmienna);
// printf("%d", Argument);
// taka proba sie NIE UDA !
getch();
}
void FUNKCJA( int Argument) //Definicja funkcji
{
printf("jestesmy wewnatrz funkcji\n");
printf("Nastapilo kopiowanie Zmienna -> Argument\n" );
printf("\t\t%d\t%d\n", Zmienna, Argument);
getch();
Argument = 10*Argument + Argument;
printf("\t\t%d\t%d\n", Zmienna, Argument);
getch();
}
Próba wydrukowania zmiennej Argument gdziekolwiek poza wnętrzem
FUNKCJI() nie uda się i spowoduje komunikat o błędzie. Oznacza
to, że POZA FUNKCJĄ zmienna Argument NIE ISTNIEJE. Jest tworzona
na stosie jako zmienna automatyczna na wyłączny użytek funkcji,
w której została zadeklarowana i znika po wyjściu z funkcji.
Przy takiej organizacji funkcji i programu funkcja otrzymuje
kopię zmiennej, na niej wykonuje swoje działania, natomiast
zmienna (zmienne) wewnętrzna funkcji znika po wyjściu z funkcji.
Problem przekazania parametrów pomiędzy funkcjami wywołującymi
("wyższego rzędu" - tu: main) i wywoływanymi (tu: FUNKCJA) można
rozwiązać przy pomocy
* instrukcji return (zwrot do programu jednej wartości) lub
* wskaźników.
Możemy przecież funkcji przekazać nie samą zmienną, a wskaźnik
do zmiennej (robiliśmy to już w przypadku funkcji scanf() -
dlatego, że samej zmiennej jeszcze nie było - miała zostać
dopiero pobrana, ale istniało już przeznaczone na tą nową
zmienną - zarezerwowane dla niej miejsce. Mogł zatem istnieć
wskaźnik wskazujący to miejsce). wskaźnik należy oczywiście
zadeklarować. Nasz program przybrałby zatem nową postać.
Wskaźnik do zmiennej nazwiemy *Argument.
[P048.CPP]
//Pamietaj o plikach naglowkowych !
void FUNKCJA( int *Argument); //Prototyp
int Zmienna;
void main()
{
clrscr();
printf("Stadium: \tZmienna Argument");
printf("\nStadium 1\t%d\tnie istnieje\n", Zmienna);
Zmienna = 7;
printf("Stadium 2\t%d\tnie istnieje\n", Zmienna );
FUNKCJA( &Zmienna); //Pobierz do funkcji ADRES Zmiennej
printf("Stadium 3\t%d", Zmienna);
// printf("%d", Argument);
// taka proba sie NIE UDA !
getch();
}
void FUNKCJA( int *Argument) // Definicja funkcji
{
printf("jestesmy wewnatrz funkcji\n");
printf("Nastapilo kopiowanie ADRESOW a nie zmiennej\n" );
printf("ADRESY:\t\t %X\t%X\n", &Zmienna, Argument);
getch();
*Argument = 10* *Argument + *Argument; /* DZIALANIE */
printf("\t\t%d\t%d\n", Zmienna, *Argument);
getch();
}
W linii /* DZIALANIE */ mnożymy i dodajemy to, co wskazuje
wskaźnik, czyli Zmienną. Funkcja działa zatem nie na własnej
kopii zmiennej a bezpośrednio na zmiennej zewnętrznej. Zwróć
uwagę na analogię w sposobie wywołania funkcji:
FUNKCJA( &Zmienna );
scanf( "%d", &Zmienna );
A jeśli argumentem funkcji ma być tablica? Rozważ przykładowy
program. Program zawiera pewną nadmiarowość (ku większej
jasności mechanizmów).
[P049.CPP]
# include
# include
SUMA( int k, int Tablica[] )
{
int i, SumTab=0;
for (i=0; i
SumTab = SumTab + Tablica[i];
printf("%d + ", Tablica[i]);
}
printf("\b\b= %d", SumTab);
return SumTab;
}
int suma=0, N; char Odp;
int TAB[10] = {1,2,3,4,5,6,7,8,9,10};
main()
{
clrscr();
do
{
printf("\n Ile wyrazow tablicy dodac ??? \n");
scanf("%d", &N);
if (N>10)
{ printf("TO ZA DUZO ! - max. 10");
continue;
}
suma = SUMA( N,TAB );
printf("\nTO JEST suma z progr. glownego %d", suma);
printf("\n Jeszcze raz ? T/N");
Odp = getch();
}
while (Odp!='N' && Odp!='n');
return 0;
}
Kompilacja w C++ jest wieloprzebiegowa (PASS 1, PASS 2), więc
definicja funkcji może być zarówno na początku jak i na końcu.
A oto następny przykład. Operując adresem - wskaźnikiem do
obiektu (tu wskaźnikami do dwu tablic) funkcja Wypelniacz()
zapisuje pod wskazany adres ciąg identycznych znaków. Na końcu
każdego łańcucha znaków zostaje dodany NUL - (\0) jako znak
końca. Taki format zapisu łańcuchów znakowych nazywa się ASCIIZ.
[P050.CPP]
void Wypelniacz(char *BUFOR, char Znak, int Dlugosc);
char TAB2D[5][10]; // Tablica 5 X 10 = 50 elementow
char TAB_1D[50]; // Tablica 1 X 50 = 50 elementow
int k;
main()
{
clrscr();
Wypelniacz( TAB_1D, 'X', 41); //Wypelnia X-ami
printf("%s\n\n", TAB_1D);
for (k=0; k<5; k++) Wypelniacz( TAB2D[k], 65+k, 9);
//ASCII 65 to 'A'; 66 to 'B' itd.
for (k=0; k<5; k++) printf("%s\n", TAB2D[k]);
getch();
return 0;
}
void Wypelniacz( char *BUFOR, char Znak, int Dlugosc )
{
int i;
for ( i=0; i<=(Dlugosc-1); i++) *(BUFOR+i) = Znak;
*(BUFOR+Dlugosc) = '\0';
}
Zwróć uwagę, że:
* NAZWA TABLICY (tu: TAB_1D i TAB2D) funkcjonuje jako wskaźnik
PIERWSZEGO ELEMENTU TABLICY.
FUNKCJE TYPU WSKAŹNIKOWEGO.
Funkcje mogą zwracać do programu zarówno wartości typu int, czy
float, jak i wartości typu ADRESU. Podobnie jak wskaźnik wymaga
deklaracji i podania w deklaracji na jakiego typu obiekty będzie
wskazywał, podobnie funkcja takiego typu wymaga w deklaracji
określenia typu wskazywanych obiektów. Wiesz już, że zależy od
tego tzw. krok wskaźnika. W przykładzie poniżej funkcja
Minimum() poszukuje najmniejszego elementu tablicy i zwraca
wskaźnik do tegoż elementu. Znając lokalizację najmniejszego
elementu możemy utworzyć nową tablicę, ale już uporządkowaną
według wielkości.
[P051.CPP]
int BALAGAN[10];
int PORZADEK[10]; // Tablica koncowa - uporzadkowana
int k, *pointer , MAX=10000 ;
int *Minimum(int Ilosc, int *TABL);
main()
{
clrscr();
printf("Podaj 10 liczb calkowitych od -10000 do 10000\n");
for (k=0; k<=9; k++) scanf("%d", &BALAGAN[k]);
printf("Po kolei: \n\n");
for ( k=0; k<=9; k++ )
{
pointer=Minimum(10, BALAGAN);
PORZADEK[k]=*pointer;
*pointer=MAX;
}
for(k=0; k<=9; k++) printf("%d ", PORZADEK[k]);
getch();
return 0;
}
int *Minimum( int Ilosc, int *TABL )
{
int *pMin; int i;
pMin=TABL;
for (i=1; i
if (*(TABL+i) < *pMin) pMin=(TABL+i);
}
return (pMin);
}
WSKAŹNIKI DO FUNKCJI.
W C++ możemy nie tylko podstawić daną w miejsce zmiennej (co
jest trywialną i oczywistą operacją we wszystkich językach
programowania), ale możemy także podstawiać na miejsce funkcji
stosowanej w programie tę funkcję, która w danym momencie jest
nam potrzebna. Aby wskazać funkcję zastosujemy, jak sama nazwa
wskazuje - WSKAŹNIK DO FUNKCJI. Aby uniknąć deklarowania funkcji
standardowych i być w zgodzie z dobrymi manierami nie zapomnimy
o dołączeniu pliku z prototypami. Deklarację
double ( *FUNKCJA ) (double);
należy rozumieć:
"Przy pomocy wskaźnika do funkcji *FUNKCJA wolno nam wskazać
takie funkcje, które
* pobierają jeden argument typu double float;
* zwracają do programu wartość typu double float. "
Dostępne są dla nas zatem wszystkie standardowe funkcje
arytmetyczne z pliku MATH.H (MATH pochodzi od MATHematics -
matematyka.)
[P052.CPP]
# include
# include
double NASZA( double ); //Deklaracja zwyklej funkcji
double (*Funkcja)(double ARG); //pointer do funkcji
double Liczba, Wynik; //Deklaracje zmiennych
int WYBOR;
main()
{
clrscr();
printf("Podaj Liczbe \n");
scanf("%lf", &Liczba);
printf("CO MAM ZROBIC ?\n");
printf("1 - Sinus \n");
printf("2 - Pierwiastek\n");
printf("3 - Odwrotnosc 1/x\n");
scanf("%d", &WYBOR);
switch(WYBOR)
{
case 1: Funkcja=sin; break;
case 2: Funkcja=sqrt; break;
case 3: Funkcja=NASZA; break;
}
Wynik=Funkcja(Liczba); // Wywolanie wybranej funkcji
printf("\n\nWYNIK = %lf", Wynik);
getch();
return 0;
}
double NASZA(double a)
{
printf("\n A TO NASZA PRYWATNA FUNKCJA\n");
if (a!=0) a=1/a; else printf("???\n");
return a;
}
main() - FUNKCJA SPECJALNA.
Ta książka siłą rzeczy, ze względu na swoją skromną objętość i
skalę zagadnienia o którym traktuje (autor jest zdania, że język
C to cała filozofia nowoczesnej informatyki "w pigułce") pełna
jest skrótów. Nie możemy jednak pozostawić bez, krótkiego
choćby, opisu pomijanego dyskretnie do tej pory problemu
PRZEKAZANIA PARAMETRÓW DO PROGRAMU.
Konwencja funkcji w języku C/C++ wyraźnie rozgranicza dwa różne
punkty widzenia. Funkcja pozwala na swego rodzaju separację
świata wewnętrznego (lokalnego, własnego) funkcji od świata
zewnętrznego. Nie zdziwi Cię więc zapewne, że i sposób widzenia
parametrów przekazywanych programowi przez DOS i sposób widzenia
"od wewnątrz" argumentów pobierabych przez funkcję main() jest
diametralnie różny.
To, co DOS widzi tak:
PROGRAM PAR1 PAR2 PAR3 PAR4 PAR5 [...][Enter]
funkcja main() widzi tak:
main(int argc, char **argv, char **env)
lub tak:
main(int argc, char *argv[], char *env[])
[???]CO TO JEST ???
________________________________________________________________
Zapisane zgodnie z obyczajami stosowanymi w prototypach funkcji:
int argc - liczba całkowita (>=1, bo parametr Nr 1 to nazwa
samego programu, za pośrednictwem której DOS wywołuje funkcję
main). Liczba argumentów - parametrów może być zmienna.
UWAGA: Język programowania wsadowego BPL przyjmuje nazwę
programu za parametr %0 a C++ uznaje ją za parametr o numerze
argv[0], tym niemniej, nawet jeśli nie ma żadnych parametrów
argc = 1.
argv - to tablica zawierająca wskaźniky do łańcuchów tekstowych
reprezentowanych w kodzie ASCIIZ - nazw kolejnych paramentrów, z
którymi został wywołany program.
Pierszy element tej tablicy to nazwa programu. Ostatni element
tej tablicy, o numerze argv - 1 to ostatni niezerowy parametr
wywołania programu.
env - to także tablica zawierająca wskaźniki do łańcuchów
znakowych w kodzie ASCIIZ reprezentujących parametry środowiska
(environment variables). Wskaźnik o wartości NUL sygnalizuje
koniec tablicy. W Turbo C++ istnieje także predefiniowana
zmienna globalna (::), przy pomocy której można uzyskać dostęp
do środowiska operacyjnego - environ .
________________________________________________________________
Przykłady poniżej przedstawiają sposób wykorzystania parametrów
wejściowych programu.
[P053.CPP]
# include "stdio.h"
# include "stdlib.h"
main(int argc, char *argv[], char *env[])
{
printf("Parametry srodowiska DOS: \n");
int i = 0;
do
{
printf("%s \n", env[i]);
i++;
};
while (env[i] != NULL);
printf("Lista parametrow programu: \n");
for(i=1; i<= argc - 1; i++)
printf("%s \n", argv[i]);
printf("Nazwa programu: \n");
printf("%s", argv[0]);
return 0;
}
Ponieważ C++ traktuje nazwę tablicy i wskaźnik do tablicy w
specjalny sposób, następujące zapisy są równoważne:
*argv[] oraz **argv
*env[] oraz **env
Nazwy argumentów argc, argv i env są zastrzeżone i muszą
występować zawsze w tej samej kolejności. Argumenty nie muszą
występować zawsze w komplecie. Dopuszczalne są zapisy:
main(int argc, char **argv, char **env)
main(int argc, char *argv[])
main(int argc)
main()
ale niedopuszczalny jest zapis:
main(char *env[])
Nawet jeśli nie zamierzamy wykorzystać "wcześniejszych"
parametrów - MUSIMY JE PODAĆ.
[Z]
________________________________________________________________
1. Spróbuj tak zmodyfikować funkcję Demo(), by liczba w formie
dwójkowej była pisana "od tyłu". Do cofania kursora w funkcji
printf użyj sekwencji \b\b.
2. Zinterpretuj zapis:
if (MIANOWNIK) printf("%f", 1/MIANOWNIK); else exit(1);
3 Spróbuj przeprowadzić rzutowanie typu we własnym programie.
4 Przekaż wartość w programie przykładowym posługując się
instrukcją:
return (10*Argument + Argument);
5 Rozszerz zestaw funkcji do wyboru w programie przykładowym.
________________________________________________________________