algoritmoa etiketadun mezuak erakusten. Erakutsi mezu guztiak
algoritmoa etiketadun mezuak erakusten. Erakutsi mezu guztiak

2025(e)ko apirilaren 9(a), asteazkena

Ariketa 79 | Bilaketa: 4. algoritmoa

ZER DAKIDAN:
Fitxategiak zer diren badakit, eta fitxategiak irekitzeko w, r eta a markak erabili behar ditudala badakit.



ZER IKASIKO DUDAN:
FILE datu-motarekin jarraituz, elementu baten bilaketa fitxategian nola programatzen den ikasiko dut, baldintza konposatua duen while agindu errepikakor bat erabil daiteke. Baina, errazagoa da fitxategi osoa irakurtzeko while (fread()==1) agindua idaztea eta elementua bilatzean return bitartez prozesu errepikakorra moztea.

Datuak gordetzen dituen fitxategi bat daukagu. Esate baterako, estrukturen fitxategi bat daukagu eta gako bat eman ondoren (adibidez Danel izena) izen horretako elementurik ote dagoen fitxategian jakin nahi dugu, hots, bilaketa bat egin nahi dugu fitxategian eta horretarako iIzenaBilatu() funtzioa idatziko dugu, stIzenaBilatu() funtzioa idatziko dugu edo bestela liIzenaBilatu() funtzioa idatziko dugu.


Algoritmo honek lan gutxiago dauka hurrengo algoritmoak baino. Bilaketa arrakastatsua bada, bilatzen dugun gakoa fitxategian aurkitzen da, orduan iIzenaBilatu() funtzioaren parametro batek estruktura den elementu osoa itzuliko dio programa nagusiari, eta iIzenaBilatu() funtziok TRUE itzuliko du. Aldiz, bilaketak arrakastarik ez badu, bilatzen den gakoa fitxategian aurkitzen ez delako, orduan iIzenaBilatu() funtzioak FALSE itzuliko du.

Erakusten den programa honetan fitxategiaren existentzia frogatzen da programa nagusian, horren arabera:

  • Zehaztutako fitxategiaren edukia pantailaratu
  • Izen bat teklatuz irakurri eta fitxategian bilatzen da, egoera bi hauek aintzat hartzen dira:
    1. Gakoa den izena ez da aurkitzen fitxategian, mezu bat pantailaratzen da
    2. Gakoa den izena fitxategian aurkitzen da, elementu horren datuak pantailaratzen dira
/* Ariketa-79_Fitxategien_4a_algoritmoa: bilaketa bat fitxategian */

// Bilatzen ari den gakoa aurkitzean, estruktura bat den elementu
// osoa itzuliko da (azkenik irakurri den elementua).
// Bestela, estruktura bat itzuliko da baina null karakterea duena.

#include <stdio.h>
#include <stdlib.h>   // exit() funtziorako
#include <string.h>   // strcpy() eta strcmp() funtzioetarako
#include <conio.h>    // getche() eta getch() funtzioetarako

#define sBIDEA "C:\\Tokia\\"
#define FITX_IZEN_MAX 120  // fitxategiaren izenerako 119 karaktere gehi null mugatzailea
#define DATU_IZEN_MAX  72  // ikaslearen izena gordetzeko 71 karaktere gehi null mugatzailea
#define TRUE  1
#define FALSE 0

struct tstFitxa
{
    char sIzenDeiturak[DATU_IZEN_MAX];
    int iDeialdia;
    float fNota;
};


innt iFitxategirikBada(const char *sFitxIzen);
void FitxategiaIkusi(const char *sFitxIzen);
int iIzenaBilatu(const char *sFitxIzen,
                 const char *sGakoa,
                 struct tstFitxa *stElem);


int main()
{
    char sFitxIzenLaburra[FITX_IZEN_MAX];
    char sFitxIzen[FITX_IZEN_MAX];
    char sGakoa[DATU_IZEN_MAX];
    struct tstFitxa stBilatutakoa;

    printf("Fitxategia existitzen da eta datuak ditu\n(adibidez C:\\Tokia\\Ikasleak.DAT)\n\n");
    printf("Fitxategiaren izen laburra eman (adibidez 'Ikasleak'): ");
    gets(sFitxIzenLaburra);

    strcpy(sFitxIzen, sBIDEA);
    strcat(sFitxIzen, sFitxIzenLaburra);
    strcat(sFitxIzen, ".dat");
    printf("Fitxategiaren izen osoa: >>>%s<<<\n\n", sFitxIzen);

    if (iFitxategirikBada(sFitxIzen) == 1)
    {
        printf("'%s' fitxategia existitzen da, lan egin dezagun.\n\n", sFitxIzen);
        printf("---------------------------------------------------------------\n");
        FitxategiaIkusi(sFitxIzen);
        printf("---------------------------------------------------------------\n\n");
        printf("Bilatu nahi den ikaslearen izen deiturak eman: ");
        gets(sGakoa);

        if (iIzenaBilatu(sFitxIzen, sGakoa, &stBilatutakoa) == FALSE)
            printf("'%s' izeneko ikaslerik ez dago %s fitxategian\n", sGakoa, sFitxIzen);
        else
        {
            printf("Bilatzen den ikaslearen datu guztiak:\n");
            printf("%50s\n%50u\n%50.2f\n", stBilatutakoa.sIzenDeiturak,
                                           stBilatutakoa.iDeialdia,
                                           stBilatutakoa.fNota);
        }
    }
    else
    {
        printf("'%s' fitxategia ez da existitzen.\n", sFitxIzen);
    }

    printf("\nPrograma bukatzera doa. Edozein tekla sakatu! ");
    getch();  // itxaron edozein tekla sakatu arte

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


// Funtzio honek fitxategi baten existentzia frogatzen du.
int iFitxategirikBada(const char *sFitxIzen)
{
    FILE *f;

    // Irakurketarako irekitze saiakera ("r" = read)
    f = fopen(sFitxIzen, "rb");

    // Fitxategirik ez balego fopen() funtzioak NULL itzuliko luke
    if (f != NULL)
    {
        fclose(f);  // fitxategia itxi baliabidwak askatzeko
        return 1;   // Itzuli 1 (true): fitxategia bada
    }

    // Fitxategirik ez balego fopen() funtzioak NULL itzuliko luke
    return 0;       // Itzuli 0 (false): fitxategia ez da existitzen
}


void FitxategiaIkusi(const char *sFitxIzen)
{
    FILE *f;
    struct tstFitxa stFitxa;
    int iPos = 0;

    // Irakurketarako irekitze saiakera ("r" = read)
    // Jakina da fitxategia existitzen dela eta errorerik ez dela izango fopen() funtzioan
    f = fopen(sFitxIzen, "rb");

    printf("'%s' fitxategiaren edukia:\n", sFitxIzen);
    while (fread(&stFitxa, sizeof(struct tstFitxa), 1, f) == 1)
    {
        printf("%d. ", iPos);
        printf("Ikaslea: %-20s  Deialdia: %d  Nota: %.2f\n",
               stFitxa.sIzenDeiturak, stFitxa.iDeialdia, stFitxa.fNota);
        iPos++;
    }

    fclose(f);
}


// Bilatzen den gakoa aurkitzean, emaitza den stEmaitza estrukturak
// irakurritako *stElem parametroak azken elementuaren balioak itzuliko
// ditu eta TRUE marka itzultzen da return bitartez.
// Bestela, aurkitzen ez bada, *stElem parametroak ez du balio ezagunik
// izango eta FALSE marka itzultzen da return bitartez.
int iIzenaBilatu(const char *sFitxIzen, 
                 const char *sGakoa, 
                 struct tstFitxa *stElem)
{
    FILE *f;
    struct tstFitxa stLaguntzailea;

    // Irakurketarako irekitze saiakera ("r" = read)
    // Jakina da fitxategia existitzen dela eta errorerik ez dela izango fopen() funtzioan
    f = fopen(sFitxIzen, "rb");

    while (fread(&stLaguntzailea, sizeof(stLaguntzailea), 1, f) == 1)   // irakurtzeko gai garen bitartean
    {
        if (strcmp(stLaguntzailea.sIzenDeiturak, sGakoa) == 0)
        {
            fclose(f);
            *stElem = stLaguntzailea;
            return TRUE;   // aurkitu da
        }
    }

    fclose(f);
    return FALSE;   // ez da aurkitu
}


/*
// Aurrekoa bezalako baina stLaguntzailea aldagai laguntzailerik gabe
int iIzenaBilatu(const char *sFitxIzen, 
                 const char *sGakoa, 
                 struct tstFitxa *stElem)
{
    FILE *f;

    // Irakurketarako irekitze saiakera ("r" = read)
    // Jakina da fitxategia existitzen dela eta errorerik ez dela izango fopen() funtzioan
    f = fopen(sFitxIzen, "rb");

    while (fread(stElem, sizeof(*stElem), 1, f) == 1)   // irakurtzeko gai garen bitartean
    {
        if (strcmp(stElem->sIzenDeiturak, sGakoa) == 0)
        {
            fclose(f);
            return TRUE;   // aurkitu da
        }
    }

    fclose(f);
    return FALSE;   // ez da aurkitu
}
*/


Algoritmo honek lan gutxiago dauka hurrengo algoritmoak baino. Bilaketa arrakastatsua bada, bilatzen dugun gakoa fitxategian aurkitzen da, orduan stIzenaBilatu() funtzioak estruktura den elementu osoa itzuliko dio programa nagusiari. Aldiz, bilaketak arrakastarik ez badu, bilatzen den gakoa fitxategian aurkitzen ez delako, orduan stIzenaBilatu() funtzioak estruktura bat itzuliko dio ere programa nagusiari, baina izenean null karakterea duena.

Erakusten den programa honetan fitxategiaren existentzia frogatzen da programa nagusian, horren arabera:

  • Zehaztutako fitxategiaren edukia pantailaratu
  • Izen bat teklatuz irakurri eta fitxategian bilatzen da, egoera bi hauek aintzat hartzen dira:
    1. Gakoa den izena ez da aurkitzen fitxategian, mezu bat pantailaratzen da
    2. Gakoa den izena fitxategian aurkitzen da, elementu horren datuak pantailaratzen dira
/* Ariketa-79_Fitxategien_4b_algoritmoa: bilaketa bat fitxategian */

// Bilatzen ari den gakoa aurkitzean, estruktura bat den elementu
// osoa itzuliko da (azkenik irakurri den elementua).
// Bestela, estruktura bat itzuliko da baina null karakterea duena.

#include <stdio.h>
#include <stdlib.h>   // exit() funtziorako
#include <string.h>   // strcpy() eta strcmp() funtzioetarako
#include <conio.h>    // getche() eta getch() funtzioetarako

#define sBIDEA "C:\\Tokia\\"
#define FITX_IZEN_MAX 120  // fitxategiaren izenerako 119 karaktere gehi null mugatzailea
#define DATU_IZEN_MAX  72  // ikaslearen izena gordetzeko 71 karaktere gehi null mugatzailea

struct tstFitxa
{
    char sIzenDeiturak[DATU_IZEN_MAX];
    int iDeialdia;
    float fNota;
};


int iFitxategirikBada(const char *sFitxIzen);
void FitxategiaIkusi(const char *sFitxIzen);
struct tstFitxa stIzenaBilatu(const char *sFitxIzen, const char *sGakoa);


int main()
{
    char sFitxIzenLaburra[FITX_IZEN_MAX];
    char sFitxIzen[FITX_IZEN_MAX];
    char sGakoa[DATU_IZEN_MAX];
    struct tstFitxa stBilatutakoa;

    printf("Fitxategia existitzen da eta datuak ditu\n(adibidez C:\\Tokia\\Ikasleak.DAT)\n\n");
    printf("Fitxategiaren izen laburra eman (adibidez 'Ikasleak'): ");
    gets(sFitxIzenLaburra);

    strcpy(sFitxIzen, sBIDEA);
    strcat(sFitxIzen, sFitxIzenLaburra);
    strcat(sFitxIzen, ".dat");
    printf("Fitxategiaren izen osoa: >>>%s<<<\n\n", sFitxIzen);

    if (iFitxategirikBada(sFitxIzen) == 1)
    {
        printf("'%s' fitxategia existitzen da, lan egin dezagun.\n\n", sFitxIzen);
        printf("---------------------------------------------------------------\n");
        FitxategiaIkusi(sFitxIzen);
        printf("---------------------------------------------------------------\n\n");
        printf("Bilatu nahi den ikaslearen izen deiturak eman: ");
        gets(sGakoa);

        stBilatutakoa = stIzenaBilatu(sFitxIzen, sGakoa);

        if (strcmp(stBilatutakoa.sIzenDeiturak, "\0") == 0)
            printf("'%s' izeneko ikaslerik ez dago %s fitxategian\n", sGakoa, sFitxIzen);
        else
        {
            printf("Bilatzen den ikaslearen datu guztiak:\n");
            printf("%50s\n%50u\n%50.2f\n", stBilatutakoa.sIzenDeiturak,
                                           stBilatutakoa.iDeialdia,
                                           stBilatutakoa.fNota);
        }
    }
    else
    {
        printf("'%s' fitxategia ez da existitzen.\n", sFitxIzen);
    }

    printf("\nPrograma bukatzera doa. Edozein tekla sakatu! ");
    getch();  // itxaron edozein tekla sakatu arte

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


// Funtzio honek fitxategi baten existentzia frogatzen du.
int iFitxategirikBada(const char *sFitxIzen)
{
    FILE *f;

    // Irakurketarako irekitze saiakera ("r" = read)
    f = fopen(sFitxIzen, "rb");

    // Fitxategirik ez balego fopen() funtzioak NULL itzuliko luke
    if (f != NULL)
    {
        fclose(f);  // fitxategia itxi baliabidwak askatzeko
        return 1;   // Itzuli 1 (true): fitxategia bada
    }

    // Fitxategirik ez balego fopen() funtzioak NULL itzuliko luke
    return 0;       // Itzuli 0 (false): fitxategia ez da existitzen
}


void FitxategiaIkusi(const char *sFitxIzen)
{
    FILE *f;
    struct tstFitxa stFitxa;
    int iPos = 0;

    // Irakurketarako irekitze saiakera ("r" = read)
    // Jakina da fitxategia existitzen dela eta errorerik ez dela izango fopen() funtzioan
    f = fopen(sFitxIzen, "rb");

    printf("'%s' fitxategiaren edukia:\n", sFitxIzen);
    while (fread(&stFitxa, sizeof(struct tstFitxa), 1, f) == 1)
    {
        printf("%d. ", iPos);
        printf("Ikaslea: %-20s  Deialdia: %d  Nota: %.2f\n",
               stFitxa.sIzenDeiturak, stFitxa.iDeialdia, stFitxa.fNota);
        iPos++;
    }

    fclose(f);
}


// Bilatzen den gakoa aurkitzean, emaitza den stEmaitza estrukturak
// irakurritako stElem azken elementuaren balioak hartuko ditu.
// Bestela, aurkitzen ez bada, emaitza den stEmaitza estrukturaren
// sIzenDeiturak eremuan null karakterea gordetzen da.
struct tstFitxa stIzenaBilatu(const char *sFitxIzen, const char *sGakoa)
{
    FILE *f;
    struct tstFitxa stElem;
    struct tstFitxa stEmaitza;

    // Irakurketarako irekitze saiakera ("r" = read)
    // Jakina da fitxategia existitzen dela eta errorerik ez dela izango fopen() funtzioan
    f = fopen(sFitxIzen, "rb");

    while (fread(&stElem, sizeof(struct tstFitxa), 1, f) == 1)   // irakurtzeko gai garen bitartean
    {
        if (strcmp(stElem.sIzenDeiturak, sGakoa) == 0)
        {
            fclose(f);
            stEmaitza = stElem;
            return stEmaitza;
        }
    }

    fclose(f);
    strcpy(stEmaitza.sIzenDeiturak, "\0");
    return stEmaitza;
}

iIzenaBilatu() funtzioaren eta stIzenaBilatu() funtzioaren arteko alderaketa irizpide desberdinen arabera:

Irizpidea

return struct

struct* parametro gisa

Kodearen argitasuna

✅ Bai

❌ Zailagoa

Errendimendua egitura txikietan

✅ Nahikoa

❌ Gehiegizkoa izan daiteke

Errendimendua egitura handietan

❌ Kopiak

✅ Eraginkorra

Kanpoko aldaketak

❌ Ez

✅ Bai

Segurtasun eta kontrola

✅ Arrisku gutxi

❌ Arrisku gehiago

Estruktura txikia denean (oso eremu gutxi dituelako eta gainera eremu txikiak direlako) stIzenaBilatu() funtzioa erabil daiteke, baina gehienetan estrukturak handitxoak direlako iIzenaBilatu() funtzioa hobestuko dugu.


Arrayetan egiten zen bezala: Bilaketa arrakastatsua bada, bilatzen dugun gakoa fitxategian aurkitzen da, orduan liIzenaBilatu() funtzioak elementuaren indizea itzuliko dio programa nagusiari. Aldiz, bilaketak arrakastarik ez badu, bilatzen den gakoa fitxategian aurkitzen ez delako, orduan liIzenaBilatu() funtzioak -1 marka itzuliko dio programa nagusiari.

Bilatzen den elementu osoa itzultzen duen aurreko algoritmoa hobesten da. Izan ere, bilatzen den elementuaren indizea itzultzean, arrayetan ez bezala, fitxategietan datuak ikusteko lan eskerga egin behar da DatuakPantailaratu() funtzioan: (1) fitxategia ireki, (2) jauzia egin, (3) elementua fitxategitik irakurri, (4) pantailan erakutsi eta (5) fitxategia itxi.

Erakusten den programa honetan fitxategiaren existentzia frogatzen da programa nagusian, horren arabera:

  • Zehaztutako fitxategiaren edukia pantailaratu
  • Izen bat teklatuz irakurri eta fitxategian bilatzen da, egoera bi hauek aintzat hartzen dira:
    1. Gakoa den izena ez da aurkitzen fitxategian, mezu bat pantailaratzen da
    2. Gakoa den izena fitxategian aurkitzen da, elementu horren datuak pantailaratzen dira
/* Ariketa-79_Fitxategien_4c_algoritmoa: bilaketa bat fitxategian */

// Bilaketaren funtsa prozesu errepikakor honetan datza:
//     while (fread(&stElem, sizeof(struct tstFitxa), 1, f) == 1)
// Non bilaketa arrakastatzua izatean break bitartez eteten den.

// Bilatzen ari den gakoa aurkitzean, elementuaren indizea fitxategian
// itzuliko da:  liIndizea = ftell(f) / sizeof(struct tstFitxa) - 1;
// Bestela, aurkitzen ez bada, -1 marka itzuliko da.

#include <stdio.h>
#include <stdlib.h>   // exit() funtziorako
#include <string.h>   // strcpy() eta strcmp() funtzioetarako
#include <conio.h>    // getche() eta getch() funtzioetarako

#define sBIDEA "C:\\Tokia\\"
#define FITX_IZEN_MAX 120  // fitxategiaren izenerako 119 karaktere gehi null mugatzailea
#define DATU_IZEN_MAX  72  // ikaslearen izena gordetzeko 71 karaktere gehi null mugatzailea

struct tstFitxa
{
    char sIzenDeiturak[DATU_IZEN_MAX];
    int iDeialdia;
    float fNota;
};


int iFitxategirikBada(const char *sFitxIzen);
void FitxategiaIkusi(const char *sFitxIzen);
long liIzenaBilatu(const char *sFitxIzen, const char *sGakoa);
void DatuakPantailaratu(const char *sFitxIzen, long liIndizea);


int main()
{
    char sFitxIzenLaburra[FITX_IZEN_MAX];
    char sFitxIzen[FITX_IZEN_MAX];
    char sGakoa[DATU_IZEN_MAX];
    long liIndizea;

    printf("Fitxategia existitzen da eta datuak ditu\n(adibidez C:\\Tokia\\Ikasleak.DAT)\n\n");
    printf("Fitxategiaren izen laburra eman (adibidez 'Ikasleak'): ");
    gets(sFitxIzenLaburra);

    strcpy(sFitxIzen, sBIDEA);
    strcat(sFitxIzen, sFitxIzenLaburra);
    strcat(sFitxIzen, ".dat");
    printf("Fitxategiaren izen osoa: >>>%s<<<\n\n", sFitxIzen);

    if (iFitxategirikBada(sFitxIzen) == 1)
    {
        printf("'%s' fitxategia existitzen da, lan egin dezagun.\n\n", sFitxIzen);
        printf("---------------------------------------------------------------\n");
        FitxategiaIkusi(sFitxIzen);
        printf("---------------------------------------------------------------\n\n");
        printf("Bilatu nahi den ikaslearen izen deiturak eman: ");
        gets(sGakoa);

        liIndizea = liIzenaBilatu(sFitxIzen, sGakoa);

        if (liIndizea == -1)
            printf("'%s' izeneko ikaslerik ez dago %s fitxategian\n", sGakoa, sFitxIzen);
        else
            DatuakPantailaratu(sFitxIzen, liIndizea);
    }
    else
    {
        printf("'%s' fitxategia ez da existitzen.\n", sFitxIzen);
    }

    printf("\nPrograma bukatzera doa. Edozein tekla sakatu! ");
    getch();  // itxaron edozein tekla sakatu arte

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


// Funtzio honek fitxategi baten existentzia frogatzen du.
int iFitxategirikBada(const char *sFitxIzen)
{
    FILE *f;

    // Irakurketarako irekitze saiakera ("r" = read)
    f = fopen(sFitxIzen, "rb");

    // Fitxategirik ez balego fopen() funtzioak NULL itzuliko luke
    if (f != NULL)
    {
        fclose(f);  // fitxategia itxi baliabidwak askatzeko
        return 1;   // Itzuli 1 (true): fitxategia bada
    }

    // Fitxategirik ez balego fopen() funtzioak NULL itzuliko luke
    return 0;       // Itzuli 0 (false): fitxategia ez da existitzen
}


void FitxategiaIkusi(const char *sFitxIzen)
{
    FILE *f;
    struct tstFitxa stFitxa;
    int iPos = 0;

    // Irakurketarako irekitze saiakera ("r" = read)
    // Jakina da fitxategia existitzen dela eta errorerik ez dela izango fopen() funtzioan
    f = fopen(sFitxIzen, "rb");

    printf("'%s' fitxategiaren edukia:\n", sFitxIzen);
    while (fread(&stFitxa, sizeof(struct tstFitxa), 1, f) == 1)
    {
        printf("%d. ", iPos);
        printf("Ikaslea: %-20s  Deialdia: %d  Nota: %.2f\n",
               stFitxa.sIzenDeiturak, stFitxa.iDeialdia, stFitxa.fNota);
        iPos++;
    }

    fclose(f);
}


// Emaitzaren hasieraketa -1 eta irakurtzeko gai garen bitartean...
// Bilatzen den gakoa aurkitzean, azkenik irakurri den elementuaren
// indizea fitxategian itzuliko da:
//       liIndizea = ftell(f) / sizeof(struct tstFitxa) - 1;
// Bestela, aurkitzen ez bada, -1 marka itzuliko da.
long liIzenaBilatu(const char *sFitxIzen, const char *sGakoa)
{
    FILE *f;
    struct tstFitxa stElem;
    long liIndizea = -1;

    // Irakurketarako irekitze saiakera ("r" = read)
    // Jakina da fitxategia existitzen dela eta errorerik ez dela izango fopen() funtzioan
    f = fopen(sFitxIzen, "rb");

    while (fread(&stElem, sizeof(struct tstFitxa), 1, f) == 1)   // irakurtzeko gai garen bitartean
    {
        if (strcmp(stElem.sIzenDeiturak, sGakoa) == 0)
        {
            liIndizea = ftell(f) / sizeof(struct tstFitxa) - 1;
            break;
        }
    }

    fclose(f);
    return liIndizea;
}


// Fitxategia berriro ireki liIndizea*bytak jauzia egin eta bertan irakurketa
// bat burutu estrukturaren balioak pantailaratzeko, ondoren fitxategia itxi
void DatuakPantailaratu(const char *sFitxIzen, long liIndizea)
{
    FILE *f;
    struct tstFitxa stElem;

    // Irakurketarako irekitze saiakera ("r" = read)
    // Jakina da fitxategia existitzen dela eta errorerik ez dela izango fopen() funtzioan
    f = fopen(sFitxIzen, "rb");

    fseek(f, liIndizea*(long)sizeof(struct tstFitxa), SEEK_SET);
    fread(&stElem, sizeof(struct tstFitxa), 1, f);

    printf("%ld indizea duen ikaslea:\n", liIndizea);
    printf("%35s\n%35u\n%35.2f\n",
           stElem.sIzenDeiturak, stElem.iDeialdia, stElem.fNota);

    fclose(f);
}






  • Ariketa-79_Fitxategien_4a_algoritmoa.cbp | main.c       [hau hobesten da]
  • Ariketa-79_Fitxategien_4b_algoritmoa.cbp | main.c
  • Ariketa-79_Fitxategien_4c_algoritmoa.cbp | main.c  


 

Ariketa 78 | Fitxategiaren existentzia: 3. algoritmoa

ZER DAKIDAN:
Fitxategiak zer diren badakit, eta fitxategiak irekitzeko w, r eta a markak erabili behar ditudala badakit.



ZER IKASIKO DUDAN:
FILE datu-motarekin jarraituz, fitxategi baten existentzia ezagutzeko access() funtzioa ikusiko dut fitxategia irekitzean behar den w, r eta a marka ongi aukeratzeko. Baina, fitxategi baten existentzia ezagutzeko fopen() funtzioa erabiltzen ikasiko dut.

Fitxategi bat irekitzerakoan w, r eta a moduetatik zein aplikatu ahal dugun jakiteko, ezagutu behar dugu fitxategia existitzen den ala ez. Fitxategi baten existentzia frogatzeko access() aipatuko dugu, baina fopen() funtzioaren bitartez egiten ikasiko dugu.

Azpimarra dezagun access() funtzioak ez duela FILE datu-motako parametrorik eta ondorioz programa nagusian erabil daitekeela. Hau da access() funtzioaren prototipoa:

              #include <unistd.h>
              int access(const char *pathname, int how);

Non pathname lehen parametroa irisgarritasuna probatu nahi zaion fitxategiaren izena den (kate bat eta kate bati seinalatzen dion erakuslea), eta, how bigarren parametroak adierazten duen zein diren probatu nahi ditugun sarbide-moduak eta unistd.h liburutegian honako sinboloak definitu dira how parametroan erabiltzeko:

  • F_OK egiazta ezazu fitxategia existitzen den
  • R_OK egiazta ezazu ea fitxategitik irakur daitekeen
  • W_OK egiazta ezazu fitxategia eskuragarri dagoen idazteko
  • X_OK egiazta ezazu fitxategia existitzen den

Azken hiru sinboloetako edozein edo guztiak har daitezke zenbait sarbide-modu aldi berean probatzeko. Baina F_OK erabiltzean, fitxategia existitzen den egiaztatzeko, ezin daiteke beste sinbolorik erabili.

Zer balio itzultzen du access() funtzioak?

  • Zehaztutako sarbidea onartzen bada, access() funtzioak 0 itzuliko du
  • Adierazitako fitxategira ezin bada zehaztutako moduan sartu, access() funtzioak -1 itzuliko du eta errno aldagai orokorrean erroreari dagokion balioa ezarriko du

access() funtzioa oso gomendagarria izan arren, fopen() funtzioa erabil daiteke ere fitxategi baten existencia ziurtatzeko.


Erakusten den programa honetan fitxategiaren existentzia frogatzen da programa nagusian iFitxategirikBada() funtzioari deia eginez, horren arabera:

  • Baldin eta fitxategia bada, ondoko hiru lanak burutuko dira:
    1. Zehaztutako fitxategiaren edukia pantailaratu
    2. Fitxategiari elementu berriak gehitu
    3. Fitxategiaren eduki berria pantailaratu
  • Baldin eta fitxategirik ez bada, ondoko bi lanak burutuko dira:
    1. Fitxategia berriki sortu eta elementuz hornitu
    2. Fitxategiaren edukia pantailaratu

Programa bukatu aurretik, fitxategiari izena aldatuko zaio bere edukia mantenduz.

/* Ariketa-78_Fitxategien_3_algoritmoa: Funtzio berezia erabili ahal da fitxategia
                                        irakurketarako ala idazketarako zabaltzeko */

// iFitxategirikBada() funtzioa programa nagusian erabil daiteke eta hartzen duen
//                     parametro bakarra fitxategiaren izena da.
//                     Fitxategiaren irekitze saiakera burutzen da eta arazoren bat
//                     gertatuz gero, suposatuko da fitxategia ez dela existitzen.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>   // strcpy() funtziorako
#include <ctype.h>    // toupper() funtziorako
#include <conio.h>    // getche() eta getch() funtzioetarako

#define sBIDEA "C:\\Tokia\\"
#define FITX_IZEN_MAX 120  // fitxategiaren izenerako 119 karaktere gehi null mugatzailea
#define DATU_IZEN_MAX  72  // ikaslearen izena gordetzeko 71 karaktere gehi null mugatzailea

struct tstFitxa
{
    char sIzenDeiturak[DATU_IZEN_MAX];
    int iDeialdia;
    float fNota;
};


int iFitxategirikBada(const char sFitxIzen[]);
void DatuakErakutsi(const struct tstFitxa *stFitxa);
void DatuakJaso(struct tstFitxa *stFitxa);
void FitxategiaSortuEtaBete(const char sFitxIzen[]);
void FitxategiaIkusi(const char sFitxIzen[]);
void FitxategiariElementuakGehitu(const char sFitxIzen[]);
void FitxategiaBerrizendatu(const char sFitxIzen[], char sFitxIzenBerria[]);


int main()
{
    char sFitxIzen[FITX_IZEN_MAX];
    char sFitxIzenBerria[FITX_IZEN_MAX];
    char sFitxIzenPath[FITX_IZEN_MAX];

    printf("Fitxategia existitzen da eta datuak ditu\n(adibidez C:\\Tokia\\Ikasleak.DAT)\n\n");
    printf("Fitxategiaren izena eman (adibidez 'Ikasleak.DAT'): ");
    gets(sFitxIzen);

    strcpy(sFitxIzenPath, sBIDEA);
    strcat(sFitxIzenPath, sFitxIzen);
    printf("Fitxategiaren izen osoa: >>>%s<<<\n\n", sFitxIzenPath);

    if (iFitxategirikBada(sFitxIzenPath) == 1)
    {
        printf("'%s' fitxategia existitzen da, lan egin dezagun.\n", sFitxIzenPath);
        FitxategiaIkusi(sFitxIzenPath);
        printf("'%s' fitxategian elementu berria gehituko dugu...\n", sFitxIzenPath);
        FitxategiariElementuakGehitu(sFitxIzenPath);
        FitxategiaIkusi(sFitxIzenPath);
    }
    else
    {
        printf("'%s' fitxategia ez da existitzen, sortuko dugu.\n", sFitxIzenPath);
        FitxategiaSortuEtaBete(sFitxIzenPath);
        FitxategiaIkusi(sFitxIzenPath);
    }

    FitxategiaBerrizendatu(sFitxIzenPath, sFitxIzenBerria);
    printf("Izena bai, baina '%s' fitxategiaren\nedukia ez da aldatu.\n", sFitxIzenBerria);
    FitxategiaIkusi(sFitxIzenBerria);

    printf("\nPrograma bukatzera doa. Edozein tekla sakatu! ");
    getch();  // itxaron edozein tekla sakatu arte

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


// Funtzio honek fitxategi baten existentzia frogatzen du.
int iFitxategirikBada(const char sFitxIzen[])
{
    FILE *f;

    // Irakurketarako irekitze saiakera ("r" = read)
    f = fopen(sFitxIzen, "rb");

    // Fitxategirik ez balego fopen() funtzioak NULL itzuliko luke
    if (f != NULL)
    {
        fclose(f);  // fitxategia itxi baliabidwak askatzeko
        return 1;   // Itzuli 1 (true): fitxategia bada
    }

    // Fitxategirik ez balego fopen() funtzioak NULL itzuliko luke
    return 0;       // Itzuli 0 (false): fitxategia ez da existitzen
}


// Funtzio honek estruktura baten datuak pantailaratzen ditu.
// Parametro bakarra da eta sarrerakoa da, beraz balioz pasatzen da.
void DatuakErakutsi(const struct tstFitxa *stFitxa)
{
    printf("Ikaslea: %-20s  Deialdia: %d  Nota: %.2f\n",
           stFitxa->sIzenDeiturak, stFitxa->iDeialdia, stFitxa->fNota);
}


// Funtzio honek estruktura baten datuak jasotzen ditu. Parametro
// bakarra da eta irteerakoa da, beraz erreferentziaz pasatzen da.
void DatuakJaso(struct tstFitxa *stFitxa)
{
    printf("Ikaslearen izena: ");
    gets(stFitxa->sIzenDeiturak);

    printf("Deialdia: ");
    scanf("%u", &stFitxa->iDeialdia);

    printf("Nota: ");
    scanf("%f", &stFitxa->fNota);
    getchar(); // lerro-berri karakterea kontsumitu
}


// Funtzio honek fitxategiaren izena hartzen du, sarrerako datua da fitxategiaren
// izena aldatzen ez delako. Funtzioan definituko da FILE datu-motatako aldagaia,
// eta funtzioaren hasieran 'fopen' egingo da (r marka irakurtzeko eta b marka
// fitxategi bitarra delako); errorea gertatzen bada irten, bestela datuekin lan
// egin fread() eta fwrite() desberdinak aplikatuz; eta azkenean, funtziotik irten
// baino lehen, fitxategia itxi beharko da 'fclose' bat eginez.
void FitxategiaIkusi(const char sFitxIzen[])
{
    FILE *f;
    struct tstFitxa stFitxa;
    int pos = 0;

    f = fopen(sFitxIzen, "rb");
    if (f == NULL)
    {
        printf("Errorea '%s' fitxategia irekitzean 'FitxategiaIkusi()' funtzioan \a\n", sFitxIzen);
        exit(1);
    }

    printf("%s fitxategiak edukia du:\n", sFitxIzen);
    while (fread(&stFitxa, sizeof(struct tstFitxa), 1, f) == 1)
    {
        printf("%d. ", pos);
        DatuakErakutsi(&stFitxa);
        pos++;
    }
    fclose(f);
}


// Funtzio honek fitxategiaren izena hartzen du, sarrerako datua da fitxategiaren
// izena aldatzen ez delako. Funtzioan definituko da FILE datu-motatako aldagaia,
// eta funtzioaren hasieran 'fopen' egingo da (w marka berria delako eta b marka
// fitxategi bitarra delako); errorea gertatzen bada irten, bestela datuekin lan
// egin fread() eta fwrite() desberdinak aplikatuz; eta azkenean, funtziotik irten
// baino lehen, fitxategia itxi beharko da 'fclose' bat eginez.
void FitxategiaSortuEtaBete(const char sFitxIzen[])
{
    FILE *f;
    struct tstFitxa stFitxa;
    int iKopurua;
    int iKont;

    f = fopen(sFitxIzen, "wb");
    if (f == NULL)
    {
        printf("Errorea '%s' fitxategia irekitzean 'FitxategiaSortuEtaBete()' funtzioan \a\n", sFitxIzen);
        exit(1);
    }

    printf("Zenbat elementu nahi dituzu %s fitxategian? ", sFitxIzen);
    scanf("%d", &iKopurua);
    getchar(); // lerro-berri karakterea kontsumitu

    for (iKont = 0; iKont < iKopurua; iKont++)
    {
        printf("%d posizioko ikaslearen datuak biltzen...\n", iKont);
        DatuakJaso(&stFitxa);
        fwrite(&stFitxa, sizeof(struct tstFitxa), 1, f);
    }

    fclose(f);
}


// Funtzio honek fitxategiaren izena hartzen du, sarrerako datua da fitxategiaren
// izena aldatzen ez delako. Funtzioan definituko da FILE datu-motatako aldagaia,
// eta funtzioaren hasieran 'fopen' egingo da (a marka aldatuko delako eta b marka
// fitxategi bitarra delako); errorea gertatzen bada irten, bestela datuekin lan
// egin fread() eta fwrite() desberdinak aplikatuz; eta azkenean, funtziotik irten
// baino lehen, fitxategia itxi beharko da 'fclose' bat eginez.                                               }
void FitxategiariElementuakGehitu(const char sFitxIzen[])
{
    FILE *f;
    struct tstFitxa stFitxa;
    char cErantz;

    f = fopen(sFitxIzen, "ab");
 // f = fopen(sFitxIzen, "r+b");  edo hau ere, baina gero bukaeran kokatuz...
    if (f == NULL)
    {
        printf("Errorea '%s' fitxategia irekitzean 'FitxategiariElementuakGehitu()' funtzioan \a\n", sFitxIzen);
        exit(1);
    }

    do
    {
        DatuakJaso(&stFitxa);
     // fseek(f, 0L, SEEK_END);  baldin eta irekiera "r+b" moduan egin bada
        fwrite(&stFitxa, sizeof(struct tstFitxa), 1, f);

        printf("Datu gehiagorik gorde nahi duzu? (B/E) ");
        cErantz = getch();
        cErantz = toupper(cErantz);
        printf("%c\n", cErantz);
    } while (cErantz != 'E');

    fclose(f);
}


void FitxategiaBerrizendatu(const char sFitxIzen[], char sFitxIzenBerria[])
{
    char sFitxIzenBerriaPath[FITX_IZEN_MAX];

    printf("Fitxategi berriaren izena eman ezazu: ");
    gets(sFitxIzenBerria);

    strcpy(sFitxIzenBerriaPath, sBIDEA);
    strcat(sFitxIzenBerriaPath, sFitxIzenBerria);

    if (rename(sFitxIzen, sFitxIzenBerriaPath) != 0)
        printf("Errorea fitxategiari izena aldatzean\n");
    else
        strcpy(sFitxIzenBerria, sFitxIzenBerriaPath);
}






  • Ariketa-78_Fitxategien_3_algoritmoa.cbp | main.c  


 

Ariketa 77 | Fitxategi osoa prozesatu: 2. algoritmoa

ZER DAKIDAN:
Array, estruktura eta gainerako datu-motako aldagaien edukiak memorian gordetzen dira eta programa bukatzean informazio hori galtzen da. Datuak modu iraunkorrean mantentzea nahi baditut fitxategiak beharko ditut.



ZER IKASIKO DUDAN:
FILE datu-motarekin jarraituz, fitxategi baten elementu guztiak prozesatzeko eman beharreko urratsak ikasiko ditut. Fitxategi bat osoki prozesatzeko hiru modu ikasiko ditut:
  1. Irakur daitekeen bitartean:   while (fread(&iElem,sizeof(int),1,f) == 1)...
  2. Bukaerara heltzen ez garen bitartean:   while (feof(f) == 0)...
  3. Elementuen kopurua ezagutuz:   for (k=1; k <= liElemKop; k++)...

Erregistroen fitxategi bat sortuta dagoela suposa daiteke eta bere edukia pantailaratuko dugu hiru modu desberdinez. Hiru algoritmoek antzekotasunak dituzte baina desberdintasun nabariak ere bai. Horregatik, programaren A, B eta C hiru bertsioen kodeak ematen dira jarraian.

Arakatu nahi dugun fitxategiaren erregistroen eremuak ezagutu behar ditugula, bai datu-motak eta bai eremuen arteko kokapen erlatiboak. Gogoratu fitxategiaren erregistroen eremuak hauek izango direla:

#define DATU_IZEN_MAX  72  // ikaslearen izena gordetzeko 71 karaktere gehi null mugatzailea
struct tstFitxa
{
    char sIzenDeiturak[DATU_IZEN_MAX];
    int iDeialdia;
    float fNota;
};

Fitxategiaren eduki osoa lantzeko urratsak hauek dira:

  1. Fitxategiaren sFitxIzen izena zehaztu
  2. sFitxIzen izeneko fitxategia irakurketarako ireki fopen() funtzioari r marka emanez
  3. Fitxategitik irakurketak burutu fread() funtzioa aplikatuz eta lortutakoa pantailan idatziz
  4. Eta amaitzeko fitxategia itxi fclose() funtzioari deia eginez

Jakin dezagun fread() funtzioak zenbat elementu irakurri dituen itzultzen duela baldin eta errorerik gertatu ez bada, eta 0 itzultzen duela elementurik irakurtzeko gai ez denean. Horregatik, ondoko hau eginez fread(&stElem, sizeof(struct tstFitxa), 1, f) irakurtzerik badago fread() funtzioak 1 itzuliko du eta irakurtzea ezinezkoa egiten bazaio fread() funtzioak 0 itzuliko du.

Goikoa dela eta, fread() funtzioaren emaitza erabil daiteke prozesu errepikakorra eteteko. Ondoko bi aukera hauek egokiak dira:

  • while ((iElemKop = fread(&stElem, sizeof(struct tstFitxa), 1, f)) == 1) prozesu errepikakorrarekin jarraitu ondo irakurtzen dugun bitartean
  • while ((iElemKop = fread(&stElem, sizeof(struct tstFitxa), 1, f)) != 0) prozesu errepikakorrarekin jarraitu txarto irakurtzen ez dugun bitartean

Erakusten den programa honetan irakurritako iElemKop elementu kopurua ezagutu nahi denez, ondoko hau egiten da   while ((iElemKop = fread(&stElem, sizeof(struct tstFitxa), 1, f)) != 0) baina orokorrean iElemKop aldagaiak zer gordetzen duen frogatzea ez zaigu interesatzen eta goiko bi aukeretatik bat erabiliko digu.

Esan gabe doa, irakurketa bakoitzeko fitxategiaren erakusleak elementu bat aurrera egiten duela eta while kontrol-egituraren prozesu errepikakorra berez etengo dela.

/* Ariketa-77_Fitxategien_2a_algoritmoa: aurretik sortutako fitxategi baten edukia pantailaratzen */

// 'while (fread(&stElem, sizeof(struct tstFitxa), 1, f)) // irakurtzeko gai garen bitartean'
// Hau da, fread() egitean zenbat bloke irakurri diren itzultzen du, irakurtzerik ez
// dagoenean 0 itzultzen du eta horrek esan nahi du fitxategiaren bukaeratik at gaudela.
// Hori frogatzeko iIrakurritakoBlokeKop aldagaia sortu eta begizta horrela planteatu:
// 'while ((iIrakurritakoBlokeKop = fread(&stElem, sizeof(struct tstFitxa), 1, f)) != 0)' edo horrela:
// 'while ((iIrakurritakoBlokeKop = fread(&stElem, sizeof(struct tstFitxa), 1, f)) == 1)'

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

#define FITX_IZEN_MAX 120  // fitxategiaren izenerako 119 karaktere gehi null mugatzailea
#define DATU_IZEN_MAX  72  // ikaslearen izena gordetzeko 71 karaktere gehi null mugatzailea

struct tstFitxa
{
    char sIzenDeiturak[DATU_IZEN_MAX];
    int iDeialdia;
    float fNota;
};

void DatuakErakusten(const char sFitxIzen[]);

int main()
{
    char sFitxIzen[FITX_IZEN_MAX];

    printf("Fitxategia lehendik existitzen da eta datuak ditu.\n");
    printf("Fitxategiaren izena eman (adibidez 'Datuak.DAT'): ");
    gets(sFitxIzen);

    printf("'%s' fitxategiaren edukia erakusten...\n\n", sFitxIzen);
    DatuakErakusten(sFitxIzen);

    printf("\nPrograma bukatzera doa. Edozein tekla sakatu! ");
    getch();  // itxaron edozein tekla sakatu arte

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


void DatuakErakusten(const char sFitxIzen[])
{
    FILE *f;
    struct tstFitxa stElem;
    int iPosizioa;
    int iIrakurritakoBlokeKop;

    // fitxategi bitarra irakurketa moduan ireki
    f = fopen(sFitxIzen, "rb");

    if (f == NULL)
    {
        printf("Errorea '%s' fitxategia irekitzean 'DatuakErakusten()' funtzioan \a\n", sFitxIzen);
    }
    else
    {
        // fitxategiko datuak banan-banan irakurri eta pantailan erakutsi
        iPosizioa = 0;
        while ((iIrakurritakoBlokeKop = fread(&stElem, sizeof(struct tstFitxa), 1, f)) != 0)   // irakurtzeko gai garen bitartean
        // while (fread(&stElem, sizeof(struct tstFitxa), 1, f))   // laburrago, iIrakurritakoBlokeKop aldagairik gabe
        {
            printf("while barruan, iIrakurritakoBlokeKop = %d\n", iIrakurritakoBlokeKop);
            printf("%10d. ikaslearen datuak: | %-20s | %d | %.2f |\n",
                   iPosizioa, stElem.sIzenDeiturak, stElem.iDeialdia, stElem.fNota);
            iPosizioa++;
        }
        printf("\nwhile kanpoan, iIrakurritakoBlokeKop = %d\n", iIrakurritakoBlokeKop);
        printf("iPosizioa=%d (%d da ere ikasleen kopurua)\n", iPosizioa, iPosizioa);

        fclose(f);
    }
}


Jakin dezagun EndOfFile markaren gainean gaudenean irakur daitekeela fitxategitik eta feof() funtzioak 0 itzuliko duela, berdin gertatzen da fitxategiaren uneko erakuslea kokaturik badago EndOfFile markaren baino lehen, hots, irakurketan errorerik ez da gertatzen eta feof() funtzioak 0 itzuliko duela. Baina, fitxategiaren posizio markatzailea kokatzen bada EndOfFile markaren baino haratago eta irakurketa bat saiatzen bada, ez da posible izango eta feof() funtzioak 0 ez den zerbait itzuliko duela.

Erakusten den programa honetan, printf() desberdinak idatzi dira ikusi ahal izateko EndOfFile marka zein elementutan dagoen une bakoitzean eta feof() funtzioak zer itzultzen duen.

Esan bezala, EndOfFile markatik haratago irakurketa bat egin behar denez fitxategiaren amaiera heldu dela jakiteko eta while kontrol-egituraren prozesu errepikakorra eteteko, horregatik azken irakurketa ez da aintzakotzat hartuko eta hori kontrolatzeko if baten beharra daukagu.

/* Ariketa-77_Fitxategien_2b_algoritmoa: aurretik sortutako fitxategi baten edukia pantailaratzen */

// 'while (feof(f) == 0) // bukaeratik harat irakurtzen ez dugun bitartean...'
// Hau da, fitxategiaren amaiera markan gaudenean feof() funtzioak oraindik 0 itzultzen du,
// amaiera markatik haratago irakurtzen saiatzean feof() funtzioak 0 ez den zerbait itzuliko du.
// Beraz, azken elementua irakurri ondoren beste irakurketa bat gehiago beharko dugu feof()
// funtzioaren bitartez jakiteko fitxategia bukatu dela, horregatik azken if agindua.

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

#define FITX_IZEN_MAX 120  // fitxategiaren izenerako 119 karaktere gehi null mugatzailea
#define DATU_IZEN_MAX  72  // ikaslearen izena gordetzeko 71 karaktere gehi null mugatzailea

struct tstFitxa
{
    char sIzenDeiturak[DATU_IZEN_MAX];
    int iDeialdia;
    float fNota;
};

void DatuakErakusten(const char sFitxIzen[]);

int main()
{
    char sFitxIzen[FITX_IZEN_MAX];

    printf("Fitxategia lehendik existitzen da eta datuak ditu.\n");
    printf("Fitxategiaren izena eman (adibidez '4ikasle.DAT'): ");
    gets(sFitxIzen);

    printf("'%s' fitxategiaren edukia erakusten...\n", sFitxIzen);
    DatuakErakusten(sFitxIzen);

    printf("\nPrograma bukatzera doa. Edozein tekla sakatu! ");
    getch();  // itxaron edozein tekla sakatu arte

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


void DatuakErakusten(const char sFitxIzen[])
{
    FILE *f;
    struct tstFitxa stElem;
    int iPosizioa;

    // fitxategi bitarra irakurketa moduan ireki
    f = fopen(sFitxIzen, "rb");

    if (f == NULL)
    {
        printf("Errorea '%s' fitxategia irekitzean 'DatuakErakusten()' funtzioan \a\n", sFitxIzen);
    }
    else
    {
       iPosizioa = 0;
       long lZenbatBit;
       while (feof(f) == 0)    // bukaeran ez gauden bitartean...
       {
           printf("\n");
           lZenbatBit = ftell(f);
           printf("---fread() baino lehen:   Elem=%d eta feof(f)=%d\n", (int)(lZenbatBit/sizeof(stElem)), (int)feof(f));

           fread(&stElem, sizeof(struct tstFitxa), 1, f);   // elementu bat irakurri eta bukaera markatik...
           if (feof(f) == 0)                         // ...haratago ez bagaude pantailaratu
           {
               printf("%d. ikaslearen datuak: | %-15s | %d | %.2f |\n",
                      iPosizioa, stElem.sIzenDeiturak, stElem.iDeialdia, stElem.fNota);
               lZenbatBit = ftell(f);
               printf("---fread() eginda gero:   Elem=%d eta feof(f)=%d\n", (int)(lZenbatBit/sizeof(stElem)), (int)feof(f));
               iPosizioa++ ;
           }
           else
           {
               printf("%d. ikaslearen datuak irakurri nahiean...\n", (int)(lZenbatBit/sizeof(stElem)));
               printf("===fread() bukaerako markan egitean  feof(f)=%d\n\n", (int)feof(f));
           }
       }
       printf("iPosizioa=%d (%d da ere ikasleen kopurua)\n", iPosizioa, iPosizioa) ;

       fclose(f);
    }
}


Fitxategiak zenbat elementu dituen ezaguna balitz, ez genuke while kontrol-egiturarik beharko eta for batekin aski izango genuke fitxategi osoa prozesatzeko. Ariketa-76_Fitxategien_1c_algoritmoa ariketan ikasi genuen kalkulatzen fitxategiaren elementu kopurua. Gogoratu behar diren funtzioak hauek direla:

  • fseek() fitxategiaren bukaeran kokatzeko,
  • ftell() byte kopurua ezagutzeko eta
  • sizeof() elementuen kopurua kalkulatzeko.
/* Ariketa-77_Fitxategien_2c_algoritmoa: aurretik sortutako fitxategi baten edukia pantailaratzen */

// Fitxategiaren elementu kopurua kalkulatu ondoren for egitura errepikakor
// bat erabiliko da fitxategiaren elementu guztiak banan-banan prozesatzeko.
// Horretarako fseek() funtzioa eta ftell() funtzioa funtsezkoak dira.

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

#define FITX_IZEN_MAX 120  // fitxategiaren izenerako 119 karaktere gehi null mugatzailea
#define DATU_IZEN_MAX  72  // ikaslearen izena gordetzeko 71 karaktere gehi null mugatzailea

struct tstFitxa
{
    char sIzenDeiturak[DATU_IZEN_MAX];
    int iDeialdia;
    float fNota;
};

void DatuakErakusten(const char sFitxIzen[]);
void DatuakBirritanErakusten(const char sFitxIzen[]);

int main()
{
    char sFitxIzen[FITX_IZEN_MAX];

    printf("Fitxategia lehendik existitzen da eta datuak ditu.\n");
    printf("Fitxategiaren izena eman (adibidez 'Datuak.DAT'): ");
    gets(sFitxIzen);

    printf("'%s' fitxategiaren edukia erakusten...\n", sFitxIzen);
    DatuakErakusten(sFitxIzen);
    printf("\n");
    printf("'%s' fitxategiaren edukia birritan erakusten...\n", sFitxIzen);
    DatuakBirritanErakusten(sFitxIzen);

    printf("\nPrograma bukatzera doa. Edozein tekla sakatu! ");
    getch();  // itxaron edozein tekla sakatu arte

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


void DatuakErakusten(const char sFitxIzen[])
{
    FILE *f;
    struct tstFitxa stElem;
    long liZenbatBit;
    int iKont;

    // fitxategi bitarra irakurketa moduan ireki
    f = fopen(sFitxIzen, "rb");

    if (f == NULL)
    {
        printf("Errorea '%s' fitxategia irekitzean 'DatuakErakusten()' funtzioan \a\n", sFitxIzen);
    }
    else
    {
        // fitxategiaren bukaeran kokatu
        fseek(f, 0L, SEEK_END);

        // fitxategiaren tamaina kalkulatu
        liZenbatBit = ftell(f);

        // fitxategiaren hasieran kokatu
        fseek(f, 0L, SEEK_SET);

        // elementu guztiak prozesatu...
        for (iKont = 1; iKont <= liZenbatBit/sizeof(struct tstFitxa); iKont++)
        {
            fread(&stElem, sizeof(struct tstFitxa), 1, f);   // elementu bat irakurri eta...
            printf("%d. ikaslearen datuak: | %-20s | %d | %.2f |\n",
                   iKont, stElem.sIzenDeiturak, stElem.iDeialdia, stElem.fNota);
        }
        printf("Irten eta gero iKont=%d \n", iKont) ;

        fclose(f);
    }
}


void DatuakBirritanErakusten(const char sFitxIzen[])
{
    FILE *f;
    struct tstFitxa stElem;
    long liZenbatBit;
    int iKont;

    // fitxategi bitarra irakurketa moduan ireki
    f = fopen(sFitxIzen, "rb");

    if (f == NULL)
    {
        printf("Errorea '%s' fitxategia irekitzean 'DatuakBirritanErakusten()' funtzioan \a\n", sFitxIzen);
    }
    else
    {
        // fitxategiaren bukaeran kokatu
        fseek(f, 0L, SEEK_END);

        // fitxategiaren tamaina kalkulatu
        liZenbatBit = ftell(f);

        // fitxategiaren hasieran kokatu
        fseek(f, 0L, SEEK_SET);

        // elementu guztiak prozesatu...
        for (iKont = 1; iKont <= liZenbatBit/sizeof(struct tstFitxa); iKont++)
        {
            fread(&stElem, sizeof(struct tstFitxa), 1, f);    // elementu bat irakurri eta...
            printf("%d. ikaslearen datuak (1): | %-20s | %d | %.2f |\n",
                   iKont, stElem.sIzenDeiturak, stElem.iDeialdia, stElem.fNota);
            fseek(f, (-1)*sizeof(struct tstFitxa), SEEK_CUR); // fitxategian posizio bat atzera
            fread(&stElem, sizeof(struct tstFitxa), 1, f);    // elementu bat irakurri eta...
            printf("%d. ikaslearen datuak (2): | %-20s | %d | %.2f |\n",
                   iKont, stElem.sIzenDeiturak, stElem.iDeialdia, stElem.fNota);
        }
        printf("Irten eta gero iKont=%d \n", iKont) ;

        fclose(f);
    }
}






  • Ariketa-77_Fitxategien_2a_algoritmoa.cbp | main.c  
  • Ariketa-77_Fitxategien_2b_algoritmoa.cbp | main.c  
  • Ariketa-77_Fitxategien_2c_algoritmoa.cbp | main.c  


 

Ariketa 76 | Fitxategia sortu: 1. algoritmoa

ZER DAKIDAN:
Array, estruktura eta gainerako datu-motako aldagaien edukiak memorian gordetzen dira eta programa bukatzean informazio hori galtzen da. Datuak modu iraunkorrean mantentzea nahi baditut fitxategiak beharko ditut.



ZER IKASIKO DUDAN:
FILE datu-mota ikasiko dut. Estrukturen fitxategiak nola sor daitezkeen ikasiko dut eta, modu beretsuan, zenbakien fitxategiak nola sor daitezkeen ikasiko dut ere.

Erregistroen fitxategi bat sortuko dugu hiru modu desberdinez. Algoritmoa, funtsean, bat da baina aldaketa txiki batzuk egingo ditugu programaren A, B eta C hiru bertsio kodetuz.

Fitxategiaren erregistroen eremuak hauek izango dira:

#define DATU_IZEN_MAX  72  // ikaslearen izena gordetzeko 71 karaktere gehi null mugatzailea
struct tstFitxa
{
    char sIzenDeiturak[DATU_IZEN_MAX];
    int iDeialdia;
    float fNota;
};

Fitxategia sortzeko eta datuz betetzeko urratsak hauek dira:

  1. Fitxategiaren sFitxIzen izena zehaztu
  2. sFitxIzen izeneko fitxategia sortu fopen() funtzioari w marka emanez
  3. Fitxategian idazketak burutu fwrite() funtzioa aplikatuz
  4. Eta amaitzeko fitxategia itxi fclose() funtzioari deia eginez

Berezitasun bezala, lPosizioa aldagaiari esker informatzen zaio erabiltzaileari zein elementutan burutuko den hurrengo idazketa. Laguntzailea den lPosizioa aldagaia inkrementatuz doa while kontrol-egituran eta prozesu errepikakor hori eteteko cErantz aldagaia erabiltzen da.

/* Ariketa-76_Fitxategien_1a_algoritmoa: fitxategi bat berriki sortu eta datuz bete */

// Berezitasun bezala, lPosizioa aldagaiari esker informatzen zaio
// erabiltzaileari zein elementutan burutuko den hurrengo idazketa.

#include <stdio.h>
#include <string.h>   // strcspn() funtziorako
#include <ctype.h>    // toupper() funtziorako
#include <conio.h>    // getche() eta getch() funtzioetarako

#define FITX_IZEN_MAX 120  // fitxategiaren izenerako 119 karaktere gehi null mugatzailea
#define DATU_IZEN_MAX  72  // ikaslearen izena gordetzeko 71 karaktere gehi null mugatzailea

struct tstFitxa
{
    char sIzenDeiturak[DATU_IZEN_MAX];
    int iDeialdia;
    float fNota;
};


void DatuakBiltegitzen(const char sFitxIzen[]);


int main()
{
    char sFitxIzen[FITX_IZEN_MAX];

    printf("Fitxategiaren izena eman ('Datuak.DAT' adibidez): ");
    gets(sFitxIzen);

    printf("Ikasleen datuak '%s' fitxategian gordetzen...\n\n", sFitxIzen);
    DatuakBiltegitzen(sFitxIzen);

    printf("\nPrograma bukatzera doa. Edozein tekla sakatu! ");
    getch();  // itxaron edozein tekla sakatu arte

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


void DatuakBiltegitzen(const char sFitxIzen[])
{
    FILE *f;
    struct tstFitxa stElem;
    long lPosizioa;
    char cErantz;

    // fitxategi bitarra sortu idazketarako
    f = fopen(sFitxIzen, "wb");
    if (f == NULL)
    {
        printf("Errorea '%s' fitxategia irekitzean 'DatuakBiltegitzen()' funtzioan \a\n", sFitxIzen);
    }
    else
    {
        lPosizioa = -1;
        do
        {
            lPosizioa++;
            printf("Eman %ld posizioko ikaslearen izen-deiturak: ", lPosizioa);
            gets(stElem.sIzenDeiturak);

            printf("Eman ikaslearen deialdia: ");
            scanf("%d", &stElem.iDeialdia);

            printf("Eman ikaslearen nota: ");
            scanf("%f", &stElem.fNota);
            getchar(); // lerro-berri karakterea kontsumitu

            printf("Ikaslearen datuak: | %-15s | %d | %.2f |\n\n", stElem.sIzenDeiturak, stElem.iDeialdia, stElem.fNota);

            // datuak banan-banan fitxategian idatzi
            fwrite(&stElem, sizeof(struct tstFitxa), 1, f);

            printf("Gehiagorik? (B/E) ");
            cErantz = getch();
            cErantz = toupper(cErantz);
            printf("%c\n", cErantz);
        } while (cErantz != 'E');

        fclose(f);
    }
}


Berezitasun bezala, fgetpos() funtzioa erabiltzen da erabiltzaileari informatzeko fitxategiaren zein elementutan burutuko den hurrengo idazketa. Idazketa edo irakurketa baten ostean berez inkrementatzen da fgetpos() funtzioaren balioa. Bertsio honetan ere while kontrol-egituraren prozesu errepikakorra eteteko cErantz aldagaia erabiltzen da.

/* Ariketa-76_Fitxategien_1b_algoritmoa: fitxategi bat berriki sortu eta datuz bete */

// Berezitasun bezala fgetpos() funtzioa erabiltzen da jakiteko fitxategiaren
// zein posiziotan burutuko den hurrengo irakurketa edo hurrengo idazketa.

#include <stdio.h>
#include <string.h>   // strcspn() funtziorako
#include <ctype.h>    // toupper() funtziorako
#include <conio.h>    // getche() eta getch() funtzioetarako

#define FITX_IZEN_MAX 120  // fitxategiaren izenerako 119 karaktere gehi null mugatzailea
#define DATU_IZEN_MAX  72  // ikaslearen izena gordetzeko 71 karaktere gehi null mugatzailea

struct tstFitxa
{
    char sIzenDeiturak[DATU_IZEN_MAX];
    int iDeialdia;
    float fNota;
};


void DatuakBiltegitzen(const char sFitxIzen[]);


int main()
{
    char sFitxIzen[FITX_IZEN_MAX];

    printf("Fitxategiaren izena eman ('Datuak.DAT' adibidez): ");
    gets(sFitxIzen);

    printf("Ikasleen datuak '%s' fitxategian gordetzen...\n\n", sFitxIzen);
    DatuakBiltegitzen(sFitxIzen);

    printf("\nPrograma bukatzera doa. Edozein tekla sakatu! ");
    getch();  // itxaron edozein tekla sakatu arte

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


void DatuakBiltegitzen(const char sFitxIzen[])
{
    FILE *f;
    struct tstFitxa stElem;
    char cErantz;
    long liPosizioa;

    // fitxategi bitarra sortu idazketarako
    f = fopen(sFitxIzen, "wb");
    if (f == NULL)
    {
        printf("Errorea '%s' fitxategia irekitzean 'DatuakBiltegitzen()' funtzioan \a\n", sFitxIzen);
    }
    else
    {
        liPosizioa = ftell(f);
        printf("\nHasieran,     ftell(f)=%ld     ftell(f)/sizeof()=%d\n", liPosizioa, (int)(liPosizioa/sizeof(struct tstFitxa)));
        do
        {
            liPosizioa = ftell(f);
            printf("Eman %ld posizioko ikaslearen izen-deiturak: ", (long)(liPosizioa/sizeof(struct tstFitxa)));
            gets(stElem.sIzenDeiturak);

            printf("Eman ikaslearen deialdia: ");
            scanf("%d", &stElem.iDeialdia);

            printf("Eman ikaslearen nota: ");
            scanf("%f", &stElem.fNota);
            getchar(); // lerro-berri karakterea kontsumitu

            printf("Ikaslearen datuak: | %-15s | %d | %.2f |\n", stElem.sIzenDeiturak, stElem.iDeialdia, stElem.fNota);

            // datuak banan-banan fitxategian idatzi
            fwrite(&stElem, sizeof(struct tstFitxa), 1, f);

            liPosizioa = ftell(f);
            printf("Idatzi ondoren,     ftell(f)=%ld     ftell(f)/sizeof()=%ld\n\n", liPosizioa, (long)(liPosizioa/sizeof(struct tstFitxa)));

            printf("Gehiagorik? (B/E) ");
            cErantz = getch();
            cErantz = toupper(cErantz);
            printf("%c\n", cErantz);
        } while (cErantz != 'E');

        fclose(f);
    }
}


C bertsio hau lehen ikusitako A bertsio bera da algoritmia aldetik, bakarrik, hori bai, kode zati bat gehitu zaio FitxategiarenBytak() funtzioaren bitartez jakiteko fitxategiak zenbat elementu biltegitu dituen. Elementuen kopurua ezagutzeko funtzio hauek aplikatu beharko dira:

  • fseek() fitxategiaren bukaeran kokatzeko,
  • ftell() byte kopurua ezagutzeko eta
  • sizeof() elementuen kopurua kalkulatzeko.
/* Ariketa-76_Fitxategien_1c_algoritmoa: fitxategi bat berriki sortu eta datuz bete
                                         bukaeran fitxategiaren tamaina bytetan lortzen
                                         da eta fitxategiaren elementuen kopurua ere. */

// Horretarako fseek() funtzioa, ftell() funtzioa eta sizeof() funtzioa beharko dira.

#include <stdio.h>
#include <string.h>   // strcspn() funtziorako
#include <ctype.h>    // toupper() funtziorako
#include <conio.h>    // getche() eta getch() funtzioetarako

#define FITX_IZEN_MAX 120  // fitxategiaren izenerako 119 karaktere gehi null mugatzailea
#define DATU_IZEN_MAX  72  // ikaslearen izena gordetzeko 71 karaktere gehi null mugatzailea


struct tstFitxa
{
    char sIzenDeiturak[DATU_IZEN_MAX];
    int iDeialdia;
    float fNota;
};


void DatuakBiltegitzen(const char sFitxIzen[]);
long liFitxategiarenBytak(const char sFitxIzen[]);


int main()
{
    char sFitxIzen[FITX_IZEN_MAX];
    long lByteKop;

    printf("Fitxategiaren izena eman ('Datuak.DAT' adibidez): ");
    gets(sFitxIzen);

    printf("Ikasleen datuak '%s' fitxategian gordetzen...\n\n", sFitxIzen);
    DatuakBiltegitzen(sFitxIzen);

    printf("\n");

    lByteKop = liFitxategiarenBytak(sFitxIzen);
    if (lByteKop != -1)
    {
        printf("Fitxategiaren tamaina: %ld bytes \n", lByteKop);
        printf("Elementuen kopurua: %ld fitxa \n", (long)(lByteKop/sizeof(struct tstFitxa)));
    }
    printf("[tstFitxa = char sIzenDeiturak[DATU_IZEN_MAX] + Int + Float]  [%ld = %ld + %ld + %ld]\n",
           (long)sizeof(struct tstFitxa), (long)sizeof(char [DATU_IZEN_MAX]), (long)sizeof(int), (long)sizeof(float));

    printf("\n");

    printf("\nPrograma bukatzera doa. Edozein tekla sakatu! ");
    getch();  // itxaron edozein tekla sakatu arte

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


void DatuakBiltegitzen(const char sFitxIzen[])
{
    FILE *f;
    struct tstFitxa stElem;
    int iPosizioa;
    char cErantz;

    // fitxategi bitarra sortu idazketarako
    f = fopen(sFitxIzen, "wb");
    if (f == NULL)
    {
        printf("Errorea '%s' fitxategia irekitzean 'DatuakBiltegitzen()' funtzioan \a\n", sFitxIzen);
    }
    else
    {
        iPosizioa = -1;
        do
        {
            iPosizioa++;
            printf("Eman %d posizioko ikaslearen izen-deiturak: ", iPosizioa);
            gets(stElem.sIzenDeiturak);

            printf("Eman ikaslearen deialdia: ");
            scanf("%d", &stElem.iDeialdia);

            printf("Eman ikaslearen nota: ");
            scanf("%f", &stElem.fNota);
            getchar(); // lerro-berri karakterea kontsumitu

            printf("Ikaslearen datuak: | %-15s | %d | %.2f |\n\n", stElem.sIzenDeiturak, stElem.iDeialdia, stElem.fNota);

            // datuak banan-banan fitxategian idatzi
            fwrite(&stElem, sizeof(stElem), 1, f);

            printf("Gehiagorik? (B/E) ");
            cErantz = getch();
            cErantz = toupper(cErantz);
            printf("%c\n", cErantz);
        } while (cErantz != 'E');

        fclose(f);
    }
}


long liFitxategiarenBytak(const char sFitxIzen[])
{
    long lZenbatBit;

    // fitxategia irakurketarako zabaldu
    FILE* fp = fopen(sFitxIzen, "rb");

    // aztertu fitxategia existitzen den ala ez
    if (fp == NULL)
    {
        printf("Errorea '%s' fitxategia irekitzean 'liFitxategiarenBytak()' funtzioan \a\n", sFitxIzen);
        return -1;
    }

    // fitxategiaren bukaeran kokatu
    fseek(fp, 0L, SEEK_END);

    // fitxategiaren tamaina kalkulatu
    lZenbatBit = ftell(fp);

    // fitxategia itxi
    fclose(fp);

    return lZenbatBit;
}


D bertsio honetan zenbaki osoen fitxategi bat sortuko da. Elementuen kopurua erabakitzeko erabiltzaileak teklatuz emango du iZenbatElementu aldagaiari balio positibo bat emanez. Fitxategiaren datuak auzaz aukeratuko dira rand() funtzioari esker.

/* Ariketa-76_Fitxategien_1d_algoritmoa: fitxategia sortu eta erakutsi */

// Berezitasun bezala, fitxategiaren balioak 0 eta 99 arteko
// kopuru osoak auzaz aukeratzen ditu programak. Erabiltzaileak
// erabakitzen du fitxategiak zenbat elementu izango dituen.

#include <stdio.h>
#include <stdlib.h>   // srand() eta rand() funtzioetarako
#include <string.h>   // strcspn() funtziorako
#include <time.h>     // time() funtziorako
#include <conio.h>    // getch() funtziorako

#define FITX_IZEN_MAX 120  // fitxategiaren izenerako 119 karaktere gehi null mugatzailea

void FitxategiarenEdukiaIkusi(const char sFitxIzen[]);
void FitxategiaSortuEtaBete(const char sFitxIzen[]);

int main()
{
    char sFitxIzen[FITX_IZEN_MAX];

    printf("Fitxategiaren izena eman ('Kopuruak.DAT' adibidez): ");
    fgets(sFitxIzen, sizeof(sFitxIzen), stdin);
    sFitxIzen[strcspn(sFitxIzen, "\n")] = 0; // lerro-berri karakterea kendu

    printf("Ikasleen datuak '%s' fitxategian gordetzen...\n\n", sFitxIzen);
    FitxategiaSortuEtaBete(sFitxIzen);

    printf("Fitxategiaren elementu guztiak pantailaratuko ditugu. Hona hemen...\n");
    FitxategiarenEdukiaIkusi(sFitxIzen);

    printf("\nPrograma bukatzera doa. Edozein tekla sakatu! ");
    getch();  // itxaron edozein tekla sakatu arte

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


void FitxategiarenEdukiaIkusi(const char sFitxIzen[])
{
    FILE *fFitxategia = fopen(sFitxIzen, "rb");
    if (!fFitxategia)
    {
        printf("Errorea '%s' fitxategia irekitzean 'FitxategiarenEdukiaIkusi()' funtzioan \a\n", sFitxIzen);
        return;
    }

    int iElem, iPosizioa = 0;
    printf("Fitxategiaren edukia:\n");
    while (fread(&iElem, sizeof(int), 1, fFitxategia) == 1)
    {
        printf("%8d. elementua = %2d\n", iPosizioa, iElem);
        iPosizioa++;
    }
    printf("\n");
    fclose(fFitxategia);
}


void FitxategiaSortuEtaBete(const char sFitxIzen[])
{
    FILE *f;
    int iElem;
    int iKopurua;

    f = fopen(sFitxIzen, "wb");
    if (!f)
    {
        printf("Errorea '%s' fitxategia irekitzean 'FitxategiaSortuEtaBete()' funtzioan \a\n", sFitxIzen);
        return;
    }
    do
    {
        printf("Zenbat elementu nahi dituzu '%s' fitxategian? ", sFitxIzen);
        scanf("%d", &iKopurua);
        getchar(); // bufferra garbitu
        if (iKopurua <= 0)
            printf("Gutxienez elementu 1 behar da\n");
    } while (iKopurua <= 0);

    srand(time(NULL));
    for (int iKont = 0; iKont < iKopurua; iKont++)
    {
        iElem = rand()%100;
        fwrite(&iElem, sizeof(int), 1, f);
    }
    fclose(f);
}


E bertsio honetan zenbaki errealen fitxategi bat sortuko da. Elementuen kopurua erabakitzeko rand() funtzioa erabiliko da. Fitxategiaren datuak auzaz aukeratuko dira rand() funtzioari esker, 0.0 eta 9.9 artekoak izango dira.

/* Ariketa-76_Fitxategien_1e_algoritmoa: fitxategia sortu eta erakutsi */

// Berezitasun bezala, fitxategiaren balioak 0.0 eta 9.9 arteko
// kopuru osoak auzaz aukeratzen ditu programak. Fitxategiak
// zenbat elementu izango dituen programak erabakitzen du ere.

#include <stdio.h>
#include <stdlib.h>   // srand() eta rand() funtzioetarako
#include <string.h>   // strcspn() funtziorako
#include <time.h>     // time() funtziorako
#include <conio.h>    // getch() funtziorako

#define FITX_IZEN_MAX 120  // fitxategiaren izenerako 119 karaktere gehi null mugatzailea

void FitxategiarenEdukiaIkusi(const char sFitxIzen[]);
void FitxategiaSortuEtaBete(const char sFitxIzen[]);

int main()
{
    char sFitxIzen[FITX_IZEN_MAX];

    printf("Fitxategiaren izena eman ('Zenbakiak.DAT' adibidez): ");
    gets(sFitxIzen);

    printf("Ikasleen datuak '%s' fitxategian gordetzen...\n\n", sFitxIzen);
    FitxategiaSortuEtaBete(sFitxIzen);

    printf("Fitxategiaren elementu guztiak pantailaratuko ditugu. Hona hemen...\n");
    FitxategiarenEdukiaIkusi(sFitxIzen);

    printf("\nPrograma bukatzera doa. Edozein tekla sakatu! ");
    getch();  // itxaron edozein tekla sakatu arte

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


void FitxategiarenEdukiaIkusi(const char sFitxIzen[])
{
    FILE *fFitxategia = fopen(sFitxIzen, "rb");
    float fElem;
    int iPosizioa = 0;

    if (!fFitxategia)
    {
        printf("Errorea '%s' fitxategia irekitzean 'FitxategiarenEdukiaIkusi()' funtzioan \a\n", sFitxIzen);
        return;
    }
    printf("Fitxategiaren edukia:\n");
    while (fread(&fElem, sizeof(float), 1, fFitxategia) == 1)
    {
        printf("%8d. elementua = %.1f\n", iPosizioa, fElem);
        iPosizioa++;
    }
    printf("\n");
    fclose(fFitxategia);
}


void FitxategiaSortuEtaBete(const char sFitxIzen[])
{
    FILE *f;
    float fElem;
    int iZenbatElementu;

    f = fopen(sFitxIzen, "wb");
    if (!f)
    {
        printf("Errorea '%s' fitxategia irekitzean 'FitxategiaSortuEtaBete()' funtzioan \a\n", sFitxIzen);
        return;
    }
    srand(time(NULL));
    iZenbatElementu = rand()%11 + 5;   // 0+5=5 eta 10+5=15 arteko kopuru bat
    printf("'%s' fitxategiak %d elementu gordeko ditu\n", sFitxIzen, iZenbatElementu);

    for (int iKont = 0; iKont < iZenbatElementu; iKont++)
    {
        int iHamarrekoa = rand()%10;
        fElem = rand()%10 + 0.1*iHamarrekoa;
        fwrite(&fElem, sizeof(float), 1, f);
    }
    fclose(f);
}






  • Ariketa-76_Fitxategien_1a_algoritmoa.cbp | main.c  
  • Ariketa-76_Fitxategien_1b_algoritmoa.cbp | main.c  
  • Ariketa-76_Fitxategien_1c_algoritmoa.cbp | main.c  
  • Ariketa-76_Fitxategien_1d_algoritmoa.cbp | main.c  
  • Ariketa-76_Fitxategien_1e_algoritmoa.cbp | main.c  


 

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

Ariketa 63 | Eratostenes-en bahea (I)

ZER DAKIDAN:
Arrayak ezagutzen ditut.



ZER IKASIKO DUDAN:
Zenbaki osoen bi dimentsiotako array baten ariketa bat programatuko dut emaniko algoritmoa jarraituz. Ariketa hau hobeto programatzen da laster ikusiko den erregistroen (edo struct datu-mota) array bat erabiliz.

Galbahe (edo bahe) baten irudia. Galbaheri esker aleak sailka daitezkeen bezala, zenbaki zerrenda bati galbahe logikoren bat aplikatuz zenbakien segida desberdinak lor daitezke, adibidez: zenbaki lehenak identifikatzeko Eratostenes matematikari greziarrak asmatutakoa

Ariketa honi bi modutan ekingo diogu:





Eratostenes (antzinako grezieraz: Ἐρατοσθένης; K.a. 276 inguru - K.a. 195 inguru) matematikari, geografo, kirolari, poeta eta astronomo greziarra izan zen. Alexandriako Liburutegia famatuaren zuzendari izendatu zuten eta aurkikuntza ugari egin zituen, hala nola, latitude eta longitude sistema. Eratostenes ezaguna da Lurraren zirkunferentzia kalkulatzen lehen greziarra izan zelako, baita Lurraren ardatzak duen makurdura. Bestalde, garaiko ezagutza geografikoaren araberako mundu mapa eratu zuen ere. 

                   
 

Eratostenes-en bahea zenbaki lehenak aurkitzeko algoritmo bat da, emandako n zenbaki arrunt bat baino txikiagoak direnen artean.

Lehendabizi, taula bat egiten da 2 eta n arteko zenbaki arruntekin, jarraian multiploak markatzen dira hurrengo ordena jarraituz:

  • 2tik hasita, haren multiplo guztiak markatzen dira, ostean, hurrengo zenbakiarekin jarraituko da baina bi egoera daude:
    • Hurrengo zenbakia markaturik gabe dago, adibidez 3 zenbakia, eta lehen bezala bere multiplo guztiak markatzen dira
    • Hurrengo zenbakia markaturik dago, adibidez 4 zenbakia, kasu honetan ez da ezer markatzen eta bere hurrengo zenbakia hartzen da
  • 5ekin markatu beharko litzateke (goiko lehen kasua), 6kin ez litzateke ezer markatuko (goiko bigarren kasua), 7ekin markatu beharko litzateke (goiko lehen kasua), 8, 9 eta 10ekin ez litzateke ezer markatuko (goiko bigarren kasuak), e.a.
    Prozedura errepikatzen da hau betetzen den bitartean: (MarkatuGabekoZenbakia)2 < n. Beste modu batez esanik, markatu gabeko zenbakiaren karratua n baino handiagoa denean eten prozesu errepikakorra

Eratostenes-en bahearen animazioa 120 baino gutxiagoko zenbaki lehenentzat:

Sieve of Eratosthenes animation
SKopp at German Wikipedia, CC BY-SA 3.0, via Wikimedia Commons

Hona hemen datu-taularen irudia MAX konstanteak 21 balio duenean, non 0 markak zenbaki lehen adierazten duen eta 1 markak zenbaki zatigarri adierazten duen:

  1    2   3    4   5    6   7    8    9   10 11  12 13  14  15  16 17  18 19  20  21   zenbakia  
  2    0  0  1  0  1  0  1  1  1  0  1  0  1  1  1  0  1  0  1  1 marka

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21


/* Ariketa-63_EratostenesenBahea-1 */

/*
   Muga den kopuru arrunta emanez, muga hori baino txikiagoak diren
   "Zenbaki Lehenak" lortzeko metodo bat aurkitu zuen Eratostenesek.

   Algoritmoa:
   ----------
   2tik iMuga-rako zenbakiak zerrenda batean jartzen dira. Lehenengo, 2ren
   multiplo guztiak markatzen dira, eta 2 zenbakia emaitza den lehenen
   zerrendari gehituko zaio. Ondoren, 3ren multiplo guztiak markatuko dira,
   eta 3 zenbakia gehituko zaio lehenen zerrendari. Gero, 4ari begiratzen
   zaio, markatuta dagoela ikusten da, eta horrek esan nahi du 2rekin
   zatigarria dela, eta, beraz, ez da lehena. Ondoren, 5era iristen da;
   markatuta ez dagoenez, lehena da, bere multiplo guztiak markatzen dira
   eta lehenen zerrendara gehituko da.
   Prozesu errepikakorra bukatzeko baldintza: Une jakin batean aztertuko den
   zenbakiaren karratua iMuga-tik beherakoa bada, jarraitu beharra dago.
   Bestela, algoritmoa amaitu egiten da, eta markatu gabe geratu diren
   guztiak zenbaki lehenak dira (emaitza-zerrendari gehitu beharrekoak).

   Animazio hau ikusi:
   https://upload.wikimedia.org/wikipedia/commons/b/b9/Sieve_of_Eratosthenes_animation.gif

   Bi programa hauek aztertu:
      * Ariketa-63_EratostenesenBahea-1 zenbaki osoen bi dimentsiotako arraya
      * Ariketa-69_EratostenesenBahea_2 erregistroen dimentsio bakarreko arraya
*/

#include <stdio.h>

#define MAX 120

typedef int taiDatuak[2][MAX + 1];   // 2 errenkada eta MAX+1 zutabe
typedef int taiLehenak[MAX];         // zenbaki lehenak gordetzeko arraya

void DatuakLortu(taiDatuak aiDatuak, int *iLuzeraDatuak);
void DatuakIkusi(const taiDatuak aiDatuak, int iLuzeraDatuak);
void LehenakLortu(const taiDatuak aiDatuak, int iLuzeraDatuak, taiLehenak aiLehenak, int *iLuzeraLehenak);
void LehenakIkusi(const taiLehenak aiLehenak, int iLuzeraLehenak);


int main()
{
    taiDatuak aiDatuak;
    int iLuzeraDatuak;
    taiLehenak aiLehenak;
    int iLuzeraLehenak;
    int iIterazioa = 2;

    DatuakLortu(aiDatuak, &iLuzeraDatuak);
    printf("\nHasierako datuak:\n");
    DatuakIkusi(aiDatuak, iLuzeraDatuak);
    printf("\n1 zenbakia alde batera utzirik, prozesu errepikakorra 2 zenbakiarekin hasiko da\n\n");

    do
    {
        printf("================================================================================\n");
        if (aiDatuak[1][iIterazioa] == 0)
        {
            printf("%d zenbakia lehena da, ", iIterazioa);
            printf("%d zenbakiaren multiploak markatzen...\n", iIterazioa);
            for (int k = iIterazioa + 1; k <= MAX; k++)
            {
                if (aiDatuak[0][k] % iIterazioa == 0)
                {
                    aiDatuak[1][k] = 1;  // Es divisible, marca con 1
                    printf("%4d zenbakia markaturik zatigarria delako\n", aiDatuak[0][k]);
                }
            }
        }
        else
        {
            printf("%d zenbakia zatigarria da\n", iIterazioa);
        }

        printf("%d arteko datuak:\n", iIterazioa);
        DatuakIkusi(aiDatuak, iLuzeraDatuak);
        printf("================================================================================\n");

        iIterazioa++;
        if (iIterazioa * iIterazioa <= MAX)
        {
            printf(" %d x %d = %d <= %d   prozesu errepikakorrarekin jarraitu\n",
                   iIterazioa, iIterazioa, iIterazioa * iIterazioa, MAX);
        }
        else
        {
            printf(" %d x %d = %d > %d   prozesu errepikakorra amaitu\n",
                   iIterazioa, iIterazioa, iIterazioa * iIterazioa, MAX);
        }
        printf("\n\n");
    } while (iIterazioa * iIterazioa <= MAX);

    LehenakLortu(aiDatuak, iLuzeraDatuak, aiLehenak, &iLuzeraLehenak);
    printf("Lehenen zerrenda:\n");
    LehenakIkusi(aiLehenak, iLuzeraLehenak);

    printf("\n\nENTER sakatu exekuzioa amaitzeko... ");
    getchar(); // itxaron ENTER sakatu arte
    return 0;
}


void DatuakLortu(taiDatuak aiDatuak, int *iLuzeraDatuak)
{
    *iLuzeraDatuak = MAX;
    for (int k = 2; k <= *iLuzeraDatuak; k++)
    {
        aiDatuak[0][k] = k;
        aiDatuak[1][k] = 0;  // 0 (FALSE) lehena, 1 (TRUE) zatigarria
    }
}

void DatuakIkusi(const taiDatuak aiDatuak, int iLuzeraDatuak)
{
    int iKont_0 = 1;  // 1 lehena da, ez da prozesatzen
    int iKont_1 = 0;  // zatigarrien kontagailua

    printf("--------------------------------------------------------------------------------\n");
    printf("   1-LEHEN");
    for (int k = 2; k <= iLuzeraDatuak; k++)
    {
        printf("%4d", aiDatuak[0][k]);
        if (aiDatuak[1][k] == 0)
        {
            printf("-LEHEN");
            iKont_0++;
        } else
        {
            printf("__ZAT.");
            iKont_1++;
        }
    }
    printf("\n--------------------------------------------------------------------------------\n");
    printf(" Zenbakien kopurua = %d     Lehenen kopurua = %d     Zatigarrien kopurua = %d\n",
           iLuzeraDatuak, iKont_0, iKont_1);
}


void LehenakLortu(const taiDatuak aiDatuak, int iLuzeraDatuak, taiLehenak aiLehenak, int *iLuzeraLehenak)
{
    *iLuzeraLehenak = 1;
    aiLehenak[*iLuzeraLehenak] = 1;

    for (int k = 2; k <= iLuzeraDatuak; k++)
    {
        if (aiDatuak[1][k] == 0)
        {
            (*iLuzeraLehenak)++;
            aiLehenak[*iLuzeraLehenak] = aiDatuak[0][k];
        }
    }
}


void LehenakIkusi(const taiLehenak aiLehenak, int iLuzeraLehenak)
{
    printf("********************************************************************************\n");
    for (int k = 1; k <= iLuzeraLehenak; k++)
    {
        printf("%3d, ", aiLehenak[k]);
    }
    printf("\n********************************************************************************\n");
    printf("  iLuzeraLehenak = %d\n", iLuzeraLehenak);
}






  • Ariketa-63_EratostenesenBahea-1.cbp | main.c