6. hét: pointerek, sztringek

Czirkos Zoltán, Nagy Gergely, Pohl László · 2016.08.28.

Gyakorlófeladatok a 6. előadás anyagához kapcsolódóan.

1. Tömbök és függvények

Tömb eleme

Vizsgán volt

Írj függvényt, amely átvesz egy double tömböt, és visszatér a 4-es indexű elemével, ha az létezik, különben 0-val!

Megoldás

A C-ben, ha egy tömböt átadunk paraméterként, akkor csak az első elemének (nullás indexű elemének) a címe adódik át a függvénynek. Ebből az is következik, hogy a függvény nem tudja, mekkora az a tömb, vagyis azt is át kell adni, külön paraméterként. A függvény paramétereinek típusa ezért double*, a tömb elejére mutató pointer, és még egy int, amelyik pedig a tömb mérete. Hogy létezik-e a tömb 4-es indexű eleme, azt pedig ebből a méret változóból tudjuk.

double fv(double *t, int meret) {
    if (meret > 4)
        return t[4];
    else
        return 0;
}

Tömb összege

Készíts függvényt, mely egy valós számokból álló tömb elemeit összegzi!

Tömb három legkisebb eleme

Készíts függvényt, amely egy tömb 3 legkisebb elemét határozza meg!

Alig változik

Készíts függvényt, mely a paraméterben kapott egész tömbről megvizsgálja, hogy elemeinek értéke szomszédos elemek E sugaron belül helyezkednek el (különbségük nem nagyobb, mint E vagy -E) A függvény bemenő paramétere a tömbre mutató pointer, a tömb elemeinek száma, valamint az E értéke. Visszatérési értéke logikai típusú legyen, amely azt mutatja, teljesült-e a feltétel!

Legalább kettő

Kis ZH volt

Írj függvényt, amely paraméterként vesz át egy egészekből álló tömböt, és visszaadja az első olyan tömbelem címét, amelyből legalább kettő található a tömbben! Ha nincs ilyen tömbelem, adjon vissza NULL pointert!

Megoldás

int *dupla(int *tomb, int n) {
    int i, j;
    for (i = 0; i < n - 1; i++)
        for (j = i + 1; j < n; j++)
            if (tomb[i] == tomb[j])
                return tomb + i;
    return NULL;
}

Rendezett-e

Kis ZH volt

Írj függvényt, amely paraméterként vesz át egy valós értékekből álló tömböt, melyről biztosan tudjuk, hogy elemei különbözőek! A függvény ellenőrizze, hogy a tömb rendezett-e (akár növekvő, akár csökkenő sorrendben; a feltételezett rendezettség iránya az első két tömbelem vizsgálatával eldönthető). Ha a tömb nem rendezett, a függvény adja vissza az első olyan tömbelem címét, amelyik elrontja a rendezettséget! Ha a tömb rendezett, adjon vissza NULL pointert! Pl. be: {-8.11, -5.3, 0.1, 2.5, 1.4, 6.9, 12.0, 5.7}, a visszaadott érték az 1.4-et tartalmazó tömbelem címe. Pl. be: {7, 1, 2, 3, 4, 5}, a visszaadott érték a 2-t tartalmazó tömbelem címe.

Megoldás

double *rendezette(double *tomb, int n) {
    int i;
    if (n < 2) return NULL;
    bool novekvo = tomb[0] < tomb[1];
    for (i = 2; i < n; i++) {
        if (novekvo && tomb[i - 1] > tomb[i])
            return tomb + i;
        else if (!novekvo && tomb[i - 1] < tomb[i])
            return tomb + i;
    }
    return NULL;
}

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(void) {
    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, az előadáson bemutatott módon.

Megoldás

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

Legkisebb és legnagyobb

Kis ZH volt

Írj függvényt, amely paraméterként vesz át egy egészekből álló tömböt! A függvény adja vissza címével átvett változókban a tömb legkisebb és legnagyobb elemének indexét! Ha több egyforma érték a legkisebb/legnagyobb, akkor ezek közül bármelyik indexét visszaadhatja.

Megoldás

void minmax(int *tomb, int n, int *pmin, int *pmax) {
    int min = 0, max = 0;
    int i;
    for (i = 1; i < n; i++) {
        if (tomb[i] < tomb[min] ) min = i;
        if (tomb[i] > tomb[max] ) max = i;
    }
    *pmin = min;
    *pmax = max;
}

24×21-es képecskék

Egy játékhoz, amit írunk, szükség vagy 24×21 fekete/fehér pontból álló kis képecskékre. Mivel ezekből rengeteg lesz, kitaláljuk, hogy a fekete/fehér jelleg miatt egy bit is tárolhat egy pontot, így az egy kép által lefoglalt memória (innentől feltételezve a 8 bites char-t) 3×21=63 bájtot foglal csak el a memóriából. Feladat: írni három függvényt, amelyek a következőeket tudják:

  • Kirajzolni pontokból és csillagokból egy ilyen képecskét.
  • Fehérre állítani egy pontot.
  • Feketére állítani egy pontot.

Megoldás

#include <stdio.h>

typedef unsigned char kep[63];

// Az elso feladatresz megoldasa: egy kepecske kirajzolasa
void kirajzol(kep k) {
    int x, y;

    for (y = 0; y < 21; y++) {
        for (x = 0; x < 24; x++) {
            /* annyival shift, utana legalso bit */
            /* (szóköz helyett .-ot használtam most) */
            printf("%c", (k[y * 3 + x / 8] >> (7 - x % 8)) & 1 ? '*' : '.');
        }
        printf("\n");
    }
    printf("---\n");
}

// A masodik feladatresz: adott pontot feherre allit
void feher(kep k, int x, int y) {
    /* keppont aktiv: bitenkenti VAGY */
    k[y * 3 + x / 8] = k[y * 3 + x / 8] | (1 << (7 - x % 8));
}

// A harmadik feladatresz: adott pontot feketere allit
void fekete(kep k, int x, int y) {
    /* keppont ki: bitenkenti ES a negalttal */
    k[y * 3 + x / 8] = k[y * 3 + x / 8] & ~(1 << (7 - x % 8));
}

int main(void) {
    int x, y;
    kep k;

    for (y = 0; y < 21; y++)
        for (x = 0; x < 24; x++)
            fekete(k, x, y);
    kirajzol(k);
    for (x = 0; x < 24; x++)
        feher(k, x, 10);
    kirajzol(k);
    for (y = 0; y < 21; y++)
        feher(k, 5, y);
    kirajzol(k);

    return 0;
}

Megoldható kétdimenziós tömbbel is, kep[3][21]. Az egy bájton belüli képpond sorrend is tetszőleges; vagy mindenhol 7-x%8, vagy mindenhol simán x%8.

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!

Hány egyedi elem van?

Készíts függvényt, mely egy adott tömbben megszámolja, hogy hány olyan elem van, amely csak egyszer fordul elő! Pl. a { 2, 7, 5, 8, 9, 5, 7, 5, 5, 3 } tömbre a visszatérési érték legyen 4, mert a { 2, 3, 8, 9 } számok mind csak egyszer szerepeltek!

A leggyakoribb elem

Készíts függvényt, mely meghatározza egy adott (véletlen számokkal feltöltött) tömbben, hogy melyik értékből található benne a legtöbb! Pl. ha a tömb elemei { 2, 7, 5, 8, 9, 5, 7, 5, 5, 3 }, akkor a függvényt visszatérési értéke legyen 5, mivel az a leggyakoribb elem.

Rendezettség vizsgálata

Kis ZH volt

Írj egy függvényt, amelyik egy double számokból álló tömböt vesz át paraméterként. A függvény térjen vissza egy felsorolt típussal, amelynek lehetséges értékei: csokkeno , ha a tömbben lévő számsorozat szigorúan monoton csökken; novekvo, ha szigorúan monoton nő; osszevissza, ha egyik sem igaz rá. Írj egy programrészt, amelyik definiál egy tömböt, és kiírja, hogy „növekvő”, ha a tömbben lévő számok szigmon növekvő sorban vannak. Pl. [3 2.1 0.9] → csokkeno, [3 4 2 9 5] → osszevissza, [3 4.65 9 11] → novekvo.

Megoldás

#include <stdio.h>
#include <stdbool.h>

/* nem lenne muszaj typedefelni amugy */
typedef enum { osszevissza, novekvo, csokkeno } SzigMon;

/* a feladat nem definialja azt, mi a helyzet a 0 es 1 elemu
   tombokre (amik szigmon novekvoek es csokkenoek is :D) */

SzigMon vizsgal(double *t, int meret) {
    int i;
    bool nov = true, csokk = true; /* egyelore barmelyik lehet */

    /* vigyazni a tulindexelesre! i+1, szoval itt i<meret-1*/
    for (i = 0; i < meret - 1; i++)
        /* ha nem igaz, hogy kisebb a kovetkezonel */
        if (!(t[i] < t[i + 1]))
            /* akkor ez novekvo nem lehet */
            nov = false;

    /* ugyanaz a logika */
    for (i = 0; i < meret - 1; i++)
        if (!(t[i] > t[i + 1]))
            csokk = false;

    /* hacsak nem 0 vagy 1 elemu a tomb, akkor ez megfelel */
    if (csokk) return csokkeno;
    if (nov) return novekvo;
    return osszevissza;
}

int main(void) {
    double t1[5] = {5, 9, 1, 3, 45};
    double t2[5] = {1, 2, 3, 4, 5};
    double t3[5] = {9, 8, 7, 6, 5};

    if (vizsgal(t1, 5) == osszevissza) printf("t1 osszevissza\n");
    if (vizsgal(t2, 5) == novekvo) printf("t2 novekvo\n");
    if (vizsgal(t3, 5) == csokkeno) printf("t3 csokkeno\n");

    return 0;
}

Minden szám megfordítása

Kis ZH volt

Írj C programot, amelyik definiál egy 1000 elemű, bájtokból álló tömböt. A program fordítsa meg az egyes bájtokban a biteket; a 7. helyiértékű cseréljen helyet a 0. helyiértékűvel, a 6. helyiértékű az 1-essel stb. (Feltételezzük, hogy a bájtok 8 bitesek. A tömb számokkal feltöltésével nem kell foglalkozni.) A program végezetül írja ki binárisan a tömb 0. elemét. A megfordításra példa:

76543210
10110010    bemenet
01001101    kimenet

Megoldás

#include <stdio.h>

int main(void) {
    unsigned char t[1000];
    int i;

    /* egyet most itt inicializalok, hogy lassam az eredmenyt,
     * de a feladat nem keri */
    t[0] = 0xd7;

    /* kiiras, csak hogy a csere elott is lassuk */
    for (i = 7; i >= 0; i--)
        putchar((t[0] >> i) & 1 ? '1' : '0');
    printf("\n");

    /* ez a MEGOLDAS LENYEGE */
    for (i = 0; i < 1000; i++) {
        int j;
        unsigned char uj = 0;

        /* amit a regi szambol kishiftelunk jobbRA,
         * azt az ujba beshifteljuk jobbROL */
        for (j = 0; j < 8; j++) {
            int x = t[i] & 1;   /* ez kiveszi az also bitet */
            t[i] >>= 1;         /* a regit shifteli */
            uj = uj << 1 | x;       /* ez az ujat balra shifteli,
                                         es az ujat berakja */
        }
        t[i] = uj;
    }

    /* ez csak copypaste, a feladat egyszer keri */
    for (i = 7; i >= 0; i--)
        putchar((t[0] >> i) & 1 ? '1' : '0');
    printf("\n");

    return 0;
}

Bitek léptetése

Kis ZH volt

Írj egy C programot, amelyik 100 elemű, bájtokból álló tömböt léptet egy bittel jobbra! A számokból jobbra kicsúszó bit jöjjön be mindig a következő számba balról. Az utolsó szám legalsó helyiértékéből kicsúszó bit pedig kerüljön az első szám legfelső helyiértékébe. (Feltételezzük, hogy a bájtok 8 bitesek. A tömb számokkal feltöltésével nem kell foglalkozni.) Például:

76543210 76543210 ... 76543210 76543210
01001010 11111101     01011110 00001101    bemenet
10100101 01111110 ... 10101111 00000110    kimenet

Megoldás

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

int main(void) {
    unsigned char t[100];
    int i, atvitel;

    /* ezt nem kerte a feladat, csak hogy ne legyen inicializalatlan */
    for (i = 0; i < 100; ++i)
        t[i] = rand() % 256;

    /* ezt se kerte, csak hogy latszodjon az eredmeny */
    for (i = 7; i >= 0; i--)
        putchar((t[0] >> i) & 1 ? '1' : '0');
    printf(" ... ");
    for (i = 7; i >= 0; i--)
        putchar((t[99] >> i) & 1 ? '1' : '0');
    printf("\n");

    /* MEGOLDASA a feladatnak: tulajdonkepp ez a ciklus. */
    /* utolso szam utolso bitje,
     * mert ez csuszik be az elso szamba; mar most kivesszuk,
     * hogy lent, amikor az atvitelt "becsusztatjuk" az
     * if (atvitel) resznel, ott mar a megfelelo erteket
     * tartalmazza */
    atvitel = t[99] & 1;
    for (i = 0; i < 100; i++) {
        int uj_atvitel = t[i] & 1; /* a kovetkezo szamhoz - ez a kicsuszo bit */
        t[i] >>= 1;                /* ezzel csuszik az egesz */
        if (atvitel == 1)          /* ha volt "atvitel", akkor azt berakjuk a legfelsobe */
            t[i] |= 1 << 7;
        atvitel = uj_atvitel;
    }

    /* kiirom az eredmenyt; a feladat nem kerte */
    for (i = 7; i >= 0; i--)
        putchar((t[0] >> i) & 1 ? '1' : '0');
    printf(" ... ");
    for (i = 7; i >= 0; i--)
        putchar((t[99] >> i) & 1 ? '1' : '0');
    printf("\n");

    return 0;
}

Párosak vagy negatívak?

Kis ZH volt

Írj egy függvényt, amelyik egy egész számokból álló tömböt vesz át paraméterként. A függvény térjen vissza az alábbi felsorolt típusból valamelyik értékkel: parosak, negativak, mindketto, egyiksem, ha a tömbben páros az összes szám, negatív az összes, illetve ha mindkét tulajdonság, vagy egyik tulajdonság sem érvényes rájuk. Írj programot, amelyik egy példaként definiált 100 elemű tömbre meghívja a függvényt, és kiírja, hogy „párosak”, ha érvényes rá ez a tulajdonság.

  • [3 4 5] → egyiksem
  • [-2 -4 -6] → mindketto
  • [4 6 10] → parosak

Megoldás

#include <stdio.h>
#include <stdbool.h>

typedef enum { parosak, negativak, mindketto, egyiksem } Tulajdonsagok;

Tulajdonsagok vizsgal(int *t, int meret) {
    int i;
    bool prsk, ngtvk;

    /* a megoldas gondolata, pl. parosakra:
     * 1) tetelezzuk fel, hogy az osszes szam paros.
     * 2) nezzuk vegig a tombot
     *    2a) ha talalunk egy nem paros szamot...
     *    2b) ... akkor nem igaz az, hogy mind parosak. */

    /* 1 */
    prsk = true;
    ngtvk = true;
    /* 2 */
    for (i = 0; i < meret; ++i) {
        if (t[i] % 2 != 0)      /* <- 2a */
            prsk = false;       /* <- 2b */
        if (t[i] >= 0)
            ngtvk = false;
    }

    if (prsk && ngtvk)
        return mindketto;
    if (prsk)           /* ... de nem ngtvk */
        return parosak;
    if (ngtvk)          /* ... de nem prsk */
        return negativak;
    return egyiksem;    /* mar csak ez lehet. */
}

int main(void) {
    int t[5] = {4, 6, 8, 10, 12};

    if (vizsgal(t, 5) == parosak)
        printf("parosak");

    return 0;
}

2. Sztringek

Sztringek, mint karaktertömbök

Hozzunk létre egy sztringet! Változtassunk meg benne néhány karaktert! Írjunk ciklust, amelyik megszámolja az 'l' betűket a sztringben!

Megoldás

#include <stdio.h>

int main(void) {
    char sz[20] = "Hello, vilag!";
    int i, db;

    printf("|%s|\n", sz);
    sz[0] = 'h';              /* sztring: "idezojel", karakter: 'h' aposztrof! */
    printf("|%s|\n", sz);
    sz[7] = '\0';             /* 0 is lehetne, ugyanaz. */
    printf("|%s|\n", sz);

    /* tekintsünk a sztringre, mint tömbre. hol van vége?
       ahol sz[i]==0, nem pedig i=19-nél, ami a tömb méretéből adódna! */
    db = 0;
    for (i = 0; sz[i] != '\0'; ++i)
        if (sz[i] == 'l')
            db += 1;
    printf("[%s] sztring %d darab l betűt tartalmaz.\n", sz, db);

    return 0;
}

Üdvözlés

Készíts programot, amely bekéri a felhasználó nevét, majd üdvözli őt a nevén szólítva!

Hány szóköz?

Készíts programot, mely bekér egy mondatot, majd
a.) megszámolja és kiírja, hogy a mondatban hány szóköz található.
b.) kiírja a mondatot szóközök nélkül.

Kisbetűk I.

Készíts függvényt (numLower), ami megkap egy stringre mutató pointert, és visszaadja az adott szövegben található kisbetűk számát. (Ehhez használható a ctype.h islower() függvénye is.)

Kisbetűk II.

Írj C függvényt, amely egy nullával terminált sztringben kicseréli az angol abécé nagybetűit a nekik megfelelő kisbetűkre. Ha a bemeneti sztring "Hello Vilag", módosítsa azt "hello vilag"-ra. (Tipp: A megoldáshoz a ctype.h könyvtári függvényei használhatóak.)

Nagybetűk

Készíts függvényt, mely a paraméterben átadott sztringet nagybetűssé alakítja!

Karakterek cseréje

Készíts függvényt, mely paraméterben egy sztringet és további két karaktert (mit és mire) kap. A függvény keresse meg a sztringben a "mit" változóban megadott karaktereket, és cserélje azokat a "mire" változóban megadottakra. A függvény visszatérési értéke a kicserélt karakterek számát jelentse.

Névelő

Készíts programot, mely adott sztringben megszámolja, hányszor fordul elő az „a” névelő. A névelő lehet mondat elején, de végén nem, viszont vessző állhat előtte is és utána is, egyébként szóköz karakterek határolják.

Decimális

Írj olyan int dec_to_int(char *s) függvényt, amelyik a megadott számjegyekből álló sztringet a neki megfelelő egész értékké alakít (tízes számrendszer szerint)! Pl. dec_to_int("256") visszatérési értéke 256. Oldd meg a feladatot a sscanf() segítségével és anélkül is!

Hexadecimális

Írj olyan int hexa_to_int(char *s) függvényt, amelyik a megadott hexadecimális számjegyekből álló sztringet a neki megfelelő egész értékké alakít! Pl. hexa_to_int("1ef") visszatérési értéke 495. Oldd meg a feladatot a sscanf() segítségével és anélkül is!

Része-e?

Írj egy függvényt, amely egy adott sztringben megkeresi egy másik sztring legutolsó előfordulását, és visszaadja annak pozícióját, illetve -1-et, ha nem található. A megoldáshoz ne használd a könyvtári strrstr() függvényt! Például "abcdabce"-ben keressük "abc"-t, a visszatérési érték 4, a színnel jelölt előfordulás miatt.

Megoldás

A következő módon bontható fel ezt részekre:

  • Kell egy függvény, amelyik megmondja, hogy egy adott sztring elején szerepel-e egy másik sztring. Ezt fogom lefuttatni a különböző részein az eredeti sztringeknek (visszafelé). Szemfülesek az strncmp-t használhatják erre.
  • Kell egy függvény, amelyik egy sztring hosszát megmondja (de jó a gyári strlen is), mivel
  • visszafelé futtatok egy ciklust, és nézem, hogy megtalálom-e valahol a szénakazal végén a tűt.
  • Ahol először megtalálom, azzal az indexszel vissza is térhetek; ha sehol nem találtam meg, akkor -1-gyel.
#include <stdio.h>
#include <stdbool.h>

bool igy_kezdodik(char *mi, char *hogyan) {
    int i;

    /* amig egyiknek sincs vege, es egyeznek a betuk, kov. karakter */
    i=0;
    while (hogyan[i]!='\0' && mi[i]!='\0' && hogyan[i]==mi[i])
        i++;
    /* ha a hogyan string vegere ertunk, akkor eddig tuti megegyezett
       a mi-vel */
    return hogyan[i]=='\0';
}

int hossz(char *str) {
    int i = 0;
    while (str[i]!='\0') i++;
    return i;
}

int utolso_elofordulas(char *szenakazal, char *tu) {
    int h;

    h=hossz(szenakazal);
    h-=hossz(tu);   /* ennel csak elorebb lehet */
    while (h>=0 && !igy_kezdodik(szenakazal+h, tu))
        h--;
    /* ha ertelmes index van, akkor azzal terunk vissza */
    if (h>=0)
        return h;
    /* amugy -1 */
    return -1;
}

int main(void) {
    printf("%d\n", utolso_elofordulas("almafa, eperfa", "fa"));
    printf("%d\n", utolso_elofordulas("almafa, eperfa", "a"));
    printf("%d\n", utolso_elofordulas("almafa, eperfa", "kortefa"));

    return 0;
}

Az első függvénynek az is jó megoldás lenne, ha az összehasonlítandó karakterek számát paraméterként kapja; olyankor nem kellene figyelnie a lezáró nullákra.

Felülírás és csere

Írj függvényt, amely az első paraméterében kapott sztringben megkeresi a második paraméterében adott karakter előfordulásait, és felülírja azokat a harmadik paraméterében adott karakterrel! Pl. "alma", 'a', 'e' → "elme".

Írj függvényt, amely szintén egy sztringet és egy karakterpárost kap, de ez ne felülírja az első előfordulásait a másodikkal, hanem cserélje meg őket! Pl. 'a', 'e' jelentse azt, hogy 'a'-t 'e'-re kell cserélni, 'e'-t pedig 'a'-ra. Hogyan lehet ezt megoldani az előző függvény felhasználásával?

Squeeze

Írj olyan "squeeze" függvényt, amely az első paraméterben megadott sztringből az összes olyan karaktert törli, amelyik szerepel a második paraméterben megadott sztringben. Például "megadott sztring", "gt" paraméterekkel meghívva a függvényt az első paraméter így módosul: "meado szrin".

Pontosan egyszer

Írj programot, amely beolvas egy karakterláncot, és megállapítja, hogy vannak-e benne olyan karakterek, amelyek pontosan egyszer fordulnak elő. A program írja ki ezeket a karaktereket, ha pedig nincsenek a karakterláncban egyedi karakterek, akkor közölje a felhasználóval!

toupper()

Készíts függvényt (myToUpper) mely egy sztringben képes a latin abc betűit nagybetűssé alakítani! A bemenet legyen a sztringre mutató kezdőpointer, a végeredmény ugyanebbe a sztringbe kerüljön bele!

Legalább kettő – sztringre

Kis ZH volt

Írj függvényt, amely paraméterként vesz át egy sztringet, és visszaadja az első olyan karakter címét, amelyből legalább kettő található a sztringben! Ha nincs ilyen karakter, adjon vissza NULL pointert!

Megoldás

char *duplas(char *string) {
    int i, j;
    for (i=0; string[i]!='\0'; i++)
        for (j=i+1; string[j]!='\0'; j++)
            if (string[i] == string[j] )
                return string+i;
    return NULL;
}

strcat()

Írjunk függvényt, amelyik egyik sztring végére másol egy másikat, vagyis hozzáfűzi a paraméterként kapott első sztringhez a másodikat! (Ezt csinálja a könyvtári strcat() függvény is.)

Megoldás

#include <stdio.h>

void sztringhozzafuz(char *mihez, char *honnan) {
    int folytat, i;

    i = 0;
    while (mihez[i] != '\0')
        i++;      /* ezzel megkeressuk, az elobbinek hol van vege */
    folytat = i;  /* es oda masoljuk a masikat, folytatolagosan */

    i = 0;        /* nezzuk a masik sztringet az elejetol */
    while (honnan[i] != '\0') {
        mihez[folytat] = honnan[i];
        i++;
        folytat++;
    }
    mihez[folytat] = '\0';     /* lezaro nulla eddig nem - most megtesszuk. */
}

/* peldak, hogyan kell meghivni a fuggvenyeket */
int main(void) {
    /* mit a mizujs[]? azt, hogy a fordito kitalalja a tomb meretet. */
    /* a hello[] sztringhez hozzafuzunk, ezert az nagyobb kell legyen. */
    char hello[50] = "Hello, vilag!",
         mizujs[] = "Mizujs?";

    printf("Sztring: [%s] es [%s]\n", hello, mizujs);
    sztringhozzafuz(hello, " ");
    sztringhozzafuz(hello, mizujs);
    printf("Osszefuzve: [%s].\n", hello);

    return 0;
}

strlcat()

Kis ZH volt

Írj egy függvényt (paraméterei: cél, forrás, cél tömb mérete), amelyik egy cél sztring (1. paraméter) végére hozzáfűz egy forrás sztringet (2. paraméter); figyelembe véve azt, hogy a cél tömb maximális mérete adott (3. paraméter), amelybe már a lezáró nullának is bele kell férnie. Mindkét helyen eredendően is 0-val lezárt sztring van. Ha az összefűzött sztring nem fér el a cél helyen, akkor le kell vágnia a függvénynek – de nullával mindig legyen lezárva. Írj programrészt, amelyben bemutatod a függvény használatát. A string.h függvényei NEM használhatóak.

Megoldás

Az strlcat() függvény működése

Rendes helyeken ilyen gyárilag szokott lenni, strlcat vagy g_strlcat néven. Az egésznek az előnye, hogy a cél puffer méretét kell megadni a harmadik paraméterben, ami statikus tömb esetén egy sima sizeof. Nem kell levonni 1-et a lezáró 0 miatt, semmi ilyesmi, pontosan a méretet várja.

#include <stdio.h>

void strlcat(char *cel, char *forras, int meret) {
    int celmeret, forrasidx;

    celmeret=0;
    while (cel[celmeret]!=0)
        ++celmeret;

    forrasidx=0;
    while (forras[forrasidx]!=0 && celmeret+forrasidx<meret-1) {
        cel[celmeret+forrasidx]=forras[forrasidx];
        forrasidx++;
    }

    /* akarmiert is lett vege, lezaro 0. */
    cel[celmeret+forrasidx]=0;
}

int main(void) {
    char cel[6]="alma";
    char cel2[9]="alma";
    strlcat(cel, "le", sizeof(cel));
    strlcat(cel2, "le", sizeof(cel2));
    printf("[%s]\n", cel);
    printf("[%s]\n", cel2);

    return 0;
}

Összefűzés

Kis ZH volt

Írj függvényt, amely paraméterként vesz át egy cél sztringet, továbbá két másik sztringet és egy elválasztó karaktert! Másolja be a cél sztringbe a másik két sztringet úgy, hogy közéjük az elválasztó karaktert teszi.

Írj főprogramot, amelyben egy példával bemutatod a függvény használatát! A beépített sztringkezelő függvények nem használhatóak!

Példa paraméterek: „alma” és „körte”, továbbá „;”

Példa eredmény: „alma;körte”

Megoldás

#include <stdio.h>

void osszefuz(char *ide, char *egyik, char *masik, char koze) {
   int pos, i;

   pos=0;
   for (i=0; egyik[i]!='\0'; ++i)
      ide[pos++]=egyik[i];
   ide[pos++]=koze;

   for (i=0; masik[i]!='\0'; ++i)
      ide[pos++]=masik[i];
   ide[pos++]='\0';
}

int main(void) {
   char kesz[20];

   osszefuz(kesz, "alma", "korte", ';');
   printf("%s\n", kesz);

   return 0;
}

Szétválasztás

Kis ZH volt

Írj egy függvényt, amely paraméterként vesz át egy bemeneti sztringet és egy elválasztó karaktert! Legyen még két további paramétere, amelyekbe az eredményt írja. Vágja ketté a függvény a sztringet az első elválasztó karakternél: az eleje menjen az egyik eredmény sztringbe, másik pedig a másikba!

Írj főprogramot, amelyben egy példával bemutatod a függvény használatát! A beépített sztringkezelő függvények nem használhatóak.

Példa paraméterek: „alma;körte” és „;”

Példa eredmény: „alma” és „körte”

Megoldás

#include <stdio.h>

void szeletel(char *be, char elvalaszto, char *egyik, char *masik) {
   int x = 0;
   int pos = 0;
   while (be[x] != elvalaszto)
      egyik[pos++] = be[x++];
   egyik[pos] = '\0';

   x++;
   pos = 0;
   while (be[x] != '\0')
      masik[pos++] = be[x++];
   masik[pos] = 0;
}

int main(void) {
   char bal[20], jobb[20];

   szeletel("alma;korte", ';', bal, jobb);
   printf("[%s] es [%s]\n", bal, jobb);

   return 0;
}

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>
#include <stdbool.h>

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

int main(void) {
    char s1[] = "Indul a kutya s a tyúk aludni.";
    char* pos1 = mystrstr(s1, "kutya");
    if (pos1 != NULL)
        printf("Pozíció: %d\n", (int) (pos1-s1));
    else
        printf("NULL - nincs benne\n");

    char s2[] = "Indul a kuty";
    char* pos2 = mystrstr(s2, "kutya");
    if (pos2 != NULL)
        printf("Pozíció: %d\n", (int) (pos2-s2));
    else
        printf("NULL - nincs benne\n");

    return 0;
}

Karakterek törlése

Kis ZH volt

Írj függvényt, amely átvesz paraméterként egy módosítandó sztringet és még egy karaktert. Alakítsa át úgy a sztringet úgy, hogy a megadott karaktert törölje a sztring elejéről és a végéről is! Mindkét oldalon lehet több is, vagy akár semennyi. A belsejében viszont tudjuk, hogy nincsen.

Írj főprogramot, amelyben egy példával bemutatod a függvény használatát! A beépített sztringkezelő függvények nem használhatóak.

Példa bemenet: „xxxHello hallo elektor kalandorxxxx” és az „x” karakter

Példa kimenet: „Hello hallo elektor kalandor”

Megoldás

#include <stdio.h>

void sztring_trim(char *str, char mit) {
    int eleje, pos, i;

    eleje = 0;
    while (str[eleje] == mit)
        eleje++;
    pos = 0;
    for (i = eleje; str[i] != mit && str[i] != '\0'; i++)
        str[pos++] = str[i];
    str[pos] = '\0';
}

int main(void) {
    char szoveg[] = "xxxHello hallo elektor kalandorxxxx";

    sztring_trim(szoveg, 'x');
    printf("[%s]\n", szoveg);

    return 0;
}

Bevezető és lezáró karakterek

Kis ZH volt

Írj függvényt, amely paraméterként átvesz egy cél sztringet, továbbá egy forrás sztringet, egy karaktert és egy darabszámot! Másolja át a cél sztringbe a forrást úgy, hogy elé és mögé a megadott karakterből a megadott darabszámút tegye. Ezen kívül a szóközöket is cserélje ki a megadott karakterre.

Írj főprogramot, amelyben egy példával bemutatod a függvény használatát! A beépített sztringkezelő függvények nem használhatóak.

Példa bemenet: „Hello hallo elektor kalandor”, továbbá az „x” karakter és 3

Példa kimenet: „xxxHelloxhalloxelektorxkalandorxxx”

Megoldás

#include <stdio.h>

void strelemoge(char *ide, char *mit, char kar, int db) {
    int pos, x;

    pos = 0;
    for (x = 0; x < db; ++x)
        ide[pos++] = kar;

    for (x = 0; mit[x] != '\0'; ++x)
        ide[pos++] = mit[x] == ' ' ? kar : mit[x];

    for (x = 0; x < db; ++x)
        ide[pos++] = kar;

    ide[pos] = '\0';
}

int main(void) {
    char novelt[30];

    strelemoge(novelt, "Hello hallo elektor kalandor", 'x', 3);
    printf("[%s]\n", novelt);

    return 0;
}

Második szó, utolsó szó

Kis ZH volt

Írj függvényt, amely paraméterként kap egy sztringet! A sztring szöveget tartalmaz, melynek szavait szóközök választják el egymástól (minden szó, ami nem szóköz). A függvény adja vissza címével átvett változókban a sztring második szavának indexét, visszatérési értékként (return-nel) pedig a sztring utolsó szavának címét! A paraméterként kapott sztringről biztosan tudjuk, hogy legalább két szóból áll, a szavakat pontosan egy szóköz választja el egymástól, és a sztring első és utolsó karaktere nem szóköz.

Megoldás

char *szavak(char *sztring, int *masodik) {
    int i, utolso = 0;
    *masodik = 0;
    for (i = 0; sztring[i] != '\0'; i++) {
        if (sztring[i] == ' ') {
            utolso = i;
            if (*masodik == 0)
                *masodik = i + 1;
        }
    }
    return sztring + utolso;
}

„The” kezdetű címek"

Könyvek, filmet címeit úgy szokás rendezni, hogy a címek elején lévő névelőket (pl. angolul a „The”, magyarul az „A” és „Az”) a rendezésben nem vesszük figyelembe. Írj egy olyan módosított strcmp_the() függvényt, amely paramétere és visszatérési értéke az eredeti strcmp()-éhez hasonló, de az összehasonlításnál figyelmen kívül hagyja a „The” kezdetet!

Megoldás

A legegyszerűbb megoldás az alábbi. Megvizsgáljuk mindkét sztringet. Ha valamelyik a „The ” részsztringgel kezdődik, az annak megfelelő pointert 4-gyel növeljük, tehát négy karakterrel hátrébb léptetjük. Az így kapott sztringeket adjuk az eredeti strcmp()-nek. A két pointer növelését azért tehetjük meg, mert azok a saját függvényünknek lokális változói, amelyet módosíthatunk.

/* Sztring összehasonlító függvény, ami nem veszi figyelembe
 * a szting elején lévő "The " előtagot */
int strcmp_the(char *egyik, char *masik) {
    if (strncmp(egyik, "The ", 4)==0)
        egyik+=4;
    if (strncmp(masik, "The ", 4)==0)
        masik+=4;
    return strcmp(egyik, masik);
}

IP cím

Vizsga volt

Írj egy olyan szabványos ANSI C függvényt, amely paraméterként kap egy sztringet, mely egy IP címet tartalmaz a szokásos alakban: négy darab 0 és 255 közötti szám pontokkal elválasztva. A függvény állítsa elő az IP cím 32 bites reprezentációját! A visszatérési értéke legyen egy unsigned érték, amelynek legalsó bájtja az IP cím utolsó részének megfelelő értéket tartalmazza, a második az IP cím utolsó előtti részét és így tovább. Feltesszük, hogy az unsigned típus az adott architektúrán legalább 32 bites. Ha a bemenet például "0.0.2.33", akkor a kimenet: 545.

Megoldás

Barátunk a scanf(). Itt egyáltalán nem kell karakterenkénti feldolgozást, és semmi hasonlót csinálni. A scanf %d be fog olvasni egy számot, és a pontnál meg fog állni, mivel a pont nem lehet része egy egész számnak. A formátumsztringbe pedig ha elhelyezünk egy pontot, akkor a scanf azt fogja várni, hogy a bemeneten ott is legyen az a pont; beolvassa és eldobja. És hát, mivel nem a standard bemenetről olvasunk, hanem sztringből, sscanf() lesz a függvényünk. Vigyázni kell, hogy a << műveleteket zárójelezni kell az összeadásnál – itt inkább bitenkénti vagy kapcsolatot használtam (az eredmény egyébként ugyanaz lenne).

#include <stdio.h>

unsigned str_to_ip(char *str) {
    unsigned a, b, c, d;

    sscanf(str, "%u.%u.%u.%u", &a, &b, &c, &d);
    return a<<24 | b<<16 | c<<8 | d;
}

int main(void) {
    printf("%u\n", str_to_ip("0.0.2.33"));
    return 0;
}

Caesar kódolás

A gyakorlaton volt egy olyan példa, amelyik karaktereket képes bekódolni a→b, b→c, c→d stb kódolással. Írj egy függvényt, amelyiknek megadható a kódolandó karakter, és a→d kódolást használ. Javítsd úgy az órán tárgyalt függvényt, hogy csak a kisbetűket kódolja, más karaktereket hagyjon változatlanul. Figyelj arra is, hogy a programkódban ne legyenek mágikus értékek (pl. 26, mint az abc betűinek száma).

Megoldás

#include <stdio.h>

/* Ez bekodol egy karaktert, a kulcs szerint. */
char kodol(char mit, char kulcs) {
    char delta = kulcs - 'a';
    if (mit >= 'a' && mit <= 'z') {
        /* eltolas */
        mit = mit + delta;
        /* tulcsuszott a z-n? */
        if (mit > 'z')
            /* akkor vissza kell menni annyit, hogy ujra az abecen
               belul legyunk. az 'annyit' erteke 'z'-'a'+1 lepes,
               nem pedig 'z'-'a'! az utobbi a ket karakter kozotti
               tavolsag, az elso pedig az a szam, amely az osszes
               letezo betuk szamat mutatja! */
            mit = mit - ('z' - 'a' + 1);
    }
    return mit;
}

char dekodol(char mit, char kulcs) {
    char delta = kulcs - 'a';
    if (mit >= 'a' && mit <= 'z') {
        mit = mit - delta;
        if (mit < 'a')
            mit = mit + ('z' - 'a' + 1);
    }
    return mit;
}


int main(void) {
    char szoveg[] = "hello, world!";
    int i;

    /* az abc kiirasa */
    for (i = 'a'; i <= 'z'; ++i)
        printf("%c", i);
    printf("\n");
    for (i = 'a'; i <= 'z'; ++i)
        printf("%c", kodol(i, 'd'));
    printf("\n");

    /* szoveg kodolasa */
    for (i = 0; szoveg[i] != 0; ++i)
        szoveg[i] = kodol(szoveg[i], 'd');
    printf("[%s]\n", szoveg);

    /* szoveg dekodolasa */
    for (i = 0; szoveg[i] != 0; ++i)
        szoveg[i] = dekodol(szoveg[i], 'd');
    printf("[%s]\n", szoveg);

    return 0;
}