gogoratzeko etiketadun mezuak erakusten. Erakutsi mezu guztiak
gogoratzeko etiketadun mezuak erakusten. Erakutsi mezu guztiak

2025(e)ko otsailaren 23(a), igandea

Ariketa 43 | Menu bat azpiprogramaz (char)

ZER DAKIDAN:
switch baldintzazko egitura ikasi nuen aukera anitzak antolatzeko (Ariketa 18 | Aukera anitzen arteko hautapena adibidea eta Ariketa 36 | Hainbat aukeren menu bat adibidea gogoratzen ditut).



ZER IKASIKO DUDAN:
Menu bat programatuko dut funtzioak erabiliz, erabiltzaileak gogoko duen hautapena cAukeraHautatu() funtzioan irakurtzen den karaktere bat izango da.







Bost aukera dituen menu batek gidatuko du programa. Aukerak hautatzeko karaktereak erabiltzen dira eta bostetatik aukera batek programa bukarazten du. Hautatutako aukerari esker switch agindu baten bitartez gidatzen da programaren exekuzioa (Ariketa 18 | Aukera anitzen arteko hautapena gogoratu). Menua pantailan aurkezteko lana eta erabiltzailearen aukeraren bat hautatzeko lana cAukeraHautatu() izeneko funtzioak egiten du:


Lehenik idatzi behar dugun main() funtzio nagusia, funtsean, prozesu errepikakor bat da, errepikapenak eteteko eta programatik irteteko I edo i karakterea sartu behar da. Deskriba ditzagun, banan-banan gainerako lau aukerak, eta ikus dezagun ere programa osoaren kodea.


cAukeraHautatu() funtzioan irakurritako A edo a karakterea main() funtzio nagusira helduko da eta funtzio nagusian DiagonalkiPantailaratu() funtzioak sarreratzat behar duen karakterea irakurriko da (funtzio horrek datu bakar bat behar du, alfabeto larriaren letra bat). Lehen aukera hau amaitzeko, DiagonalkiPantailaratu() funtzioak jarraian erakusten den mezua emateko gai da:




cAukeraHautatu() funtzioan irakurritako B edo b karakterea main() funtzio nagusira helduko da eta funtzio nagusian TaulaPantailaratu() funtzioak sarreratzat behar duen zenbaki osoa irakurriko da (funtzio horrek datu bakar bat behar du, 0 eta 9 arteko zenbaki osoa). Bigarren aukera hau bukatzeko, TaulaPantailaratu() funtzioak jarraian erakusten den mezua emateko gai da:




cAukeraHautatu() funtzioan irakurritako C edo c karakterea main() funtzio nagusira helduko da eta funtzio nagusian dbErroKuboaKalkulatu() funtzioaren sarrera den zenbaki erreala irakurriko da (funtzio horrek datu bakar bat behar du, zenbaki erreala eta positiboa). dbErroKuboaKalkulatu() funtzioaren deia egin ondoren, main() funtzio nagusian jarraian erakusten den mezuaren bezalakoak agertuko dira:




cAukeraHautatu() funtzioan irakurritako D edo d karakterea main() funtzio nagusira helduko da eta funtzio nagusian boFibonaccikoaDa() funtzioaren sarrera den zenbaki osoa irakurriko da (funtzio horrek datu bakar bat behar du, 3 eta 17000 arteko zenbaki osoa). boFibonaccikoaDa() funtzioaren deia egin ondoren, main() funtzio nagusiari balio boolear itzuliko dio eta balio boolear (FALSE ala TRUE) eta horren arabera programak honelako mezuak erakutsiko ditu:






Hona hemen Ariketa-43b_MenuaAzpiprogramaz.cbp proiektuaren iturburu-programa:
/* Ariketa-43b_MenuaAzpiprogramaz: menuaren aukeratzailea char datu-motakoa */

#include <stdio.h>
#include <stdlib.h>    // system() funtziorako
#include <conio.h>     // getche() funtziorako
#include <ctype.h>     // toupper() funtziorako
#include <math.h>      // fabs() funtziorako


char cAukeraHautatu(void);
void DiagonalkiPantailaratu(char);
void TaulaPantailaratu(int);
double dbErroKuboaKalkulatu(double);
int iFibonaccikoaDa(int);


int main()
{
    char cAukera, cLetra;
    int iZbk;
    double dbZbk, dbKuboa;

    do
    {
        system("cls");  // pantaila garbitu
        cAukera = cAukeraHautatu();

        printf("\n\n");
        switch (cAukera)
        {
            case 'A':
                do
                {
                    printf("A eta Z arteko letra bat eman: ");
                    scanf("%c", &cLetra);
                    cLetra = toupper(cLetra);
                } while (cLetra < 'A' || cLetra > 'Z');
                DiagonalkiPantailaratu(cLetra);
                break;
            case 'B':
                do
                {
                    printf("0 eta 9 arteko zenbaki osoa eman: ");
                    scanf("%d", &iZbk);

                } while (iZbk < 0 || iZbk > 9);
                TaulaPantailaratu(iZbk);
                break;
            case 'C':
                do
                {
                    printf("Zenbaki erreala eta positiboa eman: ");
                    scanf("%lf", &dbZbk);
                } while (dbZbk < 0.0);
                dbKuboa = dbErroKuboaKalkulatu(dbZbk);
                printf("%0.5f-ren erro kuboa: %0.5f\n\n", dbZbk, dbKuboa);
                break;
            case 'D':
                do
                {
                    printf("3 eta 6000 arteko zenbaki osoa eman: ");
                    scanf("%d", &iZbk);
                } while (iZbk < 3 || iZbk > 6000);
                if (iFibonaccikoaDa(iZbk) == 0)
                    printf("Ez, %d ez da Fibonacciren sekuentziakoa\n\n", iZbk);
                else
                    printf("Bai, %d Fibonacciren sekuentziakoa da\n\n", iZbk);
                break;
            case 'I':
                printf("\nPrograma amaitzera doa...\n");
                break;
        }

        // getchar();   // soberan 79 lerrokoa getche() bada 
                        // derrigorrezkoa 79 lerrokoa getchar() bada
        if (cAukera != 'I')
        {
            printf("Emaitzak ikusi ahal izateko itxaroten... ");
            getche();  // itxaroteko
        }
    } while (cAukera != 'I');

    return 0;
}


char cAukeraHautatu()
{
    char cHautapena;

    printf("==========================Menua==========================\n");
    printf("  A   Alfabeto zatia diagonalki\n");
    printf("  B   Biderkatzeko taula marraztu\n");
    printf("  C   Zenbaki baten erro kuboa Newton-Raphson bitartez\n");
    printf("  D   Zenbaki bat Fibonacciren sekuentziakoa da?\n");
    printf("\n");
    printf("  I   Programatik irten\n");
    printf("=========================================================\n");
    printf("                                Zure aukera: ");

    do
    {
        cHautapena = getche();
        cHautapena = toupper(cHautapena);

        if ((cHautapena < 'A' || cHautapena > 'D') && cHautapena != 'I')
        {
            printf("\n\aAukera ez da ondo hautatu. Berriro aukeratu: ");
        }
    } while ((cHautapena < 'A' || cHautapena > 'D') && cHautapena != 'I');

    return cHautapena;
}


void DiagonalkiPantailaratu(char cLetra)
{
    printf("Alfabeto zatia diagonalki pantailaratu:\n");

    int iNon = 15;
    for (char k = 'A'; k <= cLetra; k++)
    {
        printf("%*c\n", iNon, k);
        iNon++;
    }
    printf("\n");
}


void TaulaPantailaratu(int iZbk)
{
    printf("%d zenbakiaren biderkatzeko taula:\n", iZbk);
    for (int k = 1; k <= 10; k++)
    {
        printf("%35d x %d = %2d\n", k, iZbk, k * iZbk);
    }
    printf("\n");
}


double dbErroKuboaKalkulatu(double dbZbk)
{
    const double fEpsilon = 0.000000001;
    double dbKuboa = dbZbk / 3.0; // Lehendabiziko hurbilketa
    double dbAurrekoa;

    do
    {
        dbAurrekoa = dbKuboa;
        dbKuboa = (dbZbk / (dbAurrekoa * dbAurrekoa) + 2 * dbAurrekoa) / 3;
        dbKuboa = dbAurrekoa - (dbAurrekoa * dbAurrekoa * dbAurrekoa - dbZbk) / (3 * dbAurrekoa * dbAurrekoa);
    } while (fabs(dbKuboa - dbAurrekoa) > fEpsilon);

    return dbKuboa;
}


int iFibonaccikoaDa(int iZbk)
{
    int iFibo1 = 0, iFibo2 = 1, iFibo3 = iFibo1 + iFibo2;

    while (iFibo3 < iZbk)
    {
        iFibo1 = iFibo2;
        iFibo2 = iFibo3;
        iFibo3 = iFibo1 + iFibo2;
        printf("\tiFibo3 = %4d \t\t (%4d == %d) = %d\n", iFibo3, iFibo3, iZbk, iFibo3 == iZbk);
    }
    // C lengoaian zero gezurra da eta, ondorioz, zero ez dena egia da
    return (iFibo3 == iZbk);
}





Gure programak egiterakoan, ondoko lau gomendio hauek jarraitu:

  1. Programaren exekuzioa geldiarazteko, hots, pantaila jakin batean itxaroteko getche() funtzioa aplikatu. Beraz, getchar() ez egin ezta getch().
  2. Karaktereak teklatuz irakurtzeko betiko scanf() funtzioa erabili. Beraz, getchar() ez egin ezta getche() edo getch().
  3. Karaktereak pantailan idazteko betiko printf() funtzioa erabili. Beraz, putchar() ez egin.
  4. Bufferra beti garbitu. Horretarako, scanf() guztien ostean fflush(stdin) egin.

Lau gomendio horiek kontutan izanik, goiko Ariketa-43b_MenuaAzpiprogramaz.cbp proiektua honelaxe geratzen da: Ariketa-43c_MenuaAzpiprogramaz.cbp proiektua.

 

2025(e)ko otsailaren 19(a), asteazkena

Ariketa 36 | Hainbat aukeren menu bat

ZER DAKIDAN:
switch baldintzazko egitura ikasi nuen aukera anitzak antolatzeko.



ZER IKASIKO DUDAN:
Menu bat programa batean nola egiten den ikasiko dut, erabiltzaileak gogoko duen hautapena char datu-motako aldagai batean irakurriko dut. Bide batez system("cls") errutinaren funtzionamendua ikusiko dut ere. Eta, noski, menu bat prozesu errepikakor bat izan ohi da eta bertatik irteteko propio idaztiko dut aukera bat.


Ariketa 18 | Aukera anitzen arteko hautapena artikulua gogora ekarriz, programaren fluxua bideratzeko switch agindua erabilten da aukerak hiru edo gehiago direnean.

Jarraian erakusten den menua programa nagusian kokaturik dago, baina jakin ezazu hori horrela ez dela egingo behin azpiprogramen kontzeptua gureganatuko dugunetik aurrera.

Algoritmoa:
  1. Programa osoa prozesu errepikakor bat da, eta errepikapenak mozteko menuaren aukera egokia hautatu behar da (lehen adibidean I, i edo 0 balioak, eta bigarren adibidean A edo a balioak)
  2. Begiztaren iterazio bakoitzeko, pantaila garbitu system("cls") funtzioaren bitartez eta bost aukeren deskribapenak erakutsi
  3. Begiztaren iterazio bakoitzeko, char datu-motako cAukera aldagaiari balioa teklatuz eman era kontrolatuan (teklatuaren karaktere bat irakurtzeko getche() funtzioa oso egokia da)
  4. Irakurri den karaktere horren arabera switch egiturak kudeatuko du programaren fluxoa eta aukera horri dagozkion kalkuluak burutuko dira
  5. Begiztaren iterazio bakoitzeko, programaren exekuzioa gelditu getch() funtzioaren bitartez tekla bat sakatu arte, horrela informazioa eta kalkuluen emaitzak ikusi ahal izango dira
Ondoko bi programak nahiko berdintsuak dira, batean konstanteak erakusten dira pantailan eta bestean kalkulu baten emaitza. Bi ariketetan garrantzitsuena da programa nola antolatu den.


Programa honek goiko algoritmoa aplikatzen du:

/* Ariketa-36a_MenuBat: hainbat aukeren menu bat, aukeratzailea char */

// Programa hau 'Ariketa-18_MenuBat' programaren jarraipena da,
// harekiko dituen hobekuntzak:
//    1. Aldagai aukeratzailea char datu-motakoa da
//    2. Aldagai aukeratzailea irakurtzean egokitasuna kontrolatzen da
//    3. Iterazio bakoitzean pantaila garbitzen da
//    4. Menuak irteteko aukera du

#include <stdio.h>
#include <stdlib.h>   // system() funtziorako
#include <conio.h>    // getche() eta getch() funtzioetarako

#define LAT_A -34.927499   // Adelaide
#define LON_A 138.600000
#define LAT_B -15.793889   // Brasilia
#define LON_B -47.882778
#define LAT_C 51.047500    // Calgary
#define LON_C -114.062500
#define LAT_D 48.008889    // Donetsk
#define LON_D 37.804167

int main()
{
   char cAukera;

   do
   {
       system("cls");
       printf("\n");
       printf("\n ======Hiri baten datuak======");
       printf("\n     A. Adelaide");
       printf("\n     B. Brasilia");
       printf("\n     C. Calgary");
       printf("\n     D. Donetsk");
       printf("\n\n     I. Programatik irten");
       printf("\n =============================");

       do
       {
           printf("\n Zure aukera: ");
           cAukera = getche();
           fflush(stdin);
       } while ((cAukera != 'A') && (cAukera != 'a') &&
                (cAukera != 'B') && (cAukera != 'b') &&
                (cAukera != 'C') && (cAukera != 'c') &&
                (cAukera != 'D') && (cAukera != 'd') &&
                (cAukera != 'I') && (cAukera != 'i'));

       printf("\n");

       switch(cAukera)
       {
           case 'A':
           case 'a':
               printf("\n Adelaide");
               printf("\n Koordenatuak: (%.6f, %.6f)", LAT_A, LON_A);
               printf("\n Hego hemisferioko ekialdea");
               break;
           case 'B':
           case 'b':
               printf("\n Brasilia");
               printf("\n Koordenatuak: (%.6f, %.6f)", LAT_B, LON_B);
               printf("\n Hego hemisferioko mendebaldea");
               break;
           case 'C':
           case 'c':
               printf("\n Calgary");
               printf("\n Koordenatuak: (%.6f, %.6f)", LAT_C, LON_C);
               printf("\n Ipar hemisferioko mendebaldea");
               break;
           case 'D':
           case 'd':
               printf("\n Donetsk");
               printf("\n Koordenatuak: (%.6f, %.6f)", LAT_D, LON_D);
               printf("\n Ipar hemisferioko ekialdea");
               break;
           default:
               printf("\n Irtetera goaz.");
       }  // switch

       if ((cAukera != 'I') && (cAukera != 'i'))
       {
           printf("\n\n Edozein tekla sakatu aurrera egiteko...");
           getch();   // pantailaratutako informazioa ikusi ahal izateko
       }
   } while ((cAukera != 'I') && (cAukera != 'i'));

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

Programa honek ere goiko algoritmoa aplikatzen du:

/* Ariketa-36a2_MenuBat: hainbat aukeren menu bat, aukeratzailea int */

// Programa hau 'Ariketa-18_MenuBat' programaren jarraipena da,
// harekiko dituen hobekuntzak:
//    1. Aldagai aukeratzailea char datu-motakoa da
//    2. Aldagai aukeratzailea irakurtzean egokitasuna kontrolatzen da
//    3. Iterazio bakoitzean pantaila garbitzen da
//    4. Menuak irteteko aukera du

#include <stdio.h>
#include <stdlib.h>   // system() funtziorako
#include <conio.h>    // getche() eta getch() funtzioetarako

#define LAT_A -34.927499   // Adelaide
#define LON_A 138.600000
#define LAT_B -15.793889   // Brasilia
#define LON_B -47.882778
#define LAT_C 51.047500    // Calgary
#define LON_C -114.062500
#define LAT_D 48.008889    // Donetsk
#define LON_D 37.804167

int main()
{
   int iAukera;

   do
   {
       system("cls");
       printf("\n");
       printf("\n ======Hiri baten datuak======");
       printf("\n     1. Adelaide");
       printf("\n     2. Brasilia");
       printf("\n     3. Calgary");
       printf("\n     4. Donetsk");
       printf("\n\n     0. Programatik irten");
       printf("\n =============================\n");

       do
       {
           printf(" Zure aukera: ");
           scanf("%d", &iAukera);
       } while ((iAukera < 0) || (iAukera > 4));

       printf("\n");

       switch(iAukera)
       {
           case 1:
               printf("\n Adelaide");
               printf("\n Koordenatuak: (%.6f, %.6f)", LAT_A, LON_A);
               printf("\n Hego hemisferioko ekialdea");
               break;
           case 2:
               printf("\n Brasilia");
               printf("\n Koordenatuak: (%.6f, %.6f)", LAT_B, LON_B);
               printf("\n Hego hemisferioko mendebaldea");
               break;
           case 3:
               printf("\n Calgary");
               printf("\n Koordenatuak: (%.6f, %.6f)", LAT_C, LON_C);
               printf("\n Ipar hemisferioko mendebaldea");
               break;
           case 4:
               printf("\n Donetsk");
               printf("\n Koordenatuak: (%.6f, %.6f)", LAT_D, LON_D);
               printf("\n Ipar hemisferioko ekialdea");
               break;
           default:
               printf("\n Irtetera goaz.");
       }  // switch

       if (iAukera != 0)
       {
           printf("\n\n Edozein tekla sakatu aurrera egiteko...");
           getch();   // pantailaratutako informazioa ikusi ahal izateko
       }
   } while (iAukera != 0);

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



Programa honek ere goiko algoritmoa aplikatzen du:

/* Ariketa-36b_MenuBat: hainbat aukeren menu bat */

// Programa hau 'Ariketa-18_MenuBat' programaren antzekoa da,
// harekiko dituen hobekuntzak:
//    1. Aldagai aukeratzailea char datu-motakoa da
//    2. Aldagai aukeratzailea irakurtzean egokitasuna kontrolatzen da
//    3. Iterazio bakoitzean pantaila garbitzen da
//    4. Menuak irteteko aukera du

#include <stdio.h>
#include <stdlib.h>   // system() funtziorako
#include <conio.h>    // getche() eta getch() funtzioetarako

int main()
{
   char cAukera;
   float fEragigai1, fEragigai2;

   do
   {
       system("cls");
       printf("\n");
       printf("\n ============Menua============");
       printf("\n   +   Batura lortzeko");
       printf("\n   -   Kendura lortzeko");
       printf("\n   *   Biderkadura lortzeko");
       printf("\n   /   Zatiketa burutzeko");
       printf("\n\n   A   Amaitu programa");
       printf("\n =============================");

       do
       {
           printf("\n Zure aukera: ");
           cAukera = getche() ;
           fflush(stdin) ;
       } while ((cAukera != '+') &&
                (cAukera != '-') &&
                (cAukera != '*') &&
                (cAukera != 'x') &&
                (cAukera != 'X') &&
                (cAukera != '/') &&
                (cAukera != 'A') && (cAukera != 'a'));

       printf("\n\n");

       switch(cAukera)
       {
           case '+':
               printf(" Zenbaki errealekin lan eginez, lehenengo batugaiaren balioa eman: ");
               scanf("%f", &fEragigai1);
               printf(" Zenbaki errealekin lan eginez, bigarren batugaiaren balioa eman:  ");
               scanf("%f", &fEragigai2);
               printf(" %.2f + %.2f = %.2f", fEragigai1, fEragigai2, fEragigai1+fEragigai2);
               break;
           case '-':
               printf(" Zenbaki errealekin lan eginez, kenkizunaaren balioa eman: ");
               scanf("%f", &fEragigai1);
               printf(" Zenbaki errealekin lan eginez, kentzailearen balioa eman: ");
               scanf("%f", &fEragigai2);
               printf(" %.2f - %.2f = %.2f", fEragigai1, fEragigai2, fEragigai1-fEragigai2);
               break;
           case '*':
           case 'x':
           case 'X':
               printf(" Zenbaki errealekin lan eginez, lehenengo biderkagaiaren balioa eman: ");
               scanf("%f", &fEragigai1);
               printf(" Zenbaki errealekin lan eginez, bigarren biderkagaiaren balioa eman:  ");
               scanf("%f", &fEragigai2);
               printf(" %.2f * %.2f = %.2f", fEragigai1, fEragigai2, fEragigai1*fEragigai2);
               break;
           case '/':
               printf(" Zenbaki errealekin lan eginez, zatikizunaren balioa eman:  ");
               scanf("%f", &fEragigai1);
               do
               {
                   printf(" Zenbaki errealekin lan eginez, zatitzailearen balioa eman: ");
                   scanf("%f", &fEragigai2);
               } while (fEragigai2 == 0.0);
               printf(" %.2f / %.2f = %.2f", fEragigai1, fEragigai2, fEragigai1/fEragigai2);
               break;
           default:
               printf("\n Amaitzera goaz.");
       }  // switch

       if ((cAukera != 'A') && (cAukera != 'a'))
       {
           printf("\n\n Edozein tekla sakatu aurrera egiteko...");
           getch();   // kalkuluaren emaitza ikusi ahal izateko
       }
   } while ((cAukera != 'A') && (cAukera != 'a'));

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






  • Ariketa-36a1_MenuBat.cbp | main.c       [aukeratzailea char]
  • Ariketa-36a2_MenuBat.cbp | main.c       [aukeratzailea int]
  • Ariketa-36b_MenuBat.cbp | main.c         [aukeratzailea char]


 

2024(e)ko abenduaren 18(a), asteazkena

Sekuentziak, baldintzak eta errepikapenak (eskemak)

Orain arte aginduen sekuentziak ikusi ditugu eta erabakiak hartzeko baldintzako if eta switch aginduak. Hemendiak aurrera agindu errepikakorrekin (do-while, while eta for) ere lan egingo dugu, hauei esker iterazioak burutu daitezke.

Hona hemen aginduak antolatzeko hiru moduen eskemak:  

Sekuentziazko aginduen, baldintzazko aginduen eta agindu errepikakorren eskemak

Aginduen sekuentzietan programaren fluxuak beti aurrera egiten du eta agindu guztiak betetze dira bide bakar bat dagoelako. Baldintzako aginduetan ere programaren fluxuak beti aurrera egiten du, baina bide desberdinak daudelako, agindu batzuk beteko dira ala ez. Agindu errepikakorretan programaren fluxuak atzera egiten du agindu batzuk berriro betetzeko, horri iterazio esaten zaio:  



Baldintzazko aginduetan fluxuak aurrera egiten du



Agindu errepikakorretan fluxuak atzera egiten du

do-while eta while agindu errepikakorren arteko aldea kontzeptu bakarrean ematen da: Prozesu errepikakorra eteteko baldintza non kokatzen den, iterazioa baino lehen ala iterazioaren ostean. Bietan, bai do-while aginduan zein while aginduan prozesu errepikakorra eteteko baldintzaren logika berdina da: galderaren erantzuna ezezkoa bada eteteko da prozesu errepikakorra. Eskematikoki:  

while: iterazioa baino lehen ebaluatzen da galdera
do-while: iterazioa bukatzean ebaluatzen da galdera

Hirugarren agindu errepikakorra for da, agindu oso trinkoa delako bere erabilpena erraza da baina bere eskema marraztea ez da horren erraza. Noiz erabili for, do-while edo while agindu errepikakorrak? Araua argia da: prozesu errepikakorraren iterazio kopurua ezaguna denean for agindua erabiliko dugu, eta prozesu errepikakorraren iterazio kopurua ez dugunean ezagutzen do-while agindua edo while agindua erabili beharko dugu ezin bestean.

 

Datu-moten bihurketa automatikoa

C lengoaiak adierazpen berean datu-mota ezberdineko gaiak agertzea ahalbidetzen du, konpiladorea arduratzen da eragiketak behar bezala egiteaz. Adierazpen berean bi datu-mota edo gehiago agertzen direnean, eragigai guztien datu-motak bihurtzen ditu C lengoaiaren konpiladoreak eragigaietan dagoen datu-motarik handienera, honako bi arau hauen arabera:

  1. char eta short int guztiak int bihurtzen dira, float guztiak double bihurtzen dira
  2. Eragigai pare guztietarako, honako hau sekuentzian gertatzen da:
    • Eragigaietako bat long double bada, bestea long double bihurtzen da
    • Eragigaietako bat double bada, bestea double bihurtzen da
    • Eragigaietako bat long bada, bestea long bihurtzen da
    • Eragigaietako bat unsigned bada, bestea unsigned bihurtzen da.

Konpiladoreak bihurketa-arau horiek aplikatu ondoren, eragigaiak datu-mota berekoak izango dira, eta emaitza eragigaien datu-motako horretakoa izango da. Adibide bat ikus dezagun:

    char cKarak;
    int iKop;
    float fZbk;
    double dZbk;

    ( cKarak  /  iKop )  -  ( fZbk  +  iKop )  +  ( fZbk  *  dZbk ) ;
       char      int          float    int          float   double

Adierazpen aritmetikoan datu-mota desberdinak daudelako, lehenengo araua aplikatuko da. Lehenengo arauaren arabera, char datu-motako cKarak aldagaiaren balioa int bihurtzen da, eta, era berean, float datu-motako fZbk aldagaiaren balioa double bihurtzen da. Egoera berria hau delarik:

    ( cKarak  /  iKop )  -  ( fZbk  +  iKop )  +  ( fZbk  *  dZbk ) ;
       int       int         double    int         double   double

Hiru blokeak ikus ditzagun banan-banan. Lehen blokeko bi eragigaiak mota berekoak direnez, lehenengo eragiketa egingo dugu (cKarak/iKop), eta emaitza int datu-motakoa izango da. Era berean, hirugarren blokeko eragiketan bi biderkagaiak datu-mota berekoak direnez fZbk*dZbk eragiketa burutuko da emaitza double datu-motakoa delarik. Baina, bigarren blokeko batugaiak datu-mota desberdinekoak dira, horregatik, bigarren araua aplikatuz int datu-motakoa double datu-motara bihurtzen da eta fZbk+iKop emaitza double izango da.

    ( cKarak  /  iKop )  -  ( fZbk  +  iKop )  +  ( fZbk  *  dZbk ) ;
       int       int         double    int         double   double
       -------------         -------------         ---------------
            int                  double               double        

Hiru blokeak ebaluatu ondoren, haien integrazioa egin beharko da. Lehen blokea int datu-motakoa izango denez, eta bigarren blokea double datu-motakoa denez, lehen blokeari bihurketa bat egiten zaio double izan dadin eta bi bloken arteko kendura double datu-motakoa izango da. Amaitzeko hirugarren blokea gehituko zaio aurreko emaitzari eta biak double datu-motakoak direnez azken emaitza ere double izango da.

    ( cKarak  /  iKop )  -  ( fZbk  +  iKop )  +  ( fZbk  *  dZbk ) ;
       int       int         double    int         double   double
       -------------         -------------         ---------------
            int                  double                 double
            ---------------------------
                     double                             double
                     -----------------------------------------
                                        double
 

Operadoreen lehentasuna eta asoziatibitatea

Hurrengo taulako operadoreak lehentasunaren arabera zerrendatzen dira, handienetik txikienera. Operadore bat baino gehiago agertzen badira lerro berean edo talde batean, lehentasun bera dute eta asoziatibitateari begiratu beharko zaio hurrenkera jakiteko.

Azken lerroko esleipen-operadore soil eta esleipen-operadore konposatu guztiek lehentasun bera dute.

Operadoreen lehentasuna eta asoziatibitatea
(goitik beherako lehentasuna)
  Eragiketa mota      Asoziabilitatea                  Sinboloa
  1  Adierazpena
Ezkerretik eskumara
>>>
[] () . ->
++ --
 (atzizki)
  2  Unarioa
Eskumatik ezkerrera
<<<
sizeof & * + - ~ !
++ --
 (aurrizki)
  3  Behartzea
(edo typecast)
Eskumatik ezkerrera
<<<
(datu-mota)
  4 Biderkatzailea
Ezkerretik eskumara
>>>
*  %  /
  5  Batutzailea
Ezkerretik eskumara
>>>
+  - 
  6  Erlaziozkoa
Ezkerretik eskumara
>>>
>  <  >=  <=
  7  Berdintasuna
Ezkerretik eskumara
>>>
==  !=
  8  AND logikoa
Ezkerretik eskumara
>>>
&&
  9  OR logikoa
Ezkerretik eskumara
>>>
||
 10  Baldintzazko adierazpena
Eskumatik ezkerrera
<<<
?  :
 11  Esleipen soila
eta konposatua
Eskumatik ezkerrera
<<<
=   *=   /=   %=   +=   -=


Esan bezala, azken lerroko esleipen-operadoreek (soilak eta konposatuek) lehentasun berdina daukate.

Adierazpen batek lehentasun bera duten operadore bat baino gehiago izan ditzake. Mota horretako operadore batzuk adierazpenean maila berean agertzen direnean, ebaluazioak jarraitu egiten du, operadorearen asoziatibitatearen arabera, eskuinetik ezkerrera batzuetan eta ezkerretik eskuinera beste batzuetan. Beraz, adierazpen bat ebaluatzeko, lehentasunari begiratzen zaio lehenik eta gero asoziabilitateari.


Goiko taulari so eginez, ikus daiteke eragile aritmetikoek biderkatzaileak eta batutzaileak direla. Jarraian hiru adibide aurkeztuko dira: lehen adibidean behartze operadorea landuko dugu, bigarren adibidean parentesiak soberan ote dauden aztertuko da operadore biderkatzailekin lan egitean, eta, azkenik, hirugarren adibidean operadore biderkatzailea eta operadore batutzailea nahastuko dira.


Behartze operadorea nola aplikatu

Hau da OperadoreenLehentasuna_1.cbp proiektua non emaitza biak zilegiak diren, baina programa jakin batean bietariko bat ondo egongo den eta bestea txarto legokeen:

/* OperadoreenLehentasuna_1: behartze operadorea */

#include <stdio.h>   // printf() funtzioarako

int main()
{
   float fRadianak = 5.8;
   int iDobleOsoa;

   printf("\n   fRadianak = %.3f", fRadianak);
   printf("\n fRadianak*2 = %.3f\n", fRadianak*2);

   iDobleOsoa = (int)fRadianak*2;
   printf("\n iDobleOsoa = (int)fRadianak*2   ---> %d", iDobleOsoa);
   iDobleOsoa = (int)(fRadianak*2);
   printf("\n iDobleOsoa = (int)(fRadianak*2) ---> %d", iDobleOsoa);

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

Hona hemen OperadoreenLehentasuna_1.cbp proiektua exekutatzean lortzen den irteera:



Operadore biderkatzailekin parentesien beharra

OperadoreenLehentasuna_2.cbp proiektuan bi zeregin betetzen dira, fGraduak aldagaiari balioa ematea fRadianak ezaguna dela, eta, fSegundoenErdia aldagaiari balioa ematea fGraduak ezaguna dela. Lehen kasuan parentesiak guztiz derrigorrezkoa dira eta bigarren kasuan parentisirik ez da behar baina programa irakurterraza egitearren komenigarriak izan daitezke.

/* OperadoreenLehentasuna_2: parentesiak soberan? */

#include <stdio.h>   // printf() funtzioarako
#include <math.h>    // pow() funtziorako
#define PI 3.14

int main()
{
   float fRadianak = 5.8;
   float fGraduak;
   float fSegundoenErdia;

   printf("\n fRadianak = %.1f\n", fRadianak);

   fGraduak = fRadianak*360/(2*PI);
   printf("\n fGraduak = fRadianak*360/(2*PI) = %.3f", fGraduak);

   fGraduak = fRadianak*360/2*PI;
   printf("\n fGraduak = fRadianak*360/2*PI =  %.3f", fGraduak);


   printf("\n\n");
   fGraduak = 10.031;
   printf("\n fGraduak = %.3f\n", fGraduak);

   fSegundoenErdia = fGraduak*3600/2;
   printf("\n fSegundoenErdia = fGraduak*3600/2 =   %.3f", fSegundoenErdia);
   fSegundoenErdia = (fGraduak*3600)/2;
   printf("\n fSegundoenErdia = (fGraduak*3600)/2 = %.3f", fSegundoenErdia);

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

Hona hemen OperadoreenLehentasuna_2.cbp proiektua exekutatzean lortzen den irteera:

Biderkatzaileen asoziabilitatea ezkerretik eskumara doanez,
lehen adibidean parentesiak derrigorrezkoak dira


Operadore biderkatzailea eta operadore batutzailea konbinatuz

Hau da OperadoreenLehentasuna_3.cbp proiektua non emaitza biak zilegiak diren, baina programa jakin batean bietariko bat ondo egongo den eta bestea txarto legokeen:

/* OperadoreenLehentasuna_3: batutzaileak eta biderkatzaileak konbinatuz */

#include <stdio.h>   // printf() funtzioarako

int main()
{
   int iEmaitza;
   int iZbk_1 = 1;
   int iZbk_2 = 2;
   int iZbk_3 = 3;

   printf("\n");
   printf(" ===============================================\n");
   printf("    iEmaitza = iZbk_1 + iZbk_2 * iZbk_3 =   7\n");
   printf("    iEmaitza = (iZbk_1 + iZbk_2) * iZbk_3 = 9\n");
   printf(" ===============================================\n");

   printf("\n iZbk_1 = %d", iZbk_1);
   printf("\n iZbk_2 = %d", iZbk_2);
   printf("\n iZbk_3 = %d", iZbk_3);
   printf("\n\n");

   printf(" -----------------------------------------------");
   iEmaitza = iZbk_1 + iZbk_2 * iZbk_3;
   printf("\n    iZbk_1 + iZbk_2 * iZbk_3 =   %d", iEmaitza);
   iEmaitza = (iZbk_1 + iZbk_2) * iZbk_3;
   printf("\n    (iZbk_1 + iZbk_2) * iZbk_3 = %d\n", iEmaitza);
   printf(" -----------------------------------------------");
   printf("\n\n");

   getchar();
   return 0;
}

Hona hemen OperadoreenLehentasuna_3.cbp proiektua exekutatzean lortzen den irteera:





Eragile logikoek eta konparatzaileek beren eragigaien ebaluazioa bermatzen dute ezkerretik eskuinera (taulako 6., 7., 8. eta 9. errenkadak). Hala ere, adierazpenaren emaitza zehazteko behar diren eragigaien kopururik txikiena ebaluatzen dute, eta horri "zirkuitulaburraren" ebaluazioa esaten zaio. Beraz, baliteke adierazpen logikoaren eragigai batzuk ez ebaluatzea. Azter dezagun, adibidez, adierazpen logiko hau:
if (x>=5 && y==3)

Aurreko if adibidean AND operadore logikoak (&&) lehentasun txikiagoa du erlaziozko operadoreak baino (>=) eta berdintasunaren operadoreak baino (==). Hori dela eta, lehenik ezkerreko konparaketa ebaluatuko da eta, adibidez, x aldagaiaren balioa 4 balitz, orduan eskumako konparaketa ez litzateke ebaluatuko; izan ere, y aldagaiaren balioa edozein dela adierazpen logikoak FALSE emaitzara ebaluatuko litzateke x>=5 alderaketak FALSE balio duelako.

Baina, aurreko if adibidean AND operadore logikoaren ordez OR operadore logikoa (||) idatziko balitz, honek ere lehentasun txikiagoa du erlaziozko operadoreak baino (>=) eta berdintasunaren operadoreak baino (==). Hori dela eta, alderaketa biak ebaluatuko dira, lehenik ezkerreko konparaketa ebaluatuko da eta ondoren eskumako konparaketa ebaluatuko da:
if (x>=5 || y==3)
Izan ere, x txikiago 5 izan arren, baliteke y aldagaiaren balioa 3 izatea eta kasu horretan if aginduaren baldintza beteko litzateke.


Jakina denez, eslipen mota desberdinak daude: esleipen soila alde batetik eta esleipen konposatuak bestetik. Ikastaro honetan gehien-gehienetan esleipen soila erabiliko da.

Berrikus ditzagun lehentasun arauak adierazpen aritmetiko konplexu bat duen esleipen honetan:
iGraduOsoak = (int)( fRadianak*360/(2*PI) + (fHasiera*7)/pow(fAmaiera+0.2,PI) );

Adierazpen aritmetiko honetan bi parentesi multzo nagusi daude, baina biak ez dira berdinak:

  • (int) parentesia, taulako hirugarren lerroko behartze operadorea da
  • ( fRadianak*360/(2*PI) + (fHasiera*7)/pow(fAmaiera+0.2,PI) ) parentesia taulako lehen lerroko adierazpena delako, lehen-lehenik ebaluatuko da eta ondoren bere emaitzari behartze operadorea aplikatuko zaio
Beraz, aipatu ditugun parentesi nagusi biak ordena honetan ebaluatuko dira:
                II                           I
              ===== ----------------------------------------------------------               
iGraduOsoak = (int)( fRadianak*360/(2*PI) + (fHasiera*7)/pow(fAmaiera+0.2,PI) );

I izendatu dugun fRadianak*360/(2*PI) + (fHasiera*7)/pow(fAmaiera+0.2,PI) zatian hiru parentesi multzo daude eta hauek ere ez dira guztiz berdinak:

  • (2*PI) taulako lehen lerroko adierazpen operadorea da eta ezkerrean dagoelako ebaluatzen den aurrenekoa izango da
  • (fHasiera*7) taulako lehen lerroko adierazpen operadorea da, baina aurrekoaren eskuman dagoelako bigarrena izango da ebaluatze-segidan
  • (fAmaiera+0.2,PI) funtzio baten parametro-zerrenda mugatzeko parentesiak dira eta multzo honek aurreko biekin zerikusirik ez dauka, funtzioa ebaluatzeko unean aintzat hartuko da parentesi barnekoa
                II                           I
              ===== ----------------------------------------------------------               
iGraduOsoak = (int)( fRadianak*360/(2*PI) + (fHasiera*7)/pow(fAmaiera+0.2,PI) );
                                   ------   ============
                                      1           2
Hurrengoak ebaluatzen hiru biderkatzaileak izango dira eta ezkerreik eskumara ebaluatuko dira. Lehenik fRadianak*360, gero fRadianak*360/(2*PI) eta (fHasiera*7)/pow(fAmaiera+0.2,PI) bukatzeko; honelaxe: a, b eta c. Eskematikoki:
                II                           I
              ===== ----------------------------------------------------------               
iGraduOsoak = (int)( fRadianak*360/(2*PI) + (fHasiera*7)/pow(fAmaiera+0.2,PI) );
                                   ------   ============
                                      1           2
                     -------------
                           a   
                     --------------------         
                               b            ---------------------------------
                                                           c

Azkenik, batutzaile operadorearen txanda izango da eta horrela bukatzen da I zatiaren ebaluazioa. Helburuko iGraduOsoak aldagaiaren balioa II behartze operadoreari esker lortuko da.

Hona hemen OperadoreenLehentasuna_4.cbp proiektua exekutatzean lortzen den irteera:








  • OperadoreenLehentasuna_1.cbp | main.c  
  • OperadoreenLehentasuna_2.cbp | main.c  
  • OperadoreenLehentasuna_3.cbp | main.c  
  • OperadoreenLehentasuna_4.cbp | main.c  

 

2024(e)ko abenduaren 1(a), igandea

scanf(), lehen hurbilketa


scanf
#include <stdio.h>

int scanf(const char * formatukatea, argumentu1, argumentu2, ...);

Aipatzen ari garen scanf() funtzioa helburu orokorreko errutina bat da, stdin gailutik irakurtzen duena (stdin sarrerako gailu estandarra, normalean teklatua) eta ENTER edo RETURN tekla sakatzean irakurketa burutzen da. Funtzioaren deian adierazten diren datu-motak irakurri eta barne-formatu egokian eralda ditzake. Nolabait, scanf() funtzioa printf() funtzioaren alderantzizkoa da. Formatuaren arabera zehaztutako kontrol-kateak hiru karaktere mota izango ditu:

  • Formatu-espezifikatzaileak (edo formatu-zehaztatzaileak)
  • Zuriunearen karaktereak
  • Zuriuneak ez diren karaktereak

Sarrerako formatu-zehaztatzaileen aurretik % sinboloa dago, eta scanf() funtzioari adierazten diote zer datu mota irakurriko den jarraian. Formatu-espezifikatzaileak hauek dira non kolore berdez adierazten direnak ikastekoak diren:

scanf() funtzioaren formatu-zehaztatzaileak
 Zehaz.  Deskribapena  Adibidea Ikasi
   %c Karaktere bakarra irakurri. w BAI
   %s Karaktere-katea irakurri. kaixo BAI
   %d Irakurri osoko hamartarra zeinuarekin. -9125 BAI
   %i Irakurri osoko hamartarra zeinuarekin. +9125 EZ
   %u Irakurri osoko hamartarra zeinurik gabe. 1299 BAI
   %f Irakurri zenbaki erreala edo puntu flotatzailea. 74.93 BAI
   %e Irakurri notazio zientifikoko zenbaki erreala (e xehea). 3.926e+2 BAI
   %E Irakurri notazio zientifikoko zenbaki erreala (E larria). 3.926E+2 BAI
   %g %e eta %f artean laburrena erabili. 392.6 EZ
   %G %E eta %f artean laburrena erabili. 392.6 EZ
   %o Zortzitarra zeinurik gabe. 707 EZ
   %x Hamaseitarra, zeinurik gabeak (letra xeheak). 3fb EZ
   %X Hamaseitarra, zeinurik gabeak (letra larriak). 3FB EZ
   %p Erakusle baten edukia irakurri. b7000000 EZ
   %n Irakurritako karaktere-zenbakiaren balio bera jasotzen du.   EZ


Gainera, h (short), l (long) eta L (long) aldatzaileak daude eta printf() funtzioarekin bezala erabil daitezke. Honela:

  • h (short) aldatzailea d, i, u, o, x eta X datu-motei aplika dakieke, eta esaten digu datu-mota short int dela edo unsigned short int dela, kasuaren arabera.
  • l (long) aldatzailea aurreko kasuetan aplika daiteke (d, i, u, o, x eta X), eta adierazten du datu-mota long int dela edo unsigned long int dela, baina, horrez gain...
  • l (long) aldatzailea e, E, f eta g datu-motei ere aplika dakieke, datu-mota double dela adieraziz.
  • L (long) aldatzailea e, E, f eta g datu-motei aplika dakieke, eta datu-mota long double dela adierazten du.

Balioak jasotzeko scanf() funtzioaren aldagai guztiak erreferentzia bidez pasatu behar dira, hau da, haien helbideak pasarazi behar dira. Horregatik, zenbaki osoko baten aldagaiaren parametroa honela agertuko da &iAltuera non & sinboloak aldagaiaren helbidea adierazen duen.

Bestalde, scanf() funtzioak zuzen esleitu diren eremuen kopuru bera itzultzen du.

Hona hemen scanf() funtzioaren hainbat adibide dituen programa:

/* SCANF_1-hurbilketa.cbp proiektua, scanf funtzioaren lehen hurbilketa: zenbaki osoak edo errealak. */

// Programa honetan scanf() funtzioa ikasiko dugu, zenbakiekin lan eginez.
// Aldagai baten balioa irakurtzeko, gehien gehienetan, scanf() bana erabiliko dugu.
// Baina scanf() berak aldagai bat baino gehiago irakur ditzake, banatzaile egokia jarriz.

#include <stdio.h>

int main()
{
   int iAltuera, iOinarria, iAzalera;

   printf("\n\n");
   printf("Zenbaki osoekin lan eginez...");

   printf("\n\n");
   printf("Laukizuzenaren altuera sartu: ");
   scanf("%d", &iAltuera);
   printf("Laukizuzenaren oinarria eman: ");
   scanf("%d", &iOinarria);

   iAzalera = iAltuera*iOinarria;

   printf("Laukizuzenaren azalera %d da", iAzalera);
   printf("\nLaukizuzenaren azalera, %dx%d = %d", iAltuera, iOinarria, iAzalera);
   printf("\n\n");

   printf("Biak eman, altuera eta oinarria (zuriunez banatu): ");
   scanf("%d %d", &iAltuera, &iOinarria);   // HONELA EZ DUGU EGINGO

   iAzalera = iAltuera*iOinarria;

   printf("Laukizuzenaren azalera %d da", iAzalera);
   printf("\nLaukizuzenaren azalera, %dx%d = %d", iAltuera, iOinarria, iAzalera);
   printf("\n\n");

   printf("Biak eman, altuera eta oinarria (banatzeko :: karaktereak): ");
   scanf("%d::%d", &iAltuera, &iOinarria);   // HONELA EZ DUGU EGINGO

   iAzalera = iAltuera*iOinarria;

   printf("Laukizuzenaren azalera %d da", iAzalera);
   printf("\nLaukizuzenaren azalera, %dx%d = %d", iAltuera, iOinarria, iAzalera);
   printf("\n\n");

   return 0;
}


Esan den bezala, scanf() funtzioak aldagaiaren helbidea behar du eta horregatik aldagaiaren identifikadorearen aurrean & sinboloa idatzi beharra dago, hots, & helbide-operadorea. Baina, aldagaiaren identifikadorea soilik idazten badugu & sinbolorik gabe, zer gertatzen da? Jarraian ematen den SCANF_1-txarto.cbp proiektua aztertu:
/* SCANF_1-txarto.cbp proiektua, scanf() bitartez zenbaki bat irakurtzen. */

// Programa honetan scanf() funtzioa aplikatzean, kontrol-katea den lehen
// parametroan %f formatu-zehaztatzailea idatziko da, eta, bigarren parame-
// troan aldagaiaren helbidea zehaztu beharrean aldagaia idatziko da.
// Proiektua konpilatzean abisu bat agertuko da:
/*
 ||=== Build: Debug in SCANF_1-txarto (compiler: GNU GCC Compiler) ===|
 warning: format '%f' expects argument of type 'float *', but argument 2 has type 'double'
 ||=== Build finished: 0 error(s), 1 warning(s) (0 minute(s), 0 second(s)) ===|
*/
// Eta proiektua exekutatzean scanf() ondoren programaren exekuzioa bukatzen da
// modu desegokian, ikus daitekeen bezala main() funtzioak ez du 0 itzultzen.

#include <stdio.h>

int main()
{
   float fAltuera = 3.2;
   float fOinarria = 4.4;
   float fLuzera = 7.1;

   printf("\nZenbaki errealekin lan eginez...");

   printf("\n\n");
   printf("  fLuzera:  edukia=%.2f  helbidea=%d  (float batek 4 byte hartzen ditu)\n", fLuzera, (int)&fLuzera);
   printf("fOinarria:  edukia=%.2f  helbidea=%d  (float batek 4 byte hartzen ditu)\n", fOinarria, (int)&fOinarria);
   printf(" fAltuera:  edukia=%.2f  helbidea=%d  (float batek 4 byte hartzen ditu)\n", fAltuera, (int)&fAltuera);

   printf("\nPrismaren altuera sartu: ");
   scanf("%f", fAltuera);   // txarto, scanf() funtzioak aldagaiaren HELBIDEA behar duelako
   // scanf() funtzioak huts egiten badu, exekuzioa hemen bukatzen da eta hurrengoa EZ DA PANTAILARATUKO
   printf("Prismaren altuera %.2f da.", fAltuera);

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

Irudi honetan erakusten dira SCANF_1-txarto.cbp proiektuan erabiltzen diren hiru aldagaien nondik norakoak. Hirurak float datu-motakoak izanik bakoitzak 4 byte hartzen ditu memorian. Irudian agertzen diren zenbakiak sistema hamartarrean adierazi dira azalpena erraztearren; baina makina digital bat delako, egiari zor, benetako balioak sistema bitarrean kodeturik egongo dira:

Irudian agertzen diren zenbakizko balio guztiak kode bitarrean idatzi beharko lirateke.

Hauxe da SCANF_1-txarto.cbp proiektua exekutatzean lortzen den irteera:

Datua emateko scanf("%f",fAltuera) irakurketa egitean, programak txarto bukatzen du.

Baina SCANF_1-txarto.cbp proiekuan main.c fitxategiko irakurketa ondo idatziz —honela idatziz scanf("%f",&fAltuera)— lortzen den irteera beste hau da:

Datua emateko scanf("%f",&fAltuera) irakurketa egitean, programa ondo ibiliko da.






  • SCANF_1-hurbilketa.cbp | main.c  
  • SCANF_1-txarto.cbp | main.c