Üdv!
Egy szöveges, kézzel vi-jal szerkeszthető fájlban (adat.text) számjegyek vannak egymás alatti sorokban, pölö így:
12345624
27638744
17622357
28454989
a sorokat egyesével be tudom olvasni ciklusban egy stringbe (s), de csak a lenti módon sikerült elérnem, hogy pölö a 4. karaktert egész számként használhassam.
ifstream befajl;
string s;
char c;
int i;
befajl.open ("adat.text");
getline(befajl,s);
c=(char) s[3];
i=atoi(&c);
i=i*3;
cout << i << endl;
befajl.close();
Van valamilyen egyszerűbb/elegánsabb módja, hogy elérjem a célomat C++ alatt?
Próbálkoztam még ezzel is:
char * cp;
c=befajl.get();
cp=&c;
i=atoi(cp);
Sajnos ebben az esetben a hasznos stringek utáni fehérkaraktereket is beolvassa a fájlból a program. (Persze ciklusban megadhatnám, hogy egy-egy sorban hány darab karaktert akarok beolvasni, de hogyan ugrok a következő sorra, kihagyva az adott sor nem érdekes részét?)
Köszi!
Hozzászólások
1. Tessen hasznalni a [code] BBCode taget. Baromi olvashatatlan igy a kod.
2. Lehet karakterenkent is olvasni a file-t (ekkor persze inkabb tisztan C-ben erdemes lekodolni), es akkor kiporgeted (fseek) a szamodra erdektelen reszt, beolvasod a szamjegyet, es atoi. De ha inkabb a feladatot mondanad el, ugy tomondatokba, mindenki jobban jarna. Mert amennyire elnezem, teljesen felesleges ennyire c++ oldani meg a dolgot. Raadasul csak felig C++ mert a cin-t ki se hasznalod.
Szuper! Köszönöm!
--
unix -- több, mint kód. filozófia.
Life is feudal
Annyit még lehetne kérni, hogy elmondd, miért ez a jó megoldás?
A '0' ebben a formában egy karakter konstans, nem? Ennek az ASCII értéke mintha 38 lenne, de erre már nem emléxem. Önmagában az s[3] nem az s string 4. karakterét jelenti ezexerint? Miért kell kivonni belőle a nulla karaktert? Ez így ebben a formában nem a karakterlánc terminátor ugye? Ha jól sejtem a string objektum nem nulla bájtos végű karakterláncot jelent, hanem az objektumban el van tárolva a string hossza és onnan lehet tudni terminátor nélkül is, hogy mekkora a karakterlánc.
Köszönöm!
--
unix -- több, mint kód. filozófia.
Life is feudal
Szerintem mégjobb megoldás:
open
read
--
CCC3
Köszönöm a tippet! Megvizsgálom mire jutok vele.
--
unix -- több, mint kód. filozófia.
Life is feudal
Nem.
s egy
(0 byte) végződésű byte tömb. Aminek minden eleme egy byte, azaz s[3] a 4. elem, spec egy karakter:
, ami az ASCII kódtáblában a
után következő 8. elem.
Tehát
a 0 KARAKTERTŐL való távolságot nézi - spec. hogy ez melyik SZÁM.
és ezt így nyersen bele lehet tolni egy integerbe? Ez kicsit hasonlít arra, amikor anno a commodore plus 4-esen assemblyben attól függően mást eredményezett a 0ah memóriába írása, ha a képernyőmemóriáról, vagy a szín memóriáról volt szó... Maga a byte ugyanaz, csak máshol mást jelent. Itt attól függően mást jelent az adott helyen található byte, hogy milyen típusú változóba kerül?
--
unix -- több, mint kód. filozófia.
Life is feudal
"és ezt így nyersen bele lehet tolni egy integerbe?"
Ez így mehet egész típusba, ugyanis a char is egész típusú (pontosabban integrális típusú). A megoldás a kódtábla azon tulajdonságát használja ki, hogy a számjegyek benne egymást követik, emelkedő sorrendben.
"s egy '\0' (0 byte) végződésű byte tömb"
Nem, az s itt egy std::string típusú változó. A végeredmény szempontjából ez persze mindegy, mert a string [] operátora egy char típusú karaktert ad vissza, úgy mint a sima null-végű karaktertömböknél.
Egy nulla byteos karaktertömb egy eleme önmagában csak egyetlen karakter, nulla nélkül, nem? Akkor miért volt szükség erre:
"s[3] - '0'"?
Ha egy byteon tárolódik egyetlen karakter, akkor s[3] mérete egy byteos, nem? A fenti sor nem azt jelenti, hogy egy nullás írásjelet von ki egyetlen karakterből?
"Tehát s[3]-'0' a 0 KARAKTERTŐL való távolságot nézi - spec. hogy ez melyik SZÁM."
Történetesen ezt a fenti sort nem értem. Illetve nem vagyok biztos abban, hogy jól értem a kivonás formájú írásjellel megvalósított operátor szerepét. Nyilván nem aritmetikai kivonásról van szó, nem? Csak egy nagyon hasonló dologról? Ugyanígy ha s[3] történetesen egy B írásjel lenne, akkor s[3] - 'A' eredménye egy lenne? Mondhatjuk, hogy a '-' jel olyan "távolságmegmondó" operátor a std::stringek esetén (vagyis nem std::string, csak az std::string egyetlen karaktere)?
És még ez sem világos:
Ha s egy std::string típusú változó valamilyen értékkel, akkor s[3] típusa micsoda? std::string[3]? Hogy hívjuk ezt a típust?
Most végül is s string egy nulla végű karakterlánc, vagy egy olyan objektum ami tárolja egy adattagban a hosszát?
--
unix -- több, mint kód. filozófia.
Life is feudal
Mint már írtam, a string [] operátora egy char értéket ad vissza, tehát s[3] egy sima char. A megértéshez azt kell tudni, hogy a karaktereket is számmal tárolja a gép, általában ASCII kódtábla szerint. Tehát ha van egy char változód, amiben leírva a '4' szám van, az valójában 52-t tartalmaz. A '0' számjegy a kódtáblában a 48-as értékű, ha jól emlékszem. A kivonás a szokásos módon működik, egy egyszerű művelet ezen két egész között. Tehát ha az s[3], ami az s 3. karaktere egy '4'-es, akkor a művelet így néz ki: '4'-'0', egészekre lefordítva: 52-48. Ennek az értéke természetesen 4, amit már be lehet pakolni az int-be.
Az s változót te hoztad létre, méghozzá string típussal. A string egy objektum.
A null végű karakterlánc így nézne ki:
Javaslom valamilyen könyv nézegetését a témában, vagy vannak jó online források is, pl www.cppreference.com
Köszönöm a választ! Valahol a filerendszeren belül meg lehet találni a std::string osztály leírását (Deklaráció?)? Gondolom, ha belenézek a cpp kódba, akkor látni fogom, hogy mi alapján tudja magáról egy std::string, hogy mekkora a mérete.
Nézegetek könyveket.
--
unix -- több, mint kód. filozófia.
Life is feudal
Nálam most épp:
"MinGW\include\c++\3.4.2\bits\basic_string.h"
Linux alatt értelemszerűen. Ezzel egyébként nem leszel beljebb. :)
A lényeg, hogy az iso szabvány nem rendelkezik a belső ábrázolásról. Legtöbbször a méretet folyamatosan nyilvántartja egy változóban, és a karaktereket egy folytonos területen tárolja a memóriában.
De persze elképzelhető lenne egy olyan megvalósítás, hogy a string tartalmát valahány karakteres szakaszokban tárolja egy listában, ezzel felgyorsítva az összefűzést, beszúrást, stb.
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o
Köszönöm!
A lenti hivatkozást is! :D
--
unix -- több, mint kód. filozófia.
Life is feudal
Egy kis elgondolkodtato…
Spolsky altal leirt a problema a sztring hasznalatakor itt:
http://hungarian.joelonsoftware.com/Articles/BacktoBasics.html
Vissza az alapokhoz
Szerző: Joel Spolsky
Fordította: Krisztián Gyuris
2001. December 11.
Általában sok időt töltünk az olyan magasszintű dolgok megvitatásával, mint a .NET és a Java összehasonlítása, XML stratégia, a Lock-In, versenystratégia, szoftver tervezés, architektúra és így tovább. Ezek a dolgok csak egy rétege a tortának, ha úgy tetszik. A legfelsőbb réteg a stratégia. Eggyel alatta az architektúrák vannak pl .NET és ez alatt pedig olyan fejlesztői eszközök, mint a Java vagy platformok, mint a Windows.
Menj lejjebb egy szintet. Dll-k? Objektumok? Eljárások? Nem! Lejjeb! Addig a pontig ahol már a programsorokról van szó.
Még mindig nem elég. Ma a CPU-król szeretnék beszélni. Egy kis darab szilikonmorzsa, amiben bájtok szaladgálnak. Tegyél úgy egy pillanatra mintha kezdő programzó lennél. Felejts el mindent, amit idáig tudsz a programozásról, a menedzsmentről és menj vissza a Neumann féle elmélethez. Felejtsd el a J2EE-t egy pillanatra. Gondolkodj bájtokban.
Miért erre szükség? Azt hiszem néhány hiba, amit az emberek elkövetnek a stratégia szintjén abból fakad, hogy egyes alapelveket nem teljesen vagy egyáltalán nem értenek. Egy gyönyörű palotát építettél, de az épület gyenge alapokon nyugszik. Így aztán egy jó erős beton alap helyett egy gyenge alapra építkezel. A palota jól néz ki, de a csap leesik a a fürdőszobában és gőzöd sincs, hogy miért.
Most vegyünk egy nagy levegőt. Tarts velem, egy kis gyakorlatra.
Emlékszel hogyan működnek a C sztringek: egy csomó bájtot tartalmaznak, amit egy null karakter követ (ennek az értéke nulla). Ennek két nyilvánvaló következménye van:
1.Nem tudjuk megmondani a sztring hosszát anélkül, hogy, végig ne menjünk rajta a null karakterig.
2.Nem lehetnek nullák a sztringben. Tehét bináris állományok, mint például JPEG tárolására nem alkalmas egy C sztring.
Miért működnek a C sztringek így? Azárt mert a PDP-7 mikroprocesszor, amelyen megalkották a UNIX-t és a C programozási nyelvet rendelkezett ASCIIZ sztring típussal ASCIIZ “ASCIIZ Z-vel (zéróval) a végén”.
Ez az egyetlen mód arra, hogy sztringeket tároljunk? Nem, valójában ez az egyik legrosszab megoldás. Egyszerűbb programoknál, programozási felületeknél, operációs rendszereknél, osztálykönyvtáraknál, óvakodnod kell az ASCIIZ sztringektől, mint a pestistől. Miért?
Kezdjük azzal, hogy megirjuk a strcat függvényt, amivel egy függvényt összefűzhetünk egy másikkal.
Ha jobban megnézed a kódot könnyen rájöhetsz hogyan is működik. Elöször, végigmegyünk az első sztringen a nulla karakterig. Amikor megtaláltuk, végigmegyünk a második sztringen, egyenként átmásolva a karaktereket.
Ez a fajta sztring kezelés és összefűzés elég jó Kernighan-nek és Ritchie-nek, de megvannak a hátrányai. Itt van mindjárt egy probléma. Tegyük fel, hogy van egy rakás név, amit egy sztringgé szeretnénk összefűzni:
Ez így működik ugye? Igen. És egy tiszta és szép megoldás.
Milyen a teljesítménye? Olyan gyors amilyen csak lehet? Jól skálázható? Ha egymillió sztringünk lenne összefűzésre, akkor is ezt a megoldást használnánk?
Nem. Ez a kód a “Shlemiel féle festő algoritmust” használja. Ki az a Schemiel? Ime a vicc:
Schemielt felveszik útkarbantartónak, Neki kell az elvalasztóvonalat festeni az út közepére. Az első napon magához vesz egy vödör festéket és a nap végére 300 méternyi vonalat fest fel az útra. "Ez kiváló!" mondja a főnöke, "kiváló munkaerő vagy!" és ad neki egy dollárt.
A következő napon, csak 150 méter vonalat fest. "Nos, ez nem olyan sok mint tegnap, de még mindig elégedett vagyok. 150 méter igen szép teljesítmény." és add neki egy dollárt.
A következő nap Schemiel csak 30 méterrel végez. "Csak 30 méter!" ordít a főnök. "Ez elfogadhatatlan! Ez első napon tízszer ennyit festetél! Mi folyik itt?"
"Nem tehetek róla, uram" válaszolja Schemiel. "Minden nap messzebre és messzebre kerülök a festékes vödörtől!"
(Egy kis agytorna, mik a valódi számok a viccben ?) Ez a gyenge vicc azt hivatott illusztrálni mi megy végbe, amikor az strcat függvényt használod. Mivel az strcat függvénynek végig kell menni a cél sztringen minden esetben, a zéro karakter miatt újra és újra, ezért nagyon lassú lesz a fent mutatott ejárás és nem skálázható jól. Nagyon sok mindennap használt kódnak ez a baja. Nagyon sok file rendszert implementáltak úgy, hogy a teljesitmeny drámaian csökken ha több ezer file van egy könyvtárban. Próbálj megnyitni egy telepakolt Windows szemetest, hogy lásd ezt a hatást a gyakorlatban is – perceket vesz igénybe amig feljön az ablak, ami nincsen lineáris kapcsolatban a fileok számával. Valahol elrejtve ott dolgozik egy “Schemiel féle festő algoritmus”. Bármikor amikor úgy tűnik, hogy lineáris kapcsolat kell, hogy legyen és ehelyett négyzetes adódik, keress rejtett Schemieleket. Gyakran a programozói könyvtárakban van elrejtve. Egy sor strcat-ról vagy egy strcat ciklusbamagban nem ordít négyzetes teljesítményről, pedig erről van szó.
Hogyan lehet ezt kiküszöbölni? Néhány eszes C programozó megalkotta a saját strcat függvényét, ime:
Mit is értünk el itt? Nagyon kis többlet munkával visszaadjuk az új hosszú sztring végét. Igy az ezt használó kód hozzá tud illeszteni egy új sztringet, anélkül hogy újra végig kellene menni az egész sztringen:
Ez igy, természetesen, lineáris teljesítményt eredményez, négyzetes helyett, így hát nem lassul le hogyha nagyon sok sztringet kell összefűzni.
A Pascal nyelv tervezői tudtak erről a problémáról és „megoldották” a problémát úgy, hogy az első bájton tárolták el a sztring hosszát. Ezt a fajta sztringet Pascal sztringnek nevezzük. Tartalmazhatnak nullákat és nem nullára végződnek. Mivel a bájt csak 0 és 255 között képes számokat ábrázolni ezért a Pascal sztring nem lehet 255-nél hosszabb, mivel a Pascal sztring nem tartalmaz nulla karaktert ezért pontosan ugyanakkora helyet foglal el mint egy 255 karakter hosszú ASCIZ sztring. A nagy erőssége a Pascal sztringnek az hogy nem kell végigszaladni rajta, hogy meg tudjuk mondani a hosszát. A hossz információ költsége egy Pasal sztring esetében egyetlen utasítás szemben egy ciklussal. Ez sokkal gyorsabb.
A régi Machintos operációs rendszer Pascal sztringeket használt. Nagyon sok C programozó más platformokon Pascal típusú sztringeket használt a sebbeségük miatt. Az Excel Pascal sztringeket használ belső műveletekhez ez az amiért néhány helyen a sztringek hossza 255 karakter lehet maximum, és ez az egyik ok amiért az Excel nagyon gyors.
Hosszú időn keresztül, ha Pascal sztringet akartál C-ben használni, valami ilyesmit kellett csinálni:
Igen, a bájtokat saját magadnak kellett megszámolni és bedrótoznod a sztring első bájtjába. Egy lusta programozó ezt így oldaná meg, egy lassú programot kapva végeredményként:
Észrevehetjük, hogy ez a sztring tulajdonképpen egy nulla terminált sztring (a fordítónak köszönhetően) és Pascal sztring is. Ezeket a sztringeket elcseszett sztringeknek kerszteltem el magamban, mivel könnyebb kimondani, mint azt hogy nulla végű pascal sztring, de mivel ez egy korhatár nélküli website így kénytelenek leszünk a hosszabb nevet használni.
Kihagytam egy fontos dolgot az előbb. Emlékszel még erre?
char bigString[1000]; /* Nem tudom, hogy milyen hosszú lesz... */
Mivel ma a bitekről és bájtokról beszélünk ezt nem lett volna szabad kihagynom. Helyesen kellett volna eljárnom: kitalálni hogy mennyi bájtra van szükségem és pontosan annyit foglalni le a memóriából.
Ugye?
Mivel másképpen, egy ügyes hacker a kódból kitalálhatja, hogy 1000 karaktert foglaltam - remélve, hogy elég lesz - és találna valami ügyes módot arra, hogy valahogy egy 1100 bájt hosszú sztringet irjon az 1000 bájt hosszú sztringem helyett, ezzel felül írva a stacket és megváltoztatva a visszatérés címét. Amikor aztán ez a függvény befejezi a futást, lehetőség nyílhat a hacker által irt kód futtatására. Ezt a jelenséget hívják buffer overflow-nak. Régebben ez volt az elsőszámú módszere a hackereknek és féreg programoknak, hogy hozzáférjenek más rendszerekhez, mielőtt az Outlook segítségével széles rétegek számára elérhetővé vált az illegális kód futtatása más gépeken.
Rendben, tehát minden programozó lusta. Ki kellett volna találniuk, hogy mennyi memóriát kellett volna lefoglalni.
De valójában, a C nem könnyíti meg a dolgunkat. Térjünk vissza a Beatles-s példánkra:
Mennyi memóriát kellene lefoglalnunk? Próbáljuk meg most “A Helyes Utat”.
Lassan kezdek elfáradni. Valószínűleg már te is rég magamra hagytál. Nem is hibáztatlak ezért, de tarts velem, mert innentől kezd érdekes lenni.
Mindig végig kell futnunk a sztringen egyszer azért, hogy megmondjuk a hosszát, aztán újra végigfutunk, hogy összefűzzük. Ha Pascal sztringet használunk, akkor legalább a strlen művelet az gyors. Esetleg írhatnánk egy olyan strcat függvényt, amely lefoglalja és hozzádja a szükséges memóriát a cél sztringhez.
Ez felvet egy másik érdekes problémát is. Tudod hogyan működik a malloc függvény? A malloc egy láncolt listában tárolja a szabad memória blokkokat. Amikor meghívod a malloc-t, akkor az végigsétál ezen a láncolt listán, addig amíg a kérésnek megfelelő nagyságú memória blokkot (vagy annál nagyobbat) nem talál. Ezután két részre osztja a blokkot – az egyik a kérésnek megfelelő méretű, a másik pedig a maradék, az első lesz a lefoglalt memória terület és a maradékot (ha van) visszateszi a láncolt listába. Amikor a free függvényt hívod meg, akkor hozzáadja a felszabadítani kívánt blokkot a listához. Esetenként a szabad memória területek listája elaprózódik és amikor neked egy nagyobb darabra lenne szükséged előfordulhat, hogy nincsen akkora memória egyben. Ekkor a malloc függvény timeout-t add és elkezdi a szabad memória láncot rendezgetni és a szabad darabokat nagyobb darabokká összeállítani. Ez körübelül 3 és fél napot vesz igénybe. Ebből az egészből az következik, hogy a malloc nem igazán gyors (mindig végigszalad a szabad memória listán), és néha, előrejelezhetetlenül és sokkolóan lelassul, amíg újrarendezi a listát. (Ez véletlenül éppen ugyanazt a teljesítmény profilt mutatja, mint az úgynevezett szemétgyűjtő (garbage collection) rendszerek. Nahát, nahát. Tehát azok, akik az ilyen (garbage collection) rendszerek lassúságát kritizálják nincsen teljesen igazuk, hiszen ez hasonlít a malloc működéséhez, jóllehet ez utóbbi nem annyira erőforrásigényes.)
Okos programozók úgy kerülik el a malloc ezen zavaró viselkedését, hogy mindig 2 hatványával felírható nagyságú memóriát foglalnak le. Tudod, 4 byte, 8 byte, 16 byte, 18446744073709551616 byte, és így tovább. Rgyébb okokból, ami nyilvánvaló kell, hogy legyen annak, aki játszott már LEGO-val, ez lecsökkenti a furcsa töredezettségek számát a szabad láncban. Habár ez a módszer pazarlónak látszik, könnyen belátható, hogy így sohasem pazarlunk el többet mint a lefoglalt memória 50 százaléka. Tehát a programod nem használ többet, mint a szükséges memória kétszerese, ami még elfogadható.
Ha megírtad az intelligens strcat függvényt, ami mindig újra allokálja a cél buffert. Mindig pontosan a szükséges nagyságú memóriát kell lefoglalni? Tanárom és mentorom Stan Eisenstat azt tanácsolja, hogy amikor meghívod a realloc függvényt, mindig az előzőleg lefoglalt memória kétszeresét kell lefoglalnod. Ez azt jelenti, hogy a realloc-t nem kell lg n –nél többször meghívnod, aminek így igen jó lesz a teljesítmény karakterisztikája és nem pazarolsz 50%-nál több memóriát.
Akárhogy is. Az élet egyre és egyre bonyolultabb lesz itt bájtföldön. Hát nem vagy szerencsés, hogy nem kell C-ben kódolnod többé? Ott vannak a Perl és Java, VB és XSLT – nagyszerű nyelvek – soha többet nem kell ilyesféle dolgokon gondolkodnod, mivel ezek a nyelvek megoldják ezt helyetted. De néha elsyabadul a pokol és - csőtörés miatt - a szennyvíz elárasztja a nappalid és olyan dolgokon kell törnünk a fejünket, hogy a String vagy a StringBuilder osztályt használd, vagy hasonló dolgok, mivel a fordítók nem elég okosak ahhoz, hogy megértsék, hogy mit is próbálunk elérni és segíteni abban, hogy ne tegyünk Schemiel féle festő algoritmusokat a kódunkba.
....
....
Az ilyen és hasonló kérdések kívánják meg azt hogy bitekben és bájtokban gondolkozzunk és ezek azok a dolgok amik kihatnak a stratégia és architektúrális szintekre is. Ezért gondolom azt, hogy az elsőéves informatikus halgatóknak C-t kell tanulniuk és az alapoktól (CPU) indulva felfelé építkezni. Személy szerint igen botrányosnak találom, hogy nagyon sok informatikai oktatás a Java-t első nyelvként tanítja, mivel “könnyű” és nem kell mindféle zavaró és unalmas malloc-string dolgokkal foglakozni, hanem rögtön az Objektum Orientált programozást mutatja be, amivel minden eddiginél modulárisabb programok írását teszi lehetővé. Ez az oktatás csődje katsztrófa ami nemsokára bekövetkezik. Frissen végzett generációk jönnek, akik jobbra és balra is “Schemiel Festő algoritmus”-t implementálják, azért mert alapvetően nincsen fogalmuk arról, hogy milyen is például egy sztring megvalósítása a legalacsonyabb szinten. Ha valakit jól meg akarsz tanítani valamire a legegyszerűbb dolgoknál kell kezdeni. Mint a Karate Kölyökben. Wax On, Wax Off. Wax On, Wax Off. Csináld ezt három hétig, kiütni egy másik kölyköt ezután már gyerekjáték.
Köszönöm a hasznos olvasnivalót!
Azt egy életre megtanultam, hogy const * char a paramétere az atoi-nak. És azt is, hogy a konstans karakter változó, vagy konstans karaktertömb változó létrehozásakor a nullás terminátor automatikusan a végéhez íródik, ezért nem ellenőriz az atoi és ezért bízik abban, hogy addig kell mennie, amíg nullás terminátort nem talál.
Azt az egyet viszont nem tudom, hogy miért pont Scheimel és miért nem Smith?
--
unix -- több, mint kód. filozófia.
Life is feudal
const * char
const char* :)
És azt is, hogy a konstans karakter változó
Konstans valtozo eleg keves van. :)
nullás terminátor automatikusan a végéhez íródik
Csak ha konstansrol van szo, ha valtozo, akkor neked kell gondoskodnod a vegen a \0-rol.
Pl.
- atoi("23"); - itt valoban a compiler hozzacsapja.
- char tmp[512]; read(fd, tmp, 10); atoi(tmp); - ez mar fals erteket fog adni, ha nem teszed oda a tmp[10]=0;-t. (Felteve, hogy a szam amit beolvasol 10 karakter hosszu. A pelda itt santit kicsit.)
---
pontscho / fresh!mindworkz
Ööööö... Valóban. Köszönöm!
--
unix -- több, mint kód. filozófia.
Life is feudal
'0'::48d::0x30::O60
'1'::49d::0x31::O61
...
'9'::57d::0x39::O71
mellé ment 10 helyjel az én tippem...
--
unix -- több, mint kód. filozófia.
Life is feudal
ez azert fajt ...
Miért? 48 - 38 nem 10?
--
unix -- több, mint kód. filozófia.
Life is feudal
off
hellyel, ld. teljes hasonulás írásban jelölt esete.
/off
:D
Ja,ja,ja 0 . 1 meg az atvitel?
---------------------------
Az információ egysége a bit, nagyobb egysége a megabit, kisebb egysége a mikrobit.
Itt azt hiszem, hogy meg kell világítsak pár dolgot. Kezdjük azzal, hogy minden ami a gépen van az számként tárolódik, a különbség annyi, hogy mi megmondjuk, pl. char c-t karakterként kezeljük. Ezért kiíratásnál az érték helyett a karakter íródik ki. Nem próbáltam de szerintem csak ASCII karakterkódolás estén működik. És a legnagyobb hátránya, hogy akármilyen karakter van az s[3] helyén mindenképpen számot fogsz kapni, tehát az ilyen hibát soha nem fogod észre venni.
Szerintem egy sokkal elegánsabb megoldás:
--
A lehetetlen csak a lusta ember kifogása!
Ez így egyszerűen rossz. :)
Kezdjük az elején:
"Nem próbáltam de szerintem csak ASCII karakterkódolás estén működik."
Mindenhol működik, ahol a szám karakterek egymás után növekvő sorban helyezkednek el.
Ilyen az ASCII, illetve minden ASCII leszármazott 8-bites kódolások (latin-1, stb.), illetve az egyéb 8 bites kódolások (UTF-8, EBCDIC).
Ennél egzotikusabbal nem valószínű hogy találkozhatsz.
A string::operator[] char-t ad vissza, tehát az égvilágon semmi típuskényszerítés nincs, itt teljesen jó a:
A te verziód csúnyább, és lassabb is...
Ez szintén rossz:
Miért? Mert az atoi c-stílusú stringet vár, te viszont egy char címét adod vissza, ami mögött maximum csak véletlenül van lezáró 0...
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o
char c;
i=atoi(&c);
Ebben az a fasza, hogy gyonyoruen kepes fals erteket adni. Mivel te a c cimet adod at, amit az atoi stringnek vesz. Mindossze csak azert mukodott, mert a stack-en veletlenul nulla volt a c utan.
Ebbol lesz aztan kesobb a BoF, etc. Buktattam meg embert anno vizsgan ilyen huzasokert. (Amugy mint mindenki, en is kovettem mar el ilyen hibat.:)
---
pontscho / fresh!mindworkz
Engem nem tudnál megbuktatni, mert nem járok iskolába (sajnos!). :D
De köszi a segítséget!
--
unix -- több, mint kód. filozófia.
Life is feudal
Nem az iskola tanit meg a helyes programozasra, hanem a jozan paraszti esz es a tapasztalat. Ezek kozul egyik sem tanulhato meg normalisan a fentebb emlitett intezmenyben.
---
pontscho / fresh!mindworkz
józan parasztul gondolkodni csak pontos információk alapján lehet. Egy függvény belső működése nem tippelhető meg józan paraszti ésszel. A függvény olyan, amilyenre kialakítják. Embertől függ. Az iskola pont az a hely, ahol elmesélhetnek olyan apróságokat, amin nagyot lehet hasalni kódolás közben. Ezek nagy része könyvben nincs benne. Maarad a fórum és a kérdezősködés.
--
unix -- több, mint kód. filozófia.
Life is feudal
józan parasztul gondolkodni csak pontos információk alapján lehet. Egy függvény belső működése nem tippelhető meg józan paraszti ésszel.
Nem egeszen. Mivel el lehet kepzelni, hogy ha te csinalnad hogyan mukodne. Max. nem ugy van a valosagban. Masreszt a fuggveny definiciobol mar eleg jo aranyban lehet ki lehet talalni, hogy mi a feladata es mit muvel a hatterben.
Az iskola pont az a hely, ahol elmesélhetnek olyan apróságokat, amin nagyot lehet hasalni kódolás közben. Ezek nagy része könyvben nincs benne.
Ha szerencsed van. Az viszont garantalhato, hogy az esetek nagy reszeben ez nem igy mukodik. Masreszt ami az eloadason az egyik fuleden bemegy, az a masikon kifog. Ha nem kepzed magad (es nem ok teged! fontos kulonbseg), akkor az egesz iskola lofaszt se er. Plane az atlag 10 evvel elavult tudas a vicces, amit sok felsooktatasi intezmenyben nyomnak.
---
pontscho / fresh!mindworkz
"Ha nem kepzed magad (es nem ok teged! fontos kulonbseg)"
Ez jó gondolat. Köszi!
--
unix -- több, mint kód. filozófia.
Life is feudal
Az jutott még eszembe ezzel kapcsolatban, hogy miért számít, hogy nulla értékű-e a következő byte? a char * cp nem azt jelenti, hogy olyan mutató, ami karakter tárolására alkalmas méretű memóriaterületre mutat? Azaz a mérete adott, nem? nem fog addig haladni a memóriában, amíg nullás byteot nem talál.
--
unix -- több, mint kód. filozófia.
Life is feudal
De az atoi valoszinu, hogy fog tovabb is olvasni. Addig olvasa karaktereket folyamatosan amig elkepzelheto, hogy a kov karakter egy int szam resze.
Es a legtobb char* kapo fuggveny addog olvassa a karaktereket megatott char* kezdo pontol amig \0 -t nem talal.
char* valoban egy karakterre mutat, C -stringeknel csak a kezdo karakter cimet adjuk at, es addig tart a string amig \0 -val le nem zarodik.
"" -kozotti szoveg vegere automatikusan bekerul '\0' . ' ' kozottihez nem.
Értem. Köszönöm!
--
unix -- több, mint kód. filozófia.
Life is feudal
"De az atoi valoszinu, hogy fog tovabb is olvasni. Addig olvasa karaktereket folyamatosan amig elkepzelheto, hogy a kov karakter egy int szam resze."
Ez attól függ mit kap paraméterként.
Az atoi definíciója: int atoi( const char *str ); Ami azt jelenti, hogy amit vár az egy karakterre mutató mutatót, ami egy (kezdő)karakter címét tartalmazza, ezért tudjuk átadni neki egy karakter címét is. Így ezt már megtehetjük kétféle módon:
Ami fontos a kettő közti különbség, nem mindegy, hogy mutatóról van szó, vagy egy memória terület címéről, még ha nagyon hasonló is a kettő. Ha valaki viszont normális eszközökkel el tudja érni a char c következő "karakterét" az számoljon be róla, mert nagyon kíváncsi lennék, a hogyanra.
megj.: És mindezt C++-ra vállalom felelősségteljesen.
--
A lehetetlen csak a lusta ember kifogása!
OMG, ez az egész bullshit.
Vannak itt tudásbeli hiányosságok...
vagy
tetszés szerint.
Egyebet nem akarok mondani. Kérem kapcsolja ki.
nekem ez a jelölés a kedvencem:
int main()
{
char c0='A';
char c1='B';
std::cout << 1[&c0] << std::endl;
}
g++ v4.1.2 Verzióval fordítva, ha a c így lett deklarálva: char c; Akkor mindegyik esetben error-t ad fordításkor: "error: invalid conversion from ‘char’ to ‘const char*’"
Lehet, hogy nem fogalmaztam túlságosan pontosan, de ha nincs igazam, azt elismerem, amit meg is fogok tenni ha mutatsz olyan esetet amikor a char c='3'; atoi(&c) nem hármat ad eredményül.
--
A lehetetlen csak a lusta ember kifogása!
ez jo ? (32-t ad)
Rendben van beismerem bűnösségem, teljes mértékig megkövezhettek.
Nem tudom hogyan, de az évek során még soha nem futottam bele ebbe a hibába. Szóval akkor mi a megoldás arra, ha egy karakter szám értékét akarjuk kapni?
--
A lehetetlen csak a lusta ember kifogása!
Ma hasznalt kodlapoknal a fenti megoldas jo.
c-'0'
Ha ragszkodsz az atoi -hez akkor:
char work[2]=" "; // work[1]==0 lesz, nem piszkaljuk.
work[0]=c;
atoi(work);
Az ilyen aprosagok szoktak a daily WTF oldalan elsokent megjelenni.
1. Az egesz sztorit ott kurtad el, hogy a char*-nal egy string kezdo cimet varja az atoi, nem egy karakter cimet. Es igen, az atoi addig fogja azt a szerencsetlen string-et beolvasni, amig egy \0-t nem talal, es nem egy egesz byte-ot dolgoz fel.
2. char c következő "karakterét" az számoljon be róla, mert nagyon kíváncsi lennék, a hogyanra.
Szepen: mc = &c; mc[1]...
Mukodokepesen: *(&c + 1)
A miertekre a valaszt megtalalod a 'C for dummies' kotetben.
---
pontscho / fresh!mindworkz
Ez nem igaz! Ugyanis char c egy karakter tárolására alkalmas, &c egy karakter tárolására alkalmas memóriaterület címe, és nem nagyobb. Tehát semmi nem nézi még át utána a 2 GB memóriát, míg nem talál egy lezáró karaktert. (char*-ra igaz lenne, de itt nem az szerepelt).
--
A lehetetlen csak a lusta ember kifogása!
rosszul tudod. ld: http://en.wikipedia.org/wiki/Stack_buffer_overflow
Szerintem a kettő teljesen különböző dolog.
--
A lehetetlen csak a lusta ember kifogása!
De azt gondolom tudod, hogy ha egy C stringet váró függvénynek &c -t adsz, akkor olyan helyről fog olvasni, ahonnan nem kéne:
int main()
{
char c='A';
printf(&c);
}
Nem az. Nem veletlen tiltja minden normalisabb coding policy az strcpy(), sprintf(), stb hasznalatat, mivel kurvara nem foglalkoznak az array bounding-gal. Ugy tovabb irja, mint a huzat a tombot es jon az alomszep BOF. Effektive ha a string a stack-en van, akkor ott.
---
pontscho / fresh!mindworkz
cc kiterjesztessel g++ forgatva is ezt adja.
Te szerencsetlen, mielott osztod az eszet nezz mar utana annak amirol magyarazol ha mar fingod sincs rola.
strcpy() libc-bol. Latsz itt valahol meret limitet? Igenis vegig fogja nyalni azt a (max. cim - string base pointer)-nyi teruletet szo nelkul. Ha 2GB atnyalasa utan talalja meg a \0-t, akkor ott fogja.
---
pontscho / fresh!mindworkz
Most megkovezed :), Mar lezart ugy.
Hat erre mondjak, hogy ijb. Az altalad linkelteket mar csak kesobb olvastam. :) Nehezen viselem, ha valaki olyan dologrol osztja az eszet nagy mellennyel amirol nyilvanvaloan fogalma sincs.
---
pontscho / fresh!mindworkz
Teljesen igazad van. Akármit kapok ebben a témában, azt megérdemlem. Ezt nagyon elb*am, akarom mondani nagyon benéztem. Nem akarom védeni magam, de két óriási tanulsággal szolgált ez az eset a számomra:
- soha ne állíts olyat, amit 3x át nem rágtál, és utána nem néztél, főleg ne rutinból
- ennyi tapasztalat után ekkora lámaságot elkövetni, ezért vezekelnem kell, ezért elő is vettem azt a bizonyos 2000 oldalas C++ könyvet
Félreértés ne essék, nem védeni akarom magamat, de ilyen hibát nekem semmilyen körülmények között nem szabadott volna elkövetni, és ez miatt most nagyon szarul érzem magam, ráadásul visszagondolva még én is érzem mennyire nem gondolkodtam.
--
A lehetetlen csak a lusta ember kifogása!
:)
ráadásul visszagondolva még én is érzem mennyire nem gondolkodtam.
Ez a lenyeg.
---
pontscho / fresh!mindworkz
Az en glibc ez nem igy nez ki. De ugyan ezt csinalja (2.7).
Melleseleg egy assembly kodot hasznal, ami sokkal bonyolultabb (x86_64), de ami nem vilagos, hogy miert nem hasznl benne cmovcc utasitasokat.
Vagy a cmovcc -vel roszabb lenne ?
A dolog inkabb ket okbol vicces:
- az x86_64 arch.-ok mar javareszt tudnak SIMD-ul, es cache buzeralasul. Ezekkel viccesebben meg lehet irni jobbra.
- rep movs a CPU-ban pontosan string masolasra szolgal.
Nem tudom milyen kodot lattal, es hogy a cmovcc-nek milyen cache/etc beli vonatkozasa van, egy ideje nem nagyon foglalkoztam a "modern" cpu-k asm szintu programozasaval. De azt sem tartom kizartnak, hogy a tisztelt "coder"-nek eszebe sem jutott cmovcc lete. Anno glibc-ben/apple corefoundation-ban/etc-ben is talaltam jo par WTF-et.
---
pontscho / fresh!mindworkz
rep prefixet altalban nem ajanljak, pedig az en gyik proceszoromon jobbank tunt (fix hoszakra) rep movsq mint 4 mov egy ciklusban, bar mereskor ugyanazt masoltam ugyan oda, tehet cache misseim nem igen voltak, de masodik legjobb volt csak a 4 mov (probaltam parat). optimalicacios javaslatok, talan ez en esetemben is 4 -es movost ajanlottak.
Ez van leforgatva:
Jeeezus. Ez ilyen: "anyuuuu... bonyolultabban nem lehet?". :) Legviccesebb resze az, hogy beolvas egyszerre 64 bitet, majd vegig buzeralja a regisztert, hogy az egyik resze nem nulla-e.
Ha az egyszeruseg a cel, akkor a rep movs verhetetlen. Ha a sebesseg, akkor a pipeline optimalizacio miatt jobb a 4 mov. Mivel altalaban - mar a Cyrix 6x86 ota - az x86 vonal kepes egyreszt "kiugratni" a pipeline-bol a vegrehajtast nem akadalyozo utasitasokat masik pipe-ra, illetve az egymas utan kovetkezo, precedencia problemat nem okozo utasitasokat egymas mellett vegrehajtani.
---
pontscho / fresh!mindworkz
Ez tényleg perverz, de nem hülyeség amit csinál... Beolvas 64 bitet, és azt buzerálja, viszont ezt mind regiszterekkel, ami majdnem ingyen van, hiszen a következő 64 bitre úgyis várni kell. Nekem tetszik. :)
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o
Ja, ha kisebb egysegeket hasznalna az is problema lehet, hogy nem tudna olyan jol parhuzamositani a CPU mivel ugyan azon a 8 byten belul cimezne.
Mintha olyat is olvastam volna, hogy az inc az gonosz es add 1 jobb sok esetben.
Erdekes lenne versenyeztetni kodokat a problemara, (hossz szerint, cache legyilkolassal es nelkule, grafikonokat krealni.. )
Prefetch -dologal gond lehet, ha string utanni terulet nem a mienk.Es ugye elore nem tudjuk meddig tart.
Tudom, utána kéne olvasnom, de most így hirtelen nem találtam többet ennél:
std::string s;
cin>>s;
s.size();
s.length();
mondja meg az s hosszát. De azt nem tudtam meg, hogy ezek a függvények belülről hogyan néznek ki és honnan/hogyan állapítják meg a string hosszát?
Elnézést, hogy ezzel hozakodok elő, de tényleg érdekel és nyilván unalmas és túl
egyszerű kérdés. Nézzétek el nekem, hogy ezzel zaklatom a társaságot!
Szeretném ezt megtudni.
Köszönöm!
--
unix -- több, mint kód. filozófia.
Life is feudal
1. Semmi közöd hozzá! :)
2. Implementációfüggő.
3. itt
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o