Keresés

Hirdetés

Új hozzászólás Aktív témák

  • Jester01

    veterán

    válasz TheRolf #2493 üzenetére

    Először is, használd a fordítót arra, hogy minél több hibát jelezzen neked. gcc esetén erre a -Wall kapcsoló szolgál. Lássuk mi nem tetszik neki:

    t.c: In function 'fordit':
    t.c:14: warning: implicit declaration of function 'malloc'
    t.c:14: warning: incompatible implicit declaration of built-in function 'malloc'
    t.c:14: error: called object 'str' is not a function
    t.c:15: error: called object 'out' is not a function
    t.c:15: warning: return makes integer from pointer without a cast
    t.c: At top level:
    t.c:18: warning: return type defaults to 'int'
    t.c: In function 'main':
    t.c:21: warning: assignment makes pointer from integer without a cast

    Az első kettő azért van, mert nincs meg a malloc prototípusa, ehhez erősen ajánlott egy #include <stdlib.h> (bár nem kötelező).

    A következő kettő azért van, mert kerek zárójelet használtál szögletes helyett tömb indexeléshez.

    Az ötödik probléma, hogy a main() függvényed visszatérési típusa nincs megadva. Bár C-ben alapértelmezés az int, de azért ajánlott kiírni.

    Az utolsó kettő oka, hogy a függvényed visszatérési típusából hiányzik egy csillag, hogy pointert adjon vissza.

    Ezeket javítva sajnos további hibákra derül fény:

    t.c: In function 'main':
    t.c:25: warning: control reaches end of non-void function
    t.c: In function 'fordit':
    t.c:16: warning: 'i' may be used uninitialized in this function
    /tmp/ccle9qDf.o: In function `main':
    t.c:(.text+0x89): warning: the `gets' function is dangerous and should not be used.

    Az első, hogy a main() nem ad vissza értéket. Ezt egy return 0; kiválóan orvosolja.

    A második már súlyosabb, azt mondja, az i változónak nincs kezdőérték megadva mielőtt használod. C-ben a változóknak nincs alapértelmezett kezdőértékük.

    Végül, a gets függvény használata veszélyes, mivel nincs benne hosszúság ellenőrzés. Ugyan ez nem végzetes hiba de helyette ajánlott az fgets használata.

    Jelenleg akkor így néz ki a program ami a fordítónak már nem okoz fejfájást:

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

    int hossza(char *str){
    int i=0;
    while (str) {
    i++;
    }
    return i;
    }

    char* fordit(char *str) {
    int i=0;
    char *out;
    out = (char*)malloc((hossza(str))*(sizeof(char)));
    while (str[i]) {
    out[i] = str[-i-1];
    }
    return out;
    }

    int main() {
    char betuk[50];
    char *z;
    gets(betuk);
    z = fordit(betuk);
    puts(z);
    free(z);
    //getchar();
    return 0;
    }

    (A gets benne maradt egyelőre, lásd később.)

    Ezután jutunk el a futási hibákhoz. A felderítésükhöz debugger vagy más diagnosztikai program (pl. valgrind) ajánlott. Példának okáért kapjuk elő a gdb debuggert. Miután beadtuk a stringünket, azt látjuk, hogy a processzor pörög de nem történik semmi. Nézzük meg miben mesterkedik a programunk:

    (gdb) r
    Starting program: /var/tmp/a.out
    hello
    ^C
    Program received signal SIGINT, Interrupt.
    hossza (str=0x7fffffffe6d0 "hello\n") at t.c:6
    6 while (str) {

    Ahha. Szóval ott került végtelen ciklusba, mivel az str az biza nem változik. Oda igazából str[i] kellene. Nézzük, jobb lesz-e ettől. Igen, most egy másik ciklusban pörög, aminek a feltétele a megtévesztésig hasonló:

    Program received signal SIGINT, Interrupt.
    0x00000000004005f5 in fordit (str=0x7fffffffe6d0 "hello\n") at t.c:16
    16 while (str[i]) {

    Innen pedig azért nem lép ki, mert az i nem változik a ciklusban. Tegyünk róla, hogy 1-el növekedjen. Szuper jó, ettől már legalább lefut a program, csak semmit nem ír ki. Nézzük meg például honnan lesz első betűje a kimenetnek:

    (gdb) br 17
    Breakpoint 1 at 0x40066d: file t.c, line 17.
    (gdb) r
    Starting program: /var/tmp/a.out
    hello

    Breakpoint 1, fordit (str=0x7fffffffe6d0 "hello\n") at t.c:17
    17 out[i] = str[-i-1];
    (gdb) p i
    $1 = 0
    (gdb) p -i-1
    $2 = -1

    Hoppá, mire is kértük a számítógépet? out[0] = str[-1]. Ez így nem lesz jó, oda nekünk az utolsó betű kellene, ami azt jelenti itt még hozzá kellene adni a string hosszát. Tegyük ezt meg. Csoda, kiírta fordítva a szöveget. Na de minket nem olyan egyszerű boldoggá tenni, ráengedjük a valgrindot is:

    hello
    ==28218== Invalid read of size 1
    ==28218== at 0x4C25824: __GI_strlen (mc_replace_strmem.c:284)
    ==28218== by 0x4E8DDCA: puts (ioputs.c:37)
    ==28218== by 0x400697: main (t.c:28)
    ==28218== Address 0x518a045 is 0 bytes after a block of size 5 alloc'd
    ==28218== at 0x4C244E8: malloc (vg_replace_malloc.c:236)
    ==28218== by 0x40061D: fordit (t.c:15)
    ==28218== by 0x400687: main (t.c:27)

    Elismerem ez kissé érthetetlen, de azt szeretné mondani nekünk, hogy a kiírásnál az első 5 byte után a hatodik olvasása nem jó. De miért is akar hatot olvasni, ha egyszer a "hello" csak 5 betű. Jusson eszünkbe, hogy C-ben a stringek végét egy nulla byte jelzi. Írjuk át a programot, hogy ezt vegye figyelembe. Ettől már a valgrind is elégedett lesz.

    Végszó:
    1) Sajnos az fgets függvény a sor végét jelző entert is eltárolja a pufferbe, így azzal extra izzadnunk kell egy kicsit.
    2) gondolom az strlen használata tiltott volt, ezért írtál saját hossza függvényt
    3) sizeof(char) definíció szerint 1.
    4) a malloc visszatérési típusa void*, és az bármilyen pointerré cast nélkül konvertálható. Lehetőleg kerüljük a felesleges castolásokat.
    5) némi visszajelzés a felhasználó felé nem árt

    Fentiek figyelembevételével a végső program:

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

    int hossza(char *str){
    int i=0;
    while (str[i]) {
    i++;
    }
    return i;
    }

    char* fordit(char *str) {
    int i=0;
    int hossz=hossza(str);
    char *out = malloc(hossz+1);
    while (str[i]) {
    out[i] = str[hossz-i-1];
    i++;
    }
    out[i]=0;
    return out;
    }

    int main() {
    char betuk[50];
    char *z;
    int hossz;
    printf("string (max %d karakter):\n", sizeof(betuk)-2);
    fgets(betuk, sizeof(betuk), stdin);
    hossz=hossza(betuk);
    if (hossz>0 && betuk[hossz-1]=='\n') {
    betuk[hossz-1]=0;
    }
    z = fordit(betuk);
    puts(z);
    free(z);
    return 0;
    }

    Elnézést a hosszú hozzászólásért, csak igyekeztem halászatot oktatni, nem sült galambot kínálni.

    Jester

  • kingabo

    őstag

    válasz TheRolf #2813 üzenetére

    Hali!

    Csak gyorsan átfutva az tűnt fel, hogy a string-ben az n+1-edik elemre hivatkozol. Pl van egy 5 hosszú stringed, akkor az indexek 0 és 4 között vannak a string[len-i] i=0 esetén viszont 5. Megoldás vonj le még 1-et az indexből, vagyis így nézzen ki string[len - i - 1].
    Hibakereséhez ajánlom a debugger használatát. ;)

  • Jester01

    veterán

    válasz TheRolf #2813 üzenetére

    1) gets-t tilos használni
    2) teljesen fölösleges a két változat, a második jó (lesz*) mind a két esetben
    3) a math.h is fölösleges
    4) ha egyszer int main, akkor illene valamit visszaadni
    5) a fordító üzeneteit érdemes megszívlelni (és persze bekapcsolni őket)
    6) a kiírás végére illene soremelést tenni
    7) a "valamiért nem fut le" szánalmas hibaleírás
    8) a ciklusból ki lehet lépni ha már kiderült, hogy nem palindrom

    MOD: * úgy értem, ha a kingabo által fentebb jelzett hibát javítod

    [ Szerkesztve ]

    Jester

  • Jester01

    veterán

    válasz TheRolf #2822 üzenetére

    1) igen, fgets-et szabad. Annak meg lehet adni mekkora a puffered mérete, így nem fog többet visszaadni annál.
    4) igen
    5) nézz körül hol lehet bekapcsolni a figyelmezető üzeneteket is (warnings)
    6) igen

    Jester

  • Jester01

    veterán

    válasz TheRolf #2825 üzenetére

    Itt csak az a baj, hogy az atoi-nek string kell, ami C-ben nulla byte-tal lezárt karaktertömböt jelent. Több lehetőséged is van. Talán a legegyszerűbb, ha a kar[1]-et nullázod. Ekkor ugye így fog kinézni a tömb { x, 0, y, 0 } (a végére az fgets tette a nullát). Ilyenformán a konverzióhoz simán megadhatod az &kar[0] illetve &kar[2] pointereket (ami ugyanaz mint a kar ill. kar+2).

    Másik lehetőség egy számjegyű számok konvertálására ha simán levonod belőle a 0 ascii kódját, pl. n = en - '0';

    Jester

  • Jester01

    veterán

    válasz TheRolf #2903 üzenetére

    Nem, ez lehetetlen! ;]
    Micsoda hülye kérdés, persze, hogy meg lehet. A scanf alapesetben nem is tesz különbséget a white space karakterek között tehát hidegen hagyja hány sorban írod be. Egyszerűen ciklusban hívd annyiszor ahányszor kell.

    Jester

Új hozzászólás Aktív témák