C i c++ wykłady, Jeszcze o funkcjach

background image

Jeszcze o funkcjach

Temat ważny,
ponieważ nie istnieje program w

C/C++ bez funkcji (choćby
main())

background image

Jeszcze o parametrach

przypomnienie sprzed tygodnia

W klasycznym C jedynym mechanizmem

wywołującym skutki nielokalne jest przekazanie

adresu (przez operator adresowy &)

Adres posłuży do zmiany komórek wskazanych

przez niego za pomocą L wyrażenia *adres

W C zastosowano odwołanie do

„niskopoziomowego rozumienia” zmiennej, tzn.

faktu, iż każda deklarowana zmienna posiada

miejsce w pamięci (adres) i zajmuje tę pamięć w

sposób charakterystyczny dla swego typu

background image

A co dodatkowo w C++?

Możliwe jest połączenie parametrów aktualnych z formalnymi

przez nazwę (referencję) a nie tylko przez wartość

Deklarowana zmienna nie tylko ma jakiś adres (wyznaczany

operatorem &), ale sama jej nazwa jest nośnikiem tego adresu

Na potrzeby połączeń parametrów, wystarczy aby w opisie

parametrów formalnych pojawił się operator & przed nazwą

parametru formalnego aby w wywołaniu można było użyć

samej nazwy argumentu a w treści funkcji samej nazwy

parametru

Oczywistą konsekwencją jest ograniczenie takiego argumentu

do nazwy zmiennej (tylko zmienna ma adres określony po

kompilacji) o identycznym typie co parametr. Wykluczone jest

użycie argumentu będącego wyrażeniem (wyrażenie ma

wartość, lecz nie ma adresu – powstaje na stosie)

Wprowadzenie tego mechanizmu połączeń unowocześnia

istotnie C++ względem C (na wzór innych języków

programowania strukturalnego)

background image

Złożone parametry funkcji

Tablice w parametrach

Jednowymiarowe

Wielowymiarowe

Struktury

Funkcje

background image

Tablice jednowymiarowe w
parametrach funkcji

Najczęściej spotykane jest przekazanie adresu.
Jest to podejście klasyczne (działa w C i C++)

Jest elastyczne i uniwersalne (nie wymaga
„zanurzenia” nagłówka funkcji w definicji tablicy)

Argumentem jest nazwa tablicy –NAZWA TABLICY
JEST ADRESEM JEJ PIERWSZEGO ELEMENTU

W ciele funkcji używa się modyfikacji tego adresu
np.x++ lub odliczania od niego np. *(x+i)

background image

Przykład ze statystyką –
wyznaczane są statystyki
randomizowanej tablicy

//nagłówki i definicje
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
const maxn = 100;
struct par_stat{
double srednia;
double odch;
double swob;
}; //definicja struktury – tzw. rekordu
void statystyka(double*,int,par_stat&);// par& to już

referencja C++

background image

Statystyka cd

// funkcja główna
main()
{
double dane[maxn]; //tablica lokalna
int i,n;
par_stat parametry;
clrscr();
randomize();
for (i=0;i<maxn;i++) dane[i]=(double)random(100);
statystyka(dane,maxn,parametry);
printf("srednia= %5.2f odchylenie= %5.2f NDF=%3.0f",
parametry.srednia,parametry.odch,parametry.swob);
getchar();
}

background image

Statystyka cd

//funkcja wyznaczająca statystyki
void statystyka(double *x,int ile, par_stat& w){
double suma=ile, sumax=0.0L, sumaxx=0.0L;
int j;
for (j=0;j<maxn;j++)
{sumax+=*x;
sumaxx+=*x**x;

x++;
}
w.srednia=sumax/suma; // kropka – operator

„wyłuskania”
w.odch=sqrt((sumaxx-sumax*sumax/suma)/(suma-1.0));
w.swob=suma-1.0;
}

background image

Tablice wielowymiarowe w
parametrach

Rzadko spotykane w C

Wymagają zanurzenia nagłówka w definicji

tablicy, lub samodzielnego operowania

adresami (dokonywania linearyzacji –

ponieważ niezależnie od liczby wymiarów,

tablica zajmuje kolejne komórki pamięci)

W C++ przekazanie przez referencję, często z

tzw. tablicą otwartą, wówczas w ciele funkcji

spotykana konstrukcja dostępu, to np.

*(*(x+i)+k)

gdzie x – adres początku,

i – numer wiersza,

k - kolumny

background image

Przykład trywialny – tworzenie
macierzy E

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
const maxn = 10;
typedef double mac[maxn][maxn];
void tworz(double [ ][maxn],int);//prototyp z tablicą otwartą
main(){
mac dane; int i,j,n;
clrscr(); tworz(dane,maxn);
for (i=0;i<maxn;i++)
{printf("\n");
for (j=0;j<maxn;j++) printf(" %5.1f",dane[i][j]); }
getchar();}
void tworz(double x[][maxn],int ile){
for (int j=0;j<ile;j++)
for (int k=0;k<ile;k++) *(*(x+j)+k)=j==k?1:0;
}

background image

Przykład z szukaniem
pierwiastka

Metoda Newtona

pozwala na rozwiązanie równania

f(x)=0

Załóżmy, że rozwiązanie y znajduje się w przedziale [a,b],

istnieją ciągłe f’ i f’’, f’’ nie zmienia znaku w [a,b]

Przybliżeniem rozwiązania jest x

i

, h

i

jest błędem

przybliżenia

Mamy zatem

f(x

i

+h

i

)=0

Rozwijając w szereg Taylora (w pierwszym przybliżeniu)

f(x

i

+h

i

)=f(x

i

)+h

i

f’(x

i

)

Pamiętając, że h

i

zostało obliczone w przybliżeniu, mamy

x

i+1

=x

i

-f(x

i

)/f’(x

i

)

W praktyce, przerywamy iteracje, gdy |x

i+1

-x

i

|<eps

background image

Interpretacja geometryczna –
kolejne przybliżenia w
przecięciu stycznych

background image

Zbudujmy program szukający
rozwiązania f(x)=sin(x)-1/2x=0

FUNKCJE
Wartości f dla dowolnych parametrów – f
Wartości f’ dla dowolnych parametrów – fp
Wyznaczenie rozwiązania – newt
I OCZYWIŚCIE main()

Dane to:
pierwsze przybliżenie
dokładność
maksymalna liczba iteracji (po jej
przekroczeniu uznajemy, że metoda nie jest
zbieżna)

background image

Istnieje kilka rozwiązań
to, które znajdziemy, zależy od
startu

background image

Czas na program

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double f(double),fp(double); //prototypy (i kilka na raz! Lista prototypów)
int newt(double*, double, int); // newt=0 zbieżny, 1 rozbieżny
main()
{
double x0,eps;
int n;
printf(” podaj przybl., dokładność i maks. l. iteracji \n”);
scanf(”%lf %lf %d”, &x0,&eps,&n); //uwaga na &
if(!newt(&x0,n,eps))
printf(”Rozwiązanie w %f \n”,x0);
else
printf(”Proces rozbieżny \n”);
getchar();
} // to koniec głównej funkcji

background image

A teraz czas na zdefiniowanie
zapowiedzianych prototypami
funkcji

// funkcja newt
int newt(double *x, int n, double eps)
{
double x1; // potrzeba dwóch x dla oceny
int i=0; // licznik iteracji
do
{
x1=-f(*x)/fp(*x); //poprawka
*x+=x1; //poprawiam rozwiązanie
if(fabs(x1)<eps) return 0; //osiągnięta dokładność
} while(i++<n); //przekroczono l.iteracji
return 1; //gdy nie osiągnięto

zadowalającej dokł.

} // koniec newt, 0 jest rozwiązanie, 1 brak

background image

I jeszcze funkcje z równania

double f(double x)
{
return sin(x)-0.5*x;
}
double fp(double x)
{
return cos(x)-0.5;
}

background image

Uwagi o programie

Funkcja newt, niestety sztywno rozwiązuje
wyłącznie równanie f(x)=0, pod warunkiem,
że funkcja opisana jest w f a jej pochodna w
fp

A przecież metoda Newtona jest ogólna (a
funkcja Newt NIE)

Gdyby funkcji newt można przekazać przez
parametry na czym ma działać (jakimi
funkcjami się posługiwać do wyznaczania
wartości funkcji i jej pochodnej)byłaby
uniwersalna

background image

Zmieniony program

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double f(double),fp(double); //prototypy
int newt2(double*, double, int, double (*)(double), double (*)(double)); //NOWOŚĆ

C++

// newt2=0 zbieżny, 1 rozbieżny
main()
{
double x0,eps;
int n;
printf(” podaj przybl. dokł. i maks. l. iteracji \n”);
scanf(”%lf %lf %d”, &x0,&eps,&n); //uwaga na &
if(!newt(&x0,n,eps,f,fp))
printf(”Rozwiązanie w %f \n”,x0);
else
printf(”Proces rozbieżny \n”);
getchar();
} // to koniec głównej funkcji

background image

Poprawiona funkcja newt

int newt2(double *x, int n, double eps,
double (*f1)(double), double (*f2)(double))
{
double x1;
int i=0;
do
{
x1=-(*f1)(*x)/(*f2)(*x);
*x+=x1;
if (fabs(x1)<eps) return 0;
} while(i++<n);
return 1;
}
//funkcje pozostają bez zmian
//gdy użyjemy innych funkcji, wystarczy podać to w wywołaniu

background image

Co warto wiedzieć o takich
parametrach?

Funkcje nie są zmiennymi

Identyfikator funkcji jest typu „wskaźnik do funkcji”
(i ma wartość adresu funkcji)

Można wykonać operacje na wskaźnikach do funkcji

Można zapisywać wskaźniki do funkcji w tablicach

Wskaźniki do funkcji można przekazywać jako
argumenty innych funkcji. Parametr jest wówczas
wskaźnikiem do funkcji z lokalną nazwą

Informacja o typie wartości zwracanej przez funkcję
musi być uwzględniona w deklaracji

background image

UWAGA

Między tablicami i funkcjami istnieje
analogia:

nazwa tablicy jest adresem jest początku

nazwa funkcji jest jej wskaźnikiem

Do funkcji nie można przekazać tablicy tylko
jej adres

Do funkcji nie można przekazać funkcji tylko
wskaźnik do niej

background image

Bardziej złożone typy
(na struktury przyjdzie czas)

int f[]; //tablica o elementach int

int *f[]; //tablica wskaźników do int

int f(); //funkcja zwracająca wartość int

int *f(); //funkcja zwr. wskaźnik do int

int (*f)(); //wskaźnik do funkcji
zwracającej int

int *(*f)(); // wskaźnik do funkcji zwr. wsk.
do int

int (*(f[]))(); //tablica wskaźników do funkcji
zwr. int

background image

Pliki

W stylu C

background image

W stdio dostarczony jest zestaw funkcji
realizujących operacje we/wy, które pozwalają
zapisać i odczytać dane ze zbiorów lub
urządzeń.

ANSI C stosuje tzw. strumienie do zaznaczania

abstrakcyjnego portu, poprzez który dane mogą

przepływać jedno lub dwukierunkowo.

Strumień ANSI C jest uważany za konstrukcję

niskiego poziomu, na którą jest nakładany

bardziej złożony system plikowy.

Strumienie są reprezentowane przez zmienne

typu FILE. Konstrukcja FILE jest biblioteczną.

Funkcje strumieniowe traktują zbiór danych jako

ciąg pojedynczych znaków, które mogą być

później grupowane w formatowanych

operacjach we/wy.

background image

Jak skorzystać z pliku (w C)?
Kilka kroków

(jak w TP, Moduli i

innych)

Zadeklarowanie wskaźnika do FILE

„Otwarcie” pliku – identyfikacja
zbioru/portu, określenie dopuszczalnych
operacji, skojarzenie wskaźnika FILE* z
danymi
fopen

Operacje transmisji z/do pliku
różne funkcje z biblioteki stdio

Zamknięcie pliku
fclose

background image

Funkcja

Opis

Wartość

zwracana

FILE *fopen

(const char

*namefile,

const char

*mode)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 int fclose

(FILE *stream)

 

Funkcja otwiera plik i wiąże z tym plikiem

strumień.

namefile - nazwa pliku

mode - tryb ustawienia pliku

r - do czytania. Zbiór musi istnieć

w - otwiera pusty zbiór do zapisu, jeśli

plik istnieje kasuje jego zawartość

a - do zapisu na końcu zbioru. Jeśli plik

nie istnieje tworzy nowy

r+ - otwiera istniejący plik do zapisu i

odczytu

w+ - otwiera pusty plik do zapisu i

odczytu. Istniejący plik kasuje

a+ - otwiera do odczytu i zapisu na końcu

pliku. Jeżeli plik nie istnieje to go

tworzy.

b - otwiera plik w trybie binarnym

a i a+ - zapisuje zawsze na końcu mimo

użycia funkcji pozycjonującej fseek()

w i w+ - zawsze kasuje istniejący plik

 

zamyka strumień określony parametrem

wywołania funkcji.

wartości funkcji: 0-poprawne zamknięcie,

EOF - błąd operacji

Funkcja

otwiera plik i

wiąże z tym

plikiem

strumień.

 

background image

Przykład

#include<conio.h>

#include<stdio.h>

int main() {

char *nazwa_pliku = "tekst.txt"; //w domyślnej lokalizacji

FILE *plik;

clrscr();

if (plik = fopen (nazwa_pliku, "rt")){

printf ("poprawne otwarcie pliku tekstowego do

czytania\n");

fclose(plik);

}

else

printf ("błąd otwarcia pliku do czytania\n");

getch();

}

background image

Nazwy predefiniowane

Nazwa

Zastosowanie

stdin strumień wejściowy (konsola)
stdoutstrumień wyjściowy (konsola)
stderr strumień komunikatów błędów (konsola)
stdaux

strumień pomocniczy (konsola)

stdprn

strumień drukarki

Zdefiniowane stałe

EOF – znacznik końca pliku (-1)
NULL – wskaźnik zerowy
BUFSIZ – bieżący rozmiar bufora

background image

Podstawowe funkcje obsługi
transmisji:
znaki i łańcuchy

Operowanie znakami: fgetc(…); fputc(…);

int fgetc(FILE *stream) czyta znak ze

strumienia stream jako unsigned char i

przekształca do int . Zwraca znak czytany lub

EOF, jeśli powstał błąd lub napotkano EOF.

Operowanie łańcuchami:fgets(…); fputs(…);

 char *fgets(char *string, int n, FILE

*stream) odczytuje ze strumienia stream ciąg

znaków aż do:- pierwszego znaku '\n'

(włącznie)- do końca strumienia- lub, gdy

przeczytano n-1 znakówi wstawia je do stringu

dołączając na końcu '\0'  Zwraca string lub,

NULL jeśli powstał błąd lub napotkano EOF. 

background image

#include<conio.h>
#include<stdio.h>
int main() {
char *nazwa_pliku = "tekst.txt"; char znak, str[20],
buf[100]; FILE *plik;
clrscr();
if (plik = fopen (nazwa_pliku, "w+t"))
printf ("poprawne otwarcie pliku do zapisu i odczytu");
else { printf ("błąd otwarcia pliku"); return 1; }
printf ("\npodaj tekst: ");
gets (str);
fputs (str, plik);
rewind (plik);
printf ("\ntekst odczytany z pliku znak po znaku : ");
while ((znak=fgetc(plik))!=EOF) printf ("%c", znak);
getch();
}

background image

Podstawowe funkcje obsługi
transmisji:
formatowana transmisja

Funkcja

Opis

Wartość zwracana

 int

fprintf

(FILE

*stream, const

* format,...);

 

 Funkcja formatuje i

wpisuje dane do

strumienia określonego

parametrem stream.

Zwraca liczbę

zapisanych znaków lub

-1 gdy wystąpił błąd. 

 int fscanf

(FILE

*stream, const

* format,...);

 

Funkcja czyta dane ze

strumienia określonego

parametrem stream, od

bieżącej pozycji, i

umieszcza w miejscu

pamięci wskazanym w

parametrze

nieustalonym.

Zwraca liczbę

przepisanych danych

wejściowych, gdy

wystąpił błąd:0

EOF po napotkaniu

końca zbioru

background image

Pliki binarne

Funkcja

Opis

Wartość zwracana

 

size_t fread

(void *buf, size_t

size, size_t n, FILE

*stream)

 

Odczytuje ze

strumienia stream, co

najwyżej n obiektów o

rozmiarze size bajtów i

zapamiętuje je w bloku

pamięci wskazywanym

przez parametr buf.

 

Zwraca liczbę

przeczytanych

obiektów ( nie

bajtów), w

przypadku błędu lub

końca pliku to

zwraca liczbę

mniejszą od n.

 

size_t fwrite (const

void *buf, size_t

size, size_t size,

FILE *stream)

 

 

Wysyła do strumienia n

obiektów o rozmiarze

size pobranych z

obszaru pamięci

wskazywanego

parametrem buf.

 

Zwraca liczbę

wysłanych obiektów,

w przypadku błędu

{zwraca liczbę

mniejszą od n.

background image

Sterowanie wskaźnikiem
pozycji

int

fseek

(FILE

*stream,

long offset,

int pos)

 

 

 

 

Funkcja przesuwa

wskaźnik pozycji w pliku

do miejsca oddalonego o

offset (typu long) bajtów

od pozycji pos:

SEEK_SET- początek

pliku

SEEK_CUR - bieżąca

pozycja

SEEK_END - koniec

zbioru

Zwraca 0 jeśli OK,

lub != 0 jeśli błąd.

Uwaga!!!

Dla plików

tekstowych fseek

ma ograniczone

użycie, bo zamiana

CR i LF na jeden

znak może

spowodować, że

fseek() da

nieoczekiwane

rezultaty.

 

void rewind(fp);  Przesuwa wskaźnik pozycji w

pliku na jego początek. 

background image

Sterowanie wskaźnikiem
pozycji

 long

ftell(FILE

*stream);

 

Podaje bieżącą

pozycję wskaźnika

w pliku, liczoną

jako przesunięcie

względem początku

zbioru.

Zwraca -1L

jeśli błąd, w

przeciwnym

wypadku

wartość

niezerową 

background image

sterowanie

int

fgetpos(fp

, pos)

 

Zapamiętuje w pos

bieżącą pozycję

wskaźnika

strumienia.

Zwraca, 0 gdy

poprawnie

zakończona lub

!= 0 gdy błąd.

 int

fsetpos(fp

, pos)

Ustawia wskaźnik

pozycji w pliku wg

parametru pos.

Zwraca 0 gdy

poprawnie

zakończona lub

!= 0 gdy błąd.

background image

Biblioteka strumieni w C++

Biblioteka została stworzona jako hierarchia
klas zadeklarowanych w wielu plikach
nagłówkowych

iostream.h – podstawowy

io.h – deklaracje na najniższym poziomie

istream.h, ostream.h – podstawowe klasy
we/wy

fstream.h - zawiera ifstream.h i ofstream.h –
podstawowe operacje klas strumieni

background image

Ogólne funkcje we/wy
strumienia
(metody klas strumieniowych)

funkcja void open – umożliwia otwarcie pliku

strumienia do zapisu/odczytu/dopisywania

oraz określenie, czy operacje we/wy

prowadzone są na tekście czy na danych

binarnych

funkcja void close – beparametryczna,

zamyka strumień

sprawdzanie poprawności operacji, funkcje

int good (zero – błąd operacji)

int fail (zero – poprawna operacja)

Przeciążony operator ! Stosowany do zmiennych

strumienia dla określenia błędu

background image

Sekwencyjne strumienie we/wy
dla plików tekstowych

Funkcje i operatory związane z plikami

tekstowymi są proste

Operator << umieszczający dane w
strumieniu (łańcuchy i znaki)

Operator >> pobierający dane ze
strumienia

Funkcja getline – wczytywanie łańcuchów
ze strumienia (z podaną maksymalną
liczbą znaków i ogranicznikiem)

background image

Przykład: przepisanie pliku
wej.txt do wyj.txt z zamianą
znaków ‘a’ na ‘A’

#include <iostream.h>
#include <fstream.h>
#include <conio.h>
int main()
{ fstream plikWe, plikWy;
char linia[129]; clrscr();
plikWe.open(”wej.txt”,ios::in);
if(!plikWe) {cout<<”Brak pliku”;return 1;}
plikWy.open(”wyj.txt”,ios::out);
while (plikWe.getline(linia,128)){
for (int i=0;linia[i]!=‘\0’;i++) if (linia[i]==‘a’)linia[i]=‘A’;
plikWy<<linia<<‘\n’; cout<<linia<<‘\n’;
}
plikWe.close(); plikWy.close();
getch(); return 0;
}

background image

Strumienie dla plików
binarnych

Funkcja write wysyła bajty we wskazanej

liczbie z bufora do strumienia wyjściowego

(przypomina Pascalowy BlockWrite)

Funkcja read pobiera bajty we wskazanej

liczbie do bufora ze strumienia wejściowego

(przypomina Pascalowy BlockRead)

Funkcja seekg pozwala ustalić przeniesienie

wskaźnika strumienia do dowolnego,

dozwolonego położenia (także względem:

początku, bieżącej pozycji lub końca)


Document Outline


Wyszukiwarka

Podobne podstrony:
Analiza matematyczna Wykłady, GRANICE FUNKCJI
wyklad Mes funkcje ksztaltu, Budownictwo, Semestr V, Budownictwo komunikacyjne 1, most5
FUNKCJA WYKŁADNICZA I LOGARYTMICZNA, FUNKCJA WYKŁADNICZA I LOGARYTMICZNA
Funkcja wykładnicza i logarytmiczna, Funkcja wykładnicza i logarytmiczna 2, zadania
Wykład 2 PT Funkcje i dysfunkcje turystyki
wykład 4 procedury, funkcje, sekwencje, paczki, wyzwalacze
wyklad9 szablony funkcji
Funkcja wykładnicza i logarytmiczna, Funkcja wykładnicza i logarytmiczna 1, zadania
8 Zadania do wykladu Granica funkcji Ciaglosc funkcji 1
wykład 2 Struktura, funkcje i właściwości mięśni szkieletowych
Funkcja wykładnicza i logarytmiczna Funkcja wykładnicza i logarytmiczna 2, odpowiedzi
Analiza matematyczna. Wykłady GRANICE FUNKCJI
05 Wyklad 5. Rozkład funkcji zmiennej losowej i dwuwymiarowe zmienn e losowe

więcej podobnych podstron