• Nenhum resultado encontrado

PROGRAMTERVEZÉS KICSIBEN

No documento C_Nyelv_es_Programozas_kinyomtatva_Debrecen (páginas 169-175)

A FELHASZNÁLÓ ÁLTAL DEFINIÁLT TÍPUSOK

9. FÜGGVÉNYEK 161 6 A return utasítás az eredmény értékét ( Rvalue ) téríti vissza Ezért

9.4. PROGRAMTERVEZÉS KICSIBEN

int i, j; FILE * f;

f = fopen("matrix.be", "r"); fscanf(f, "%d%d", &n, &m);

for(i = 0; i < n; i++) for(j = 0; j < m; j++) fscanf(f, "%d", &a[i][j]); fclose(f); } void kiiras() { int i, j; FILE * f; f = fopen("matrix.ki", "w"); for(i = 0; i < n; i++) { for(j = 0; j < m; j++) fprintf(f, "%5d", a[i][j]); fprintf(f, "\n"); } fclose(f); } void sor_rendezes(int k) { int i, j; for(i = 0; i < m - 1; i++) for(j = i + 1; j < m; j++)

if (a[k][i] > a[k][j]) csere(&a[k][i], &a[k][j]); }

void csere(int * p1, int * p2)

{

int v;

v = *p1; *p1 = *p2; *p2 = v; }

A fenti programtervezés indoklása

1. Mivel a függvények globális változókon keresztül jutnak hozzá n- hez,m-hez ésa-hoz, ezért kevésbé általánosak. Például abeolvasas

függvény nem lenne alkalmas egy mátrix adatainak p (sor), q (os- zlop) ésb (elemek) változókba való beolvasására. De ebben a fela- datban erre nincs is szükség.

2. A fentiekkel ellentétben, mivel a sor_rendezes paraméteren keresztül kapja meg a rendezendő sor indexét, ezért az a tömb bármelyik sorának rendezésére alkalmas, és erre szükség is van. 3. Szükségtelen lett volna a sorindexet cím szerint átadni a

Ezzel ellentétben a csere függvénynek magukra az elemekre van szüksége a felcserélésükhöz.

4. Ha kényelemből (hibásan) globálisnak definiáltuk volna az i és j

változókat, hogy ne kelljen minden függvényben külön deklaráljuk, akkor a main függvény i ciklusváltozóját „elrontotta” volna a

sor_rendezes függvény.

5. Következésképpen, bár a globális változók használata kényelmes- nek tűnik, általában kerülendők. Célszerű előnybe helyezni a paraméterátadást és a lokális változókat. Sőt, egyes pedagógusok azt ajánlják a programozni tanulóknak, hogy teljességgel kerüljék a globális változók használatát. Ez egészséges programozói stílus kialakításához vezet, amely többek között azt is magába foglalja, hogy olyan függvényeket írunk, amelyek bármely alkalmazásban értékesí- thetők. Továbbá felkészít nagy projektek „csapatmunkával” való meg- valósítására. A programozói csapatmunka egyik alapelve, hogy a pro- jekt függvényei kizárólag paraméterlistán keresztül kommunikálnak, és csak lokális változókat használnak.

Következzék hát a feladat megoldása globális változók nélkül:

#include <stdio.h>

void beolvasas(int *, int *, int (*)[50], char *);

void kiiras(int, int, int (*)[50], char *);

void sor_rendezes(int, int, int [][50]);

void csere(int *, int *); main()

{

int n, m, a[50][50], i;

beolvasas(&n, &m, a, "matrix.be");

for(i = 0; i < n; i++) sor_rendezes(i, m, a); kiiras(n, m, a, "matrix.ki");

return 0; }

void beolvasas(int* pn,int* pm,int(*a)[50],char*allomany)

{ int i, j; FILE * f; f = fopen(allomany, "r"); fscanf(f, "%d%d", pn, pm); for(i = 0; i < *pn; i++) for(j = 0; j < *pm; j++) fscanf(f, "%d", &a[i][j]); fclose(f);

9.4. PROGRAMTERVEZÉS KICSIBEN 175

}

void kiiras(int n, int m, int (*a)[50], char * allomany) { int i, j; FILE * f; f = fopen(allomany, "w"); for(i = 0; i < n; i++) { for(j = 0; j < m; j++) fprintf(f, "%5d", a[i][j]); fprintf(f, "\n"); } fclose(f); }

void sor_rendezes(int k, int m, int a[][50]) {

int i, j;

for(i = 0; i < m - 1; i++)

for(j = i + 1; j < m; j++)

if (a[k][i] > a[k][j]) csere(&a[k][i], &a[k][j]); }

void csere(int * p1, int * p2) {

int v;

v = *p1; *p1 = *p2; *p2 = v; }

Megjegyzések ezen második megoldáshoz:

1. A beolvasas függvény most már alkalmas lenne egy mátrix adatainak a beolvasására, bármilyen nevű állományból bármilyen nevű memóriaváltozókba. Ugyanez igaz a kiiraséssor_rendezés

függvényekre is.

2. Abeolvasasfüggvénynek nyilván cím szerint kellett átadnunk azn,

mésaváltozókat, hiszen a beolvasásnak ezekbe kellett megtörténnie és nem a másolatukba. Azért nem kellett külön jelezni az a tömb cím szerint való átadását, mert, amint említettük, a C nyelvben a tömbök kivételesen implicite cím szerint adódnak át. A kiiras

és sor_rendezes függvények esetében elégséges volt n és m érték szerinti átadása.

3. Úgy is mondhatnánk, hogy a main függvény a saját n-jét, m-jét ésa-ját bocsátja a cím szerinti paraméterátadás által a beolvasas

függvény rendelkezésére, míg a másik kettőnek csupánnésmértékét adja oda.

Ha dinamikusan szeretnénk helyet foglalni egy tömbnek, ezt a felada- tot is kioszthatjuk egy függvénynek.

Aletrehoz_1egynelemű egydimenziósinttípusú tömböt hoz létre.

int * letrehoz_1(int n) { int * tp; tp = (int*)malloc(n * sizeof(int)); return tp; }

Hogyan használható a fenti függvény?

int * a;

a = letrehoz_1(n); /*a tömbi-edik elemére való hivatkozás:

a[i] */

A letrehoz_2 n x m-es float típusú tömböknek foglal helyet. Pon- tosabban, egy n elemű float-pointer tömböt hoz létre, amelynek minden eleme egy m eleműfloat-tömbre mutat.

float ** letrehoz_2(int n, int m) {

float ** tpp; int i;

tpp = (float**)malloc(n * sizeof(float*)); for(i = 0; i < n; i++)

tpp[i] = (float*)malloc(m * sizeof(float)) return tpp;

}

Kétdimenziós tömb létrehozása aletrehoz_2 segítségével:

float ** b;

b = letrehoz_2(n, m); /* b[i][j], a tömb i-edik sorának

j-edik eleme*/

Amíg aza tömb törölhető afree(a); utasítással, addig b törlését az alábbi függvény valósíja meg:

void torol_2(float ** b, int n) { int i;

for(i = 0; i < n; i++) free(b[i]) free(b);}

9.5. FÜGGVÉNYPOINTEREK 177

9.5. Függvénypointerek

Egy függvény típusán eddig a visszatérési értékének típusát értettük. Azonban, ha egészen pontosak akarunk lenni, akkor ez magába foglalja még a paraméterek számát és típusát is.

Legyen a következő függvénydeklaráció:

int f(char, float);

fegy char ésfloatparaméterű int-függvény. f típusa leírva:

int (char, float).

Hogyan definiálunk egy függvénypointert? Például így:

int (*fp)(char, float);

fp, egycharésfloatparaméterűint-függvénypointer.fptípusa leír- va:int(*)(char,float).

typedef-et használva nevet adhatunk egy függvénytípusnak vagy függvénypointer-típusnak.

Példa:

typedef float FV_TIP (double, int**, char[]); typedef int (*FV_PTR_TIP) (int, int);

FV_TIP fuggv; /* függvénydeklaráció, prototípus */ FV_PTR_TIP f_ptr; /* függvénypointer-definiálás */

Egy függvény neve az illető függvénytípusú pointerkonstansként is felfogható, amely magára a függvényre mutat. Tehát f egy int(*) (char,float)típusú függvénypointer-konstansnak is tekinthető. Ezért az

f, illetve *fhivatkozások egyenértékűek.

Az fp pointer megkaphatja bármely char és int paraméterű int- függvény címét.

Példa:

fp = &f; ezzel ekvivalens:fp = f;

Az érem másik oldala az, hogy bármely függvénypointer felfogható annak a függvénynek a neveként, amelyre mutat. Így az fp és *fp hi-

vatkozások is egyenértékűek.

Az ffüggvényt a következő módokon lehet meghívni:

int x; char a; float b;

...x = f(a, b); ... /*klasszikus forma */

...x = (*fp)(a, b); ... /* pointeren keresztül*/

...x = (*f)(a, b); ... /* a nevén mint pointeren keresz- tül*/

Megjegyzés. Mivel egy függvény típusa – az adattípusokkal ellentét- ben – nem határozza meg kódjának memóriaméretét, ezért a függvény- pointerekre nem érvényesek a címaritmetika műveletei. Például egy füg- gvénypointerhez nem adható hozzá egy egész szám, vagy az azonos típusú függvénypointerek nem vonhatók ki egymásból.

9.6. Függvény paraméterként való átadása függvénynek

A függvényátadás mindig cím szerint történik.

9.4. feladat. Írjunk egy olyan rendező függvényt, amely rendezi egy tömb elemeit, függetlenül ezek típusától.

Megoldás: Mivel a rendezéshez szükséges összehasonlítás típusfüggő, ezért minden típusra írunk egy összehasonlító függvényt, amelyet majd átadunk a rendező függvénynek. A rendező függvény paraméterként a tömb címét, elemeinek számát és méretét, valamint az összehasonlító függvényt fogja megkapni. Azért, hogy a különböző összehasonlító függvények azonos típusúak legyenek, az összehasonlítandó elemek címét mint const void

pointereket fogják megkapni.

#include<sdtlib.h>

#include<string.h>

int int_cmp(const void * p1, const void * p2) { return * (int *) p1 - * (int *) p2; }

int float_cmp(const void * p1, const void * p2) { if (* (float *) p1 == * (float *) p2) return 0;

else if (* (float *) p1 < * (float *) p2) return -1;

else return 1;}

void sort(void*v,int nr,int size,int(*p_cmp)(const void*,const void*)) {

int i, j; void *pv, *pi, *pj;

pv = malloc(size); /* a veder szerepét fogja betölteni */

for(i = 0, pi=v; i < nr - 1; i++, pi=(char*)pi+size) {

for(j = i + 1,pj=(char*)pi+size; j < nr; j++,pj=(char*)pj+size) {

if (p_cmp(pi, pj) > 0) {

memcpy(pv, pi, size); memcpy(pi, pj, size);

9.7. VÁLTOZÓ PARAMÉTERSZÁMÚ FÜGGVÉNYEK 179

No documento C_Nyelv_es_Programozas_kinyomtatva_Debrecen (páginas 169-175)

Documentos relacionados