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ána 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!
- 946 megtekintés
Hozzászólások
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.
- A hozzászóláshoz be kell jelentkezni
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? :)
- A hozzászóláshoz be kell jelentkezni
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.
- A hozzászóláshoz be kell jelentkezni
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?
- A hozzászóláshoz be kell jelentkezni
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
- A hozzászóláshoz be kell jelentkezni
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.
- A hozzászóláshoz be kell jelentkezni
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
- A hozzászóláshoz be kell jelentkezni
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.
- A hozzászóláshoz be kell jelentkezni
Jaaa... Bocs, write only módban voltam.
- A hozzászóláshoz be kell jelentkezni
Akarod mondani %hu-ra...
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o
- A hozzászóláshoz be kell jelentkezni
Valoban. Koszonom a korrekciot.
- A hozzászóláshoz be kell jelentkezni