erakusle etiketadun mezuak erakusten. Erakutsi mezu guztiak
erakusle etiketadun mezuak erakusten. Erakutsi mezu guztiak

2025(e)ko martxoaren 21(a), ostirala

12. jarduera (III) | Erakusleak eta funtzioak


ZER DAKIDAN:
Erakusle kontzeptua menperatzen dut.



ZER IKASIKO DUDAN:
Funtzio bati array bat pasatzearen ordez, arrayaren erakuslea pasarazi ahal zaiola ikasiko dut.


Array bat funtzioari pasatu beharrean erakusle bat pasatu

Jarraian ematen den programan fNotak[] arraya ez da funtzioen parametroa, bere ordez float bati seinalatzen dion erakuslea pasatzen da, float hori fNotak[] arrayaren lehen elementuaren helbidea izango da, hots, afNotak aldagaia.

Hona hemen funtzioen prototipoak eta funtzioei dagozkien deiak:

void NotakSartu(float *, int *);     // erreal bat eta oso bat, biak irteerakoak                                           
void NotakIkusi(const float *, int); // erreal bat eta oso bat, biak sarrerakoak
NotakSartu(afNotak, &iZenbatIkasle); // aldagai-erakuslea eta helbidea (irteerak)                                           
NotakIkusi(afNotak, iZenbatIkasle);  // konstante-erakuslea eta balioa (sarrerak)

NotakSartu() funtziora eta NotakIkusi() funtziora erakusleak pasatzen dira.

/* 12c1-Erakusleak-Arrayak: arraya erakusle bezala funtzioetan */

// Errealekin lan eginez. Array bat datuz bete funtzio batean
// eta arrayaren edukia pantailaratu erakusle bat erabiliz.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define IKASLE_MIN 1
#define LUZERA_MAX 15   // ikasle kopuru maximoa

void NotakSartu(float *, int *);
void NotakIkusi(const float *, int);

int main()
{
    float afNotak[LUZERA_MAX];
    int iZenbatIkasle;

    printf("\n");
    printf("\n\t Zerrenda auzaz betetzen zenbaki errealez");
    printf("\n\t ----------------------------------------\n");

    NotakSartu(afNotak, &iZenbatIkasle);
    NotakIkusi(afNotak, iZenbatIkasle);

    printf("\n");
    return 0;
}


void NotakSartu(float *p_fNota, int *iZenbatIkasle)  // lehen parametroa irterakoa da
{                                                    // bigarren parametroa irteerakoa da
    int iKont;
    float fKalifikazioa;

    srand(time(NULL));

    *iZenbatIkasle = rand() % (LUZERA_MAX - IKASLE_MIN + 1) + IKASLE_MIN;  // 1 eta 15 arteko balioa
    printf("\n\t *iZenbatIkasle = %d", *iZenbatIkasle);

    printf("\n");
    for (iKont=0; iKont < *iZenbatIkasle; iKont++)
    {
        fKalifikazioa = ((float)rand()/(float)(RAND_MAX)) * (10.0 - 0.0);
        // printf("\n\t %2d. ikaslearen nota: %.2f", iKont+1, fKalifikazioa);
        *(p_fNota + iKont) = fKalifikazioa;
    }
}


void NotakIkusi(const float *p_fNota, int iZenbatIkasle)  // bi parametroak sarrerakoak
{
    int iKont;

//  afNotak[3] = 3.33;   // babestuta dago

    printf("\n");
    printf("\t     Posizioa     Ikaslea     Nota\n");
    printf("\t     --------     -------     ----\n");
    for (iKont=0; iKont < iZenbatIkasle; iKont++)
    {
        printf("\t %9d %11d %11.2f\n", iKont, iKont+1, *(p_fNota + iKont));
    }
}


Erakusle biren areko kenketa

Jarraian ematen den adibidean programan strchr() funtzioaren adibide bat ematen da, ikusi nola IzenaZenbakiaBanatu() funtzioari sDatua eta sIzena arrayen erakusleak pasatzen zaizkion parametro bezala. Ikusi ere, arrayen helbideen artean kenketaren eragiketa aritmetikoa egin daitekeela kate baten luzera lortze aldera.

Adibide honen gakoa dago strchr() funtzioak itzultzen duen emaitzan, hots, strchr() funtzioak itzultzen helbidearen erakuslean: NULL karakterea aurkitzen ez badu eta karakterearen helbidea eta indizea baldin eta aurkitzen badu.

/* 12c2-Erakusleak-Arrayak.cbp */

// strchr(katea, karak) funtzioak karak karakterea bilatzen du kate katean.
// Aurkitzen badu, karakterearen lehen agerpenaren erakuslea itzultzen du.
// Ez badu aurkitzen null erakuslea itzultzen du. Bilatutako karkaterearen
// posizioa zehazteko helbideen arteko kenketa egingo da.

#include <stdio.h>
#include <stdlib.h>   // atof() funtziorako
#include <string.h>   // strchr(), strlen(), strcpy() eta strncpy() funtzioetarako
#include <conio.h>    // getch() eta getche() funtzioetarako

#define MAXIMOA 21    // katea mugatzeko konstantea,
                      // 20 karaktere + null mugatzailea

int main()
{
    char sKatea[MAXIMOA] = "Kaixo mundua!";  // 13 letra + null mugatzailea
    char cKarakterea;
    char *erakuslea;

    printf("\n");
    printf("\n Luzera=%d      sKatea=|%s|", (int)strlen(sKatea), sKatea);

    printf("\n");
    printf("\n Bilatu nahi den karaktere eman (adibidez: a edo u edo k): ");
    cKarakterea = getche();

    erakuslea = strchr(sKatea, cKarakterea);
    printf("\n Bilaketaren emaitza: ||%s||", erakuslea);
    if (erakuslea != NULL)
        printf("\n Bilaketaren posizioa: |%d|", (int)(erakuslea - sKatea));

    printf("\n\n");
    return 0;
}

Adibide honetan Ana#7.25 datua kate batean gorderik dago, katearen hasieran izena eta amaieran zenbakia, bien artean # karakterea banatzaile bezala. Programak hasierako katea banatzen du izena eta zenbakia lortuz.

/* 12c3-Erakusleak-Arrayak.cbp */

// "Ana#7.25" katetik abiatu banaketa burutu: zenbakia alde
// batetik eta zenbakia beste aldetik.

#include <stdio.h>
#include <stdlib.h>   // atof() funtziorako
#include <string.h>   // strchr(), strlen(), strcpy() eta strncpy() funtzioetarako

#define MAXIMOA 21    // katea mugatzeko konstantea,
                      // 20 karaktere + null mugatzailea

void IzenaZenbakiaBanatu(char *sDatua, char *sIzena, float *fZbk);

int main()
{
    char sDatua[MAXIMOA] = "Ana#7.25";  // 8 karaktere + null mugatzaile
    char sIzena[MAXIMOA];
    float fZbk;

    printf("\n");
    printf("\n Luzera=%d      sDatua=|%s|\n", (int)strlen(sDatua), sDatua);

    IzenaZenbakiaBanatu(sDatua, sIzena, &fZbk);
    printf("\n sIzena=||%s||    (fZbk+1.11)=%.2f", sIzena, fZbk+1.11);

    printf("\n\n Edozein tekla sakatu exekuzioa amaitzeko...\n\n");
    return 0;
}


void IzenaZenbakiaBanatu(char *sDatua, char *sIzena, float *fZbk)
{
    char *TraolaErak;
    char sLaguntzaile[MAXIMOA];

    printf("\n                ---sDatua=|%s|---", sDatua);
    TraolaErak = strchr(sDatua, '#');
    printf("\n            ---TraolaErak=|%s|---", TraolaErak);
    printf("\n     ___(helbidea) sDatua=%li___", (long)sDatua);
    printf("\n ___(helbidea) TraolaErak=%li___", (long)TraolaErak);
    printf("\n     ___TraolaErak-sDatua=%li (karaktere kopurua)___\n", (long)(TraolaErak - sDatua));
    if (TraolaErak != NULL)
    {
        strncpy(sIzena, sDatua, TraolaErak - sDatua);
        sIzena[TraolaErak - sDatua] = '\0';
        printf("\n                ---sIzena=|%s|---\n", sIzena);
        printf("\n            ---TraolaErak=|%s|---", TraolaErak);
        printf("\n          ---TraolaErak+1=|%s|---", TraolaErak+1);
        printf("\n          ---TraolaErak-1=|%s|---\n", TraolaErak-1);
        strcpy(sLaguntzaile, TraolaErak + 1);
        *fZbk = atof(sLaguntzaile);
    }
}






  • 12c1-Jarduera_Erakusleak.cbp | main.c
  • 12c2-Jarduera_Erakusleak.cbp | main.c


 

12. jarduera (II) | Erakusleak funtzioen parametro bezala


ZER DAKIDAN:
Erakusle kontzeptua menperatzen dut.



ZER IKASIKO DUDAN:
Funtzio bati pasarazten zaizkion parametroak erakusleekin lotuta daudela ikasiko dut.

Balioak pasatzen funtzioari

Parametroak nola pasatzen zaizkion funtzioari berrikusteko bi programa idatz ditzagun. Lehen programan, bi aldagaien balioak main() programa nagusian finkantzen dira eta BiDatuPantailaratu() izeneko funtzioan pantailaratzen dira. Bigarren programan, bi aldagaien balioak BiDatuHartu() izeneko funtzioan finkantzen dira eta main() programa nagusian pantailaratzen dira.

Hau garrantzitsua da:

float *p; bitartez erakusle-aldagaia deklaratu ondoren, *p notazioari esker adierazten da p erakusleak zenbaki erreal bati seinalatzen diola.

float fZbk; bitartez zenbakizko aldagaia deklaratu ondoren, &fZbk notazioari esker adierazten da fZbk aldagaiaren helbidea.


Lehen programan, bi aldagaien balioak programa nagusian finkantzen direnez datu horiek BiDatuPantailaratu() funtzioan sarrerakoak dira eta balioz pasatzen dira BiDatuPantailaratu() funtzioak pantailan idatz ditzan.

/* 12b1-Erakusleak-Parametroak: funtzio baten parametroak sarrerakoak direnean */

// iZbk_1 eta iZbk_2 aldagaiek balioak main() programa nagusian hartzen dituzte
// iZbk_1 eta iZbk_2 aldagaien balioak BiDatuPantailaratu() funtzioak prozesatezn ditu

#include <stdio.h>

void BiDatuPantailaratu(int, int);

int main() 
{
	int iZbk_1 = 3;   // iZbk_1 zenbaki-aldagaiaren deklarazioa eta hasieraketa
	int iZbk_2 = 4;   // iZbk_2 zenbaki-aldagaiaren deklarazioa eta hasieraketa

	printf("\n");

    BiDatuPantailaratu(iZbk_1, iZbk_2);
    printf("\n       main() programa nagusian: Lehen kopurua %d da, eta bigarrena %d da.", iZbk_1, iZbk_2);

	printf("\n\n");
	return 0;
}

void BiDatuPantailaratu(int iZbk_1, int iZbk_2) 
{
   printf("\n BiDatuPantailaratu() funtzioan: Lehen kopurua %d da, eta bigarrena %d da.", iZbk_1, iZbk_2);
   iZbk_1 = -3;   // eraginik ez dauka main() programa nagusian
   iZbk_2 = -4;   // eraginik ez dauka main() programa nagusian
}

Gogoratu main() programa nagusiko iZbk_1 aldagaia eta BiDatuPantailaratu funtzioko iZbk_1 aldagaia desberdinak direla (biek gordetzen dute 3 balio bera baina memoriako posizio desberdinak dira). Gauza bera gertatzen da iZbk_2 aldagaiekin, hots, bat bestearen kopia dela.



Bigarren programan, bi aldagaien balioak BiDatuHartu() funtzioan finkatzen direlako irteerako parametroak izango dira. Horregatik, iZbk_1 eta iZbk_2 aldagaien erreferentziak (bakoitzaren helbidea) pasatzen zaizkio BiDatuHartu() funtzioari.

Modu beretsuan, BiDatuHanditu() funtzioan datuak aldatzen direlako sarrera/irteerako parametroak izango dira. Horregatik, iZbk_1 eta iZbk_2 aldagaien erreferentziak (bakoitzaren helbidea) pasatzen zaizkio BiDatuHanditu() funtzioari.

/* 12b2-Erakusleak-Parametroak: funtzio baten parametroak irteerakoak direnean */

// iZbk_1 eta iZbk_2 aldagaiek balioak BiDatuHartu() funtzioan hartzen dituzte
// iZbk_1 eta iZbk_2 aldagaien balioak main() programa nagusiak  prozesatzen ditu

#include <stdio.h>

void BiDatuHartu(int *, int *);

int main()
{
	int iZbk_1;   // iZbk_1 zenbaki-aldagaiaren deklarazioa
	int iZbk_2;   // iZbk_2 zenbaki-aldagaiaren deklarazioa

	printf("\n");

    BiDatuHartu(&iZbk_1, &iZbk_2);
    printf("\n       main() programa nagusian: Lehen kopurua %d da, eta bigarrena %d da.", iZbk_1, iZbk_2);

	printf("\n\n");
	return 0;
}

void BiDatuHartu(int *iZbk_1, int *iZbk_2)
{
   *iZbk_1 = 33;   // eraginik dauka main() programa nagusian
   *iZbk_2 = 44;   // eraginik dauka main() programa nagusian
   printf("\n BiDatuPantailaratu() funtzioan: Lehen kopurua %d da, eta bigarrena %d da.", *iZbk_1, *iZbk_2);
   *iZbk_1 = -3;   // eraginik dauka main() programa nagusian
   *iZbk_2 = -4;   // eraginik dauka main() programa nagusian
}




Parametroen jokamoldea funtzioetan bi motakoa izan daiteke:

  1. Sarrerakoa: iZenbat parametroa BiDatuHanditu() funtzioan
  2. Irteerakoa: iZbk_1 parametroa BiDatuHartu() funtzioan, edo, Sarrera/Irteerakoa: iZbk_1 parametroa BiDatuHanditu() funtzioan

  • 12b1-Jarduera_Erakusleak.cbp | main.c
  • 12b2-Jarduera_Erakusleak.cbp | main.c


 

12. jarduera (I) | Erakusleak eta helbideak


ZER DAKIDAN:
datu-mota desberdineko aldagaiak erabiltzen badakit eta batzuetan memoriako helbideak ikusi ditut ere.



ZER IKASIKO DUDAN:
Erakusle bat zer den ikasiko dut.

Erakusle bat zer da?

Erakusle batek aldagai batera sartzeko bide bat ematen du, aldagaiaren identifikadorea erabili gabe. Horretarako, aldagaiaren helbidea erabiltzen da. Beraz, aldagaiaren helbideak bitartekari gisa jokatzen du aldagaiaren eta harekin lan egin behar duen programaren artean.

Hau da, programaren instrukzio batek aldagai bati erreferentzia egin ahal dio zeharka, eta, horretarako, aldagaiaren helbidea erabil dezake.

Zergatik erabiltzen dira erakusleak?

Erakusle bat erabiltzen dira jatorrizko balioa pasatzea zaila edo desegokia den egoeretan. Adibidez:

  1. Funtzio batek balio bat baino gehiago itzuli behar duenean
  2. Array bat funtzio batera pasatu nahi denean
  3. Array bat aldatu nahi denean arrayaren elementu baten helbidea erabiliz
  4. ...

Konstante-erakuslea eta aldagai-erakuslea

Konstante-erakusle bat memoriako helbide bat da, eta aldagai-erakusle bat memoriako toki bat da helbide bat gordetzeko ahalmena duena. Esate baterako:

     float fZbk = -7.09;   // zenbakizko aldagai honek eduki bat dauka (-7.09) eta helbide bat &fZbk
     float *p;             // float bati seinalatzen dion erakusle-aldagaiaren deklarazioa, berak ere eduki bat eta helbide bat izango ditu

                  // &fZbk helbide zehatz bat delako konstante-erakusle bat da
     *p = &fZk;   // p helbide bat da, aldagai-erakusleari dagokion helbidea da
                  // *p aldagai-erakuslearen edukia da, -7.09 zenbaki erreala

     printf("\n %.2f", fZbk);   // -7.09 pantailan idatzi (zuzenean)
     printf("\n %.2f", *p);     // -7.09 pantailan idatzi (zeharka)
Hau garrantzitsua da: kontuz * asteriskoarekin

float *p; bitartez erakusle-aldagaia deklaratzean, * asteriskoaren esanahia da: erakusle datu-mota (kasu honetan, erreal bati seinalatzen dion erakuslea da p).

*p = 7.3; bitartez esleipena gauzatzean, * asteriskoaren esanahia da: erakusleak seinalatzen duen aldagaia (kasu honetan, aldagai erreal batean 7.3 gorde).


Irudia handiago ikusteko bere gainean klik egin
/* 12a-Erakusleak-Helbideak: erakusleak eta helbideak */

// int iZbk; deklarazio ondoren:
//   - iZbk integer bat, iZbk zenbaki-aldagaiaren edukia
//   - &iZbk helbide bat, iZbk zenbaki-aldagaiaren helbidea
// int *p_iZbk; deklarazio ondoren:
//   - p_iZbk helbide bat, zenbaki-aldagai bati seinalatzen dion erakusle-aldagaia
//   - *p_iZbk integer bat, p_iZbk erakusleak seinalatzen duen zenbaki-aldagaiaren edukia
// Arrayekin berdin da, baina ahaztu gabe arrayaren helbidea bere identifikadorea dela

#include <stdio.h>

int main()
{
	int iZbk;      // iZbk zenbaki-aldagaiaren deklarazioa
	int *p_iZbk;   // p_iZbk erakusle-aldagaiaren deklarazioa

	printf("\n Aldagai oso bat eta berari seinalatzen dion erakuslea");
	printf("\n -----------------------------------------------------\n");

    p_iZbk = &iZbk;   // erakuslearen edukia iZbk zenbaki-aldagaiaren helbidea
    *p_iZbk = 7;      // p_iZbk erakusleak seinalatzen duen iZbk zenbaki-aldagaian 7 gorde

    printf("\n Bi agindu hauek bete ondoren:");
    printf("\n    p_iZbk = &iZbk;  // erakuslearen edukia iZbk-ren helbidea");
    printf("\n   *p_iZbk = 7;      // p_iZbk-k seinalatzen duen aldagaian 7 gorde \n");

    printf("\n      Edukiak             Helbideak");
    printf("\n      -------             ---------");
    printf("\n      iZbk = %d            &iZbk = %d", iZbk, (int)&iZbk);
    printf("\n    p_iZbk = %d    &p_iZbk = %d", (int)p_iZbk, (int)&p_iZbk);
    printf("\n   *p_iZbk = %d            p_iZbk = %d = &*p_iZbk (hau ez da erabiltzen)", *p_iZbk, (int)&*p_iZbk);

	printf("\n\n");

	printf("\n Osoen array bat eta berari seinalatzen dion erakuslea");
	printf("\n -----------------------------------------------------\n");

	int aiKopuruak[] = {3, 5, 7, 9};  // 4 osoen array bat
	int *p_aiKopuruak;  // p_aiKopuruak erakusle-aldagaiaren deklarazioa

	p_aiKopuruak = aiKopuruak;  // arrayaren helbidea bere identifikadorea da

	printf("\n \t aiKopuruak[] arraya");
	printf("\n \t -------------------");
	for (int k=0; k < 4; k++)
        printf("\n \t k=%d \t aiKopuruak[%d]=%d", k, k, aiKopuruak[k]);

    printf("\n");
    printf("\n \t p_aiKopuruak erakuslea");
    printf("\n \t ----------------------");
    for (int k=0; k < 4; k++)
    {
        printf("\n \t k=%d \t *p_aiKopuruak=%d", k, *p_aiKopuruak);
        p_aiKopuruak++;
    }

	printf("\n\n");
	return 0;
}




Erakusle motako aldagai batek helbideak gordetzen ditu. Ikusi zer gerta daitekeen zenbakizko aldagai baten helbidea gordetzen duen erakuslearekin lan egitean:


  • 12a-Jarduera_Erakusleak.cbp | main.c