7. labor: Tömbök és függvények; sztringek

Ezen az órán a gyakorlathoz hasonló feladatokkal foglalkozunk. Az összes feladat tömbökkel dolgozik; ezek között azonban vannak sztringek, azaz karaktertömbök is.

Ha egy függvénynek átadunk egy tömböt, akkor csak a kezdőcíme adódik át. Emiatt általában a tömb méretét is át kell adnunk a függvénynek. A sztringeknél ezzel szemben nincs így; mivel a sztringeknél a tömb tartalma alapján kiderül, hol van a vége (a lezáró nullánál), ezért a méretet legtöbbször felesleges átadni paraméterként. A tömb mérete és a benne lévő sztring hossza amúgy sem egyezik meg.

A fentieket gondold végig minden feladat megoldásánál!

1 Kocka – cím szerinti paraméterátadás

Írj függvényt, amely paraméterként kapja egy kocka oldalhosszúságát (valós érték), és cím szerint átvett paraméterben visszaadja a kocka felületét és térfogatát!

A cím szerint átvett paraméter esetén a függvény módosítani is tudja a neki átadott változó értékét. Gyakran ezt úgy hívjuk, hogy „paramétersoron adja vissza az eredményt.”

Megoldás

#include <stdio.h>

void kocka(float oldal, float* pfelszin, float *pterfogat)
{
    *pfelszin=oldal*oldal*6;
    *pterfogat=oldal*oldal*oldal;
}

int main()
{
    float a, v;
    kocka(2, &a, &v);
    printf("V=%f A=%f\n", v, a);

    return 0;
}

2 Legnagyobb

Készíts függvényt, amely paraméterként vesz át egy egész számokból álló tömböt, és visszaadja a tömb legnagyobb elemének indexét! Egészítsd ki teljes programmá, amely kiírja a legnagyobb tömbelemet! (A kiírást ne a maximumkereső függvény végezze!)

Alakítsd át a programot úgy, hogy ne a legnagyobb elem indexét, hanem annak memóriacímét adja vissza a függvény!

Megoldás

#include <stdio.h>

int max(int t[], int elemszam)
{
    int i, maxidx=0;   /* Feltételezzük, hogy van legalább egy eleme */
    for (i=1; i<elemszam; i++)
        if (t[i]>t[maxidx])
            maxidx=i;  /* Ha találunk nagyobbat, megjegyezzük az indexét */
    return maxidx;     /* Visszaadjuk a maximumot */
}

int* maxcim(int t[], int elemszam)
{
    int i, maxidx=0;   /* Feltételezzük, hogy van legalább egy eleme */
    for (i=1; i<elemszam; i++)
        if (t[i]>t[maxidx])
            maxidx=i;  /* Ha találunk nagyobbat, megjegyezzük az indexét */
    return &t[maxidx]; /* Visszaadjuk a címét. return t+maxidx is jó. */
}

int main()
{
    int tomb[5]={1,5,3,9,8};
    printf("%d\n",tomb[max(tomb,5)]);
    printf("%d\n",*maxcim(tomb,5));

    return 0;
}

Alakítsd át úgy is a programot, hogy a ciklusok tömbindexek helyett pointerekkel dolgozzanak, ahogy az előadáson bemutatott módon.

Megoldás

int max(int t[], int elemszam)
{
    int *p, *max=t;
    for (p=t+1; p!=t+elemszam; ++p)
        if (*p>*max)
            max=p;
    return *max;
}

3 Névcsere

Készíts függvényt, amely paraméterként kap két sztringet: az egyikben átvesz egy nevet (pl. „Gipsz Jakab”), a másikba teszi az eredményt. Az eredmény legyen a név olyan formában, hogy a vezetéknév és a keresztnév felcserélve szerepel („Jakab Gipsz”). A feladatot a string.h-ban található sztringkezelő függvényekkel oldd meg! Írj main() függvényt is, amelyben teszteled a függvény helyes működését!

Tipp: a string.h függvényeinek a fordító helpjében vagy a nagy ZH-n és a vizsgán kinyomtatva használható, Szandi tanár úr által összeállított kétoldalas C összefoglalóban tudsz utánanézni.

Egy függvény segítségével meg tudod találni a sztringben lévő első szóközt (strchr, de az strstr is használható). A függvény a szóköz memóriacímét adja vissza. (Ha ebből levonod a bemenő sztring első karakterének címét, megkapod, hogy a szóköz hanyadik karakter.) A szóköz címe+1-et, valamint a céltömb címét átadva a sztringmásoló függvénynek (strcpy), a céltömbbe belekerül a név második fele. Ehhez hozzá kell fűzni egy szóközt, valamint a szóköz előtti nevet.

Megoldás

#include <stdio.h>
#include <string.h>

 /* Név cseréje */
void csere(char *eredeti, char *uj)
{
    /* Ez lesz a szóköz címe a memóriában (nem az hogy hányadik helyen van) */
    char* szokoz = strchr(eredeti, ' ');
    /* Az új sztringbe másoljuk a szóköz utáni részt */
    strcpy(uj, szokoz+1);
    /* Hozzáfűzünk az újhoz egy szóközt */
    strcat(uj, " ");
    /* Majd hozzáfűzzük a szóköz előtti részt. A hosszúságot úgy kapjuk meg, */
    /* hogy a szóköz címéből kivonjuk az eredeti sztring címét */
    strncat(uj, eredeti, szokoz-eredeti);
}

int main()
{
    char s1[]="Gipsz Jakab";
    char s2[20];  /* Legyen a mérete 20, hogy biztos elférjen */
    csere(s1, s2);
    printf("%s\n%s\n", s1, s2);

    return 0;
}

4 strstr()

Írj függvényt, amely két sztringet vesz át paraméterként, és az elsőben megkeresi a második első előfordulását! Ha megtalálja, adja vissza a megtalált szöveg első karakterének címét, ha nincs benne, akkor NULL pointert! A megoldáshoz nem használhatsz könyvtári függvényt. (A feladat a string.h-ban található strstr függvény saját megvalósítása.) Egészítsd ki teljes programmá, a program az "Indul a kutya s a tyúk aludni." mondatban keresse meg a "kutya" szót! (A függvény a kis és nagybetűket tekintse különbözőnek!)

Megoldás

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

char* mystrstr(char* hol, char* mit)
{
    int i, j, talalt;
    for (i=0; hol[i]!='\0'; i++) {
        talalt=1;
        for (j=0; hol[i+j] && mit[j] && talalt; j++)
            if (hol[i+j]!=mit[j])
                talalt=0;
        if (talalt && mit[j]=='\0')
            return &hol[i];
    }
    return NULL;
}

int main()
{
    char* s1="Indul a kutya s a tyúk aludni.";
    char* s2="Indul a kuty";

    char* pos1 = mystrstr(s1, "kutya");
    char* pos2 = mystrstr(s2, "kutya");

    if (pos1!=NULL)
        printf("%d\n", (int) (pos1-s1));
    else
        printf("NULL\n");

    if (pos2!=NULL)
        printf("%d\n", (int) (pos2-s2));
    else
        printf("NULL\n");

    return 0;
}

5 Trimmer

Írj függvényt, amelyik egy paraméterként kapott sztring elejéről és végéről eltávolítja a szóköz karaktereket (a többi maradjon)! Pl. ha a bemenet "  helló, mizu?   ", akkor a megváltoztatott sztring "helló, mizu?" legyen. Írj programrészt, amelyben bemutatod a függvény használatát!

Megoldás

#include <stdio.h>

void trimmer(char *s)
{
    int eleje=0, vege=0;
    int i;

    /* elején a szóközök? */
    while (s[eleje]!='\0' && s[eleje]==' ')
        eleje++;
    /* hol a vége? utána visszafelé a szóközökön */
    while (s[vege]!='\0')
        vege++;
    vege--;
    while (vege>=0 && s[vege]==' ')
        vege--;
    /* másolás az elejére, és lezárás */
    for (i=0; i<=vege-eleje; i++)
        s[i] = s[eleje+i];
    s[i]='\0';
}

int main()
{
    char s[] = "      Hello mizu?   ";
    printf("[%s]\n",s);
    trimmer(s);
    printf("[%s]\n",s);

    return 0;
}

6 További feladatok

Minden második

Írj függvényt, ami egy tömböt átvesz paraméterként, és hátulról indulva kiírja minden második elemét! Ügyelj arra, hogy nehogy túl/alulindexeld a tömböt!

Súlypont

Készíts struktúratípust, amely alkalmas egy térbeli pont koordinátáinak eltárolására (x, y, z koordinálta). Írj függvényt, amely átvesz egy térbeli pontokból álló tömböt, és visszaadja a pontok súlypontját (azaz azt a pontot, amelynek a koordiátáit a bemenő bontok megfelelő koordinátáinak átlagai)! Próbáld ki a függvényt teljes programmá kiegészítve!

Egyszeres többszörös

Írj függvényt, amely paraméterként egész számok tömbjét kapja, és kiírja azokat az elemeket, amelyek többször szerepelnek benne. (De mindegyik ilyet csak egyszer.) A tömböt szabad módosítani.

Fontos: a függvénynek átadott tömböt csak akkor szabad megváltoztatni, ha a feladat szövegéből ez következik, egyébként tilos! Ne feledd, hogy C-ben a tömb függvénynek történő átadásakor csak a tömb címe adódik át, tehát a tömb megváltoztatása az eredeti tömböt változtatja meg.

Palindrom

Írj programot, amelyik egy sztringről eldönti, hogy palindrom-e: azaz oda-vissza olvasva ugyanaz-e, mint önmaga. Közismert magyar nyelvű palindrom mondat a „Géza, kék az ég.” Hogyan lehet a gyakorlat „mindentegybevéve” és „fordítva” feladatainak ötleteiből összerakni ezt a programot? Hogyan egyszerű megírni, ha módosíthatjuk a sztringet, és hogyan akkor, ha nem?

A tesztelésnél figyelj arra, hogy egyes karakterkódolások esetén az ékezetes betűkhöz több bájt is tartozhat. Ezek megfordítva nem ugyanazt a betűt jelentik. Ezért a programot inkább ékezetes betűk nélkül teszteld!

Rajzolóprogram

A múlt heti „bitek titkai” és „bitbabrálás” feladatok alapján készíts egyszerű rajzolóprogramot! Hozz létre egy nagyobb tömböt, amely 32 pont széles rajzot fog tudni tárolni. (A konzol ablak 25 soros, ezért érdemes 24 sorosra választani a tömböt.) Rajzolj ebbe különböző formákat, pl. téglalapot, vonalat, sakktáblát stb! Rajzolj bele egy szinusz függvényt, amely nincs elforgatva 90°-kal, mint a régebbi laboron! Használj a programban egy függvényt, amelynek paraméterként lehet adni egy képet, és (x, y) koordinátapárt, ahol kigyújt, kiolt, vagy invertál egy pontot!