Segfault, de miért?

 ( snail | 2008. április 8., kedd - 17:33 )

sziasztok!

most kezdtem el nemrég gyúrni a c-t, a c példatár című könyv segítségével próbálom megérteni, hogy mi miért történik... adott az alábbi feladat:

Írjunk programot, amely kiírja egy dolgozat szöveges értékelését az érdemjegy alapján

a kód pedig:
#include

main( ) {
int jegy;
printf( "Érdemjegy: " ); scanf( "%d", &jegy );
switch( jegy ) {
case 1: puts( "elégtelen" ); break;
case 2: puts( "elégséges" ); break;
case 3: puts( "közepes" ); break;
case 4: puts( "jó" ); break;
case 5: puts( "jeles" ); break;
}
}

ez így gyönyörűen működik, de gondoltam, miért ne lehetne a jegy egy unsigned short, amikor 1 és 5 közé eső számról van szó. viszont amikor átírtam, akkor ugyan megmondta, hogy a hármas az a közepest jelenti, de utána Segmentation fault (core dumped) üzenettel lépett ki.

ugyan nem dől össze a világ emiatt a probléma miatt, csak kíváncsi vagyok, hogy ez így miért nem jó neki?
köszönöm!

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

Idézet (man scanf)
"
The following conversion specifiers are available:
[...]
d Matches an optionally signed decimal integer; the next pointer must
be a pointer to int.
"
Tehát, ha ascanf-ben %d-t használsz, akkor a pointerednek is signed int-re kell mutatnia.

Szintén innen idézet:
"The following type modifier characters can appear in a conversion specifica-
tion:

h Indicates that the conversion will be one of diouxX or n and the next
pointer is a pointer to a short int or unsigned short int (rather
than int).
"

Remélem ez segített.

Igen, ez segített, köszönöm, de egy újabb kérdés született:
ha úgy adom meg, hogy
scanf( "%d", ( int * ) &jegy );
akkor ennek nem kellene a hibát rendberaknia? vagy ezt nem azért találták ki? :)

Nem, attól, hogy te a pointert átcastolod attól még az a változó típusa nem változik meg, csak máshogy kezeli, és mivel az unsigned short rövidebb mint az int, a lefoglalt területen kívülre akar írni, ezért segfaultol.

Szerintem az int alapból signed.
Mi van nálad az include után, kacsacsőrök között? Leszedte a fórummotor. Nálam stdio.h, és megy, nem segfaultol.
Milyen C fordítót használsz?

Próbáld ki az alábbi kódot:

#include <stdio.h>
main(){
     printf("Hello, C!\n");
}

Ez megy?

Azért, mert nálad nem segfaultol, még nem jelenti azt, hogy jó...

Ahogy razta is írta, a scanf int*-ot vár...
Nem az a lényeg, hogy signed vagy nem, hanem az, hogy az int 4 byte, míg a short int csak 2 legalábbis x86-on.

(Az unsigned short==unsigned short int)

A gond az, hogy létrejön egy short int a veremben, azaz 2 byte-nyi hely, majd a scanf szépen beleír 4 byte-ot. Mivel az x86 little endian, ezért a short int-ben jó érték van, csak épp a következő 2 byte is kinullázódik. Ha ott valami értelmes adat volt, akkor már nincs. És mi szokott a verem tetején lenni a változók előtt? Visszatérési cím, és hasonló "felesleges" dolgok. Ami ügyesen felülíródott, legalább részben. Na ezért a segfault.

Ha véletlenül mégsics segfault az max azért lehet, mert a fordítók szeretik szóhatárra (4 byte) rakni a változókat, így bekerülhet használatlan terület a változók közé, és nem okoz galibát a felülírás...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Köszönöm, azt hiszem értem, hogy mi volt a baj, de azért a biztonság kedvéért leírom, javíts ki kérlek ha nem így van - eddig abban a hitben éltem, hogy a printf-nek átadott %d csak annyit tesz, hogy oda egy decimális számot kell írni, de akkor ezek szerint ebben a %d-ben bennevan azis, hogy 4 bites helyre akarok írni.

printf-nél a %d azt jelenti, hogy (signed) integer.
%u azt, hogy unsigned integer.
%hd: (signed) short (int)
%hu: unsigned short (int)

De printf-nél nem okoz gondot, mert ha %d-t írsz, de short int-et adsz át, akkor annyi történik, hogy a printf konvertálja a short-ot int-té, ami biztonságos (kisebbet a nagyobba).
Ellenben ha %d-t írsz, és long int-et adsz át, akkor az érték csonkolódik, és 2^32-en felett hülyeségeket fog kiírni, de nagyobb baj nem történik.

scanf-fel is hasonló a dolog, csak ott mutatót kap, amit gond nélkül konvertálgat egyik típusból a másikba, és ott van a bibi, mikor megtörténik a beolvasott szám értékadása...
A scanf tehát veszélyes.

(És akkor még nem is próbáltad, mi történik, ha szöveget írsz szám helyett... :) )

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Azt irta: "ez így gyönyörűen működik, de gondoltam, miért ne lehetne a jegy egy unsigned short", tehat int-et atirta, de gondolom %d-t mar elfelejtette %u-ra.

Jaaa... Bocs, write only módban voltam.

Akarod mondani %hu-ra...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Valoban. Koszonom a korrekciot.