Szeretnék írni egy programot, ami beolvas egy fájlból sok lebegőpontos számot, majd ezekkel különböző műveleteket végez. Az a része működik, hogy beolvassa a szövegfájlt, átalakítja double-é a számokat, megszámolja hány sor és oszlop. Ezután jön, ami számomra problémát jelent: a double számokat egyenként bepakolni egy tömbbe. Mivel nem tudni mennyi lehet belőlük, a tömbnek mindig dinamikusan szeretnék memóriát allokálni.Nagyon kezdő vagyok C-ben, így írtam egy kis modell programot, ami csak ezt a rész megvalósítja:
#include <stdio.h>
#include <stdlib.h>
void main()
{
double* p_vector;
p_vector = ( double* ) malloc( sizeof( double ) );
const double inc = 5.63451;
int i;
// write 5 doubles into array
for( i = 0; i < 5; i++ )
{
( *( p_vector + ( ( i + 1 ) * sizeof( double ) ) ) ) = ( i * inc);
p_vector = realloc( p_vector, ( ( i + 2 ) * sizeof( double ) ) );
}
// print the elements of the array
for( i = 0; i < 5; i++ )
{
printf( "%f\n", *( p_vector + ( ( i + 1 ) * sizeof( double ) ) ) );
}
}
Az első for ciklus 5-ször ír be egy-egy számot a tömbbe, és mindannyiszor realloc() segítségével egy double mérettel megnöveli a méretét. Ez tökéletesen működött, így azt hittem meg van oldva a kérdés.
Ekkor nekiláttam az igazi programban megvalósítani ugyanezt.
A main() meghívja a read_file() függvényt, aminek átad egy double pointert:
double* p_vector;
p_vector = (double *) malloc( sizeof( double ) );
read_file( ..., &p_vector);
A read_file() meghívja a process_line( ..., double** p_vector ) függvényt, ami beolvas számokat a fájlból, és minden beolvasott szám után meghívja a build_vector( ..., double** p_vector ) függvényt, melynek a feladata az újabb számot hozzáilleszteni a tömbhöz, és egy double méretével nagyobb memóriát allokálni:
void build_vector( double next_num, double** p_vector, unsigned int* rows, unsigned int* this_row_elements, unsigned int* first_row )
{
*( *p_vector + ( ( *rows -1 ) * *first_row * sizeof( double ) ) + ( ( *this_row_elements - 1 ) * sizeof( double ) ) ) = next_num;
*p_vector = realloc( *p_vector, ( ( *rows - 1 ) * *first_row * sizeof( double ) ) + ( ( *this_row_elements + 1 ) * sizeof( double ) ) );
}
A rows, first_row, this_row_elements az eddig beolvasott sorok száma, az egy sorban szereplő elemek száma, és az aktuális sorból eddig beolvasott elemek száma. Ebből tudjuk kiszámítani, eddig hány eleme van a tömbnek. A next_num számot kell éppen beírni a tömb legutolsó helyére. A végeredmény: a tömb első helyén szerepel a legelső szám, a többi helyen nullák. Ha beírok két printf() függvényt a build_vector()-ba, hogy kiderítsem mi is történik, látható, hogy a realloc() nem törődik a további beírt számokkal, csak az első számot másolja át az új memóriaterület elejére, a többi pedig nulla lesz. A realloc() meghívása előtt a beírt szám a helyén van, utána pedig nullává változik:
printf( "before realloc: %f\n", *( *p_vector + ( ( *rows -1 ) * *first_row* sizeof( double ) ) + ( ( *this_row_elements - 1 ) * sizeof( double ) ) ) );
*p_vector = realloc( *p_vector, ( ( *rows - 1 ) * *first_row * sizeof( double ) ) + ( ( *this_row_elements + 1 ) * sizeof( double ) ) );
printf( "after realloc: %f\n", *( *p_vector + ( ( *rows -1 ) * *first_row * sizeof( double ) ) + ( ( *this_row_elements - 1 ) * sizeof( double ) ) ) );
és a kimenet:
before realloc: 323.300000
after realloc: 0.000000
A kérdés tehát úgy hangzik, hogyan kell korrektül felépíteni egy double tömböt, dinamikus memóriakezeléssel? Itt miért sikerül neki, amikor kb. ugyanúgy használja a realloc()-ot? (Lehet, hogy a válasz nagyon triviális, de nemrég kezdtem el tanulni a C-t.)
Hozzászólások
Én valahogy így csinálnám...
nem pöcsölnék a realloc-kal, hanem egyben lefoglalnék, mondjuk 100/500/1000 * sizeof(double), plusz 2 pointer-nyi és egy számlálónyi (uint/ulong) területet.
Két pointer a (lefoglalt blokk) láncoláshoz kell, a számláló meg megmondja, hogy a lefoglalt blokkban mennyi az érvényes elemek száma. Ha betelik, foglalsz új blokkot.
Az összes elem számát így csak úgy tudod meg, ha megszámlálod az összes blokkot. N-1 ugye "tele van", az utolsóban pedig ott a számláló értéke. (Bár a többiben is van számláló, de azok értéke triviális.)
Esetleg egy külön változóban számlálod a blokkokat, vagy blokkonként nem használsz számlálót, hanem globálisan számlálod az elemeket és egy sima maradék képzéssel megtudod, hogy az utolsóban mennyi szabad hely van. Vagy a blokkokban még egy blokkindexet is elhelyezel... Ez már csak cifrázás.
Arról nem írtál, hogy mit kell ezzel a tömbbel csinálni az insert-en kívül. Delete, sort, find, change... ?
Ha ezt a kérdést tegnap 18h előtt teszed fel, tudtam volna konkrétumokkal segíteni :D
Dinamikus tömb foglalása esetén csak TE tudod mekkora a tömb (illetve ha kiolvasod a foglalás méretét a heap allokátor táblázatából:)
Van egy ökölszabály jellegű megoldás, hogy ha növelni kell a tömb méretét, mindig duplázol. Persze tárolod a tömb méretét és az utolsó elem indexét is. Ekkor csak log n lesz a foglalások időigénye.
Amúgymeg:
Try, modify.
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
A size kezdeti értéke inkább "1" legyen.
-----
"Én vagyok a hülye, hogy leállok magával vitatkozni."
hopp, jogos:)
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
Egy kisebb kiegészítés ehhez. A realloc akkor ad vissza érvényes pointert, ha sikerül az adott, összefüggő memóriaterületet befoglalnia. Ritkán, de előfordulhat, hogy NULL-al tér vissza, így arra is vizsgálni kell. Ekkor a kétszeres növelés helyett meg kell próbálni a másfélszeres növelést, stb. Illetve megoldás lehet az első hozzászólásban, hogy láncolt tömbökbe helyezzük el az adatot.
Természetesen ezek (a NULL return érték ellenőrzésének kivételével) mindig feladat és futtatási környezet függő döntések kell hogy legyenek.
az már az ő dolga.
ha mindenki csak teljesen helyes kodot posztolna, minden hsz 2 oldal lenne.
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
Jaj, nem Téged akartalak piszkálni ...
amúgy jogos amit írtál, csak ha minden beleveszek, akkor effektíve megoldom a problémáját, és nem tanul semmit a folyamatból.
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
Igen, ezt már tudom, a végleges változatban úgy lesz. A fentebbi kódot kipróbálom, bár nem értem miért más, ha duplázom a tömb méretét, mintha egy egységgel növelem meg. Az eddigi tapasztalataim alapján, az eredmény az lesz, hogy lesz egy kétszer akkora tömböm, aminek az első helyén lesz az első szám, a többi meg nulla. De majd ma délután meglátjuk :)
A sizeof(double)-t is transzformáld ki (fene tudja, hogy a fordítód optimalizál-e rá), mert felesleges ennyiszer meghívni, elég egyszer is. Nagyon valószinű, hogy az OS-t és a hardvert nem cseréled ki alatta futásidőben ...
A sizeof(double) nyugodtan maradhat a helyén, ez fordítási időben konstanssá alakul normális fordító esetén, ha az optimalizálás engedélyezett. Ha gyors programot akarsz, akkor kapcsold be az optimalizálást, és ne foglalkozz vele, hányszor fut rá a sizeof(double)-re.
Ezért mondtam, hogy a fene tudja, hogy optimalizálja-e a fordítója.
Ettől függetlenül nem tartom rossz programozási gyakorlatnak, ha az optimalizációtól függetlenül ilyen esetekben a forráskódban is végrehajtódik az egyszerűsítés. Ugyanis pl ha a kódot át kell alakítani, akkor a transzformált esetben elegendő egy helyen módosítani, míg úgyhagyva nő az esélye a hibának.
Ne árts félre, szeretem az optimalizációt, ettől függetlenül szvsz törekedni kell arra, hogy a lehető legkevesebb ismétlődő kód legyen.
Minden esetben konstans lesz a vegeredmeny. A struktura valos meretetol es az optimalizaciotol fugg az, h ez az ertek mire kerul felhasznalasra. Ha az adathalmaz merete ketto hatvanya, akkor mindenfele cimszamitasnal a cpu egy menetben szamolni kepes az adott elem helyet. Ha nem, akkor egy-ket plusz utasitassal buveszkedik egy sort, de semmikep nincs szukseg kezi kioptimalizalasara, ugyanis azzal a compiler optimalizaciojat kurod el de nem kicsit.
---
pontscho / fresh!mindworkz
A sizeof(double)-t is transzformáld ki (fene tudja, hogy a fordítód optimalizál-e rá), mert felesleges ennyiszer meghívni, elég egyszer is.
OMG LOL
?
Lecci lecci Gabucinot es drastikot vissza, inkabb mint ezt :-) Pl ha osszejon 5db +1 ide (a -1-tol fuggetlenul, ahogy korabban volt) ;))
Tipp: portable code?
--
Debian - The "What?!" starts not!
http://nyizsa.uni.cc
Szvsz arra gondolt, hogy
size_t sizeofdouble = sizeof(double);
...
malloc(sizeofdouble)
Es minek? A sizeof nyelvi elem, tippre meg -O0 -nal is kioptimalizaltatik.
--
mivel nyelvi elem, tipped helyes :)
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
Ne engem kérdezz :)
kepzeld magad a fordito helyebe, vajh milyen kod kerulhet a sizeof(double) moge? te mit forditanal bele, ha te (a fordito) az egyetlen akinek egyaltalan tudomasa van arrol mi az a double..
Linkelnem a libgcc-hez! :-)
--
nem linker, fordito :)
Ehhez csak annyit, hogy látszik a szemléletbeli hiba. Azt írod, felesleges ennyiszer meghívni, ezzel az a gond, hogy a sizeof operátor és nem függvény, meghívni pedig függvényt és vendégeket szokás. Valami vérgagyi fordítón lehet belőle kód konstans helyett, de ugyan ne az egyetemi egy féléves projektként készülő C-fordítókra alapozzunk.
A Csabos szál alant pedig fenomenális. Ekkora hülyeségeket még én sem beszéltem a Javaval kapcsolatban. Abban egyébként igaza van, hogy az emberbarátabb nyelveken felnőttek könnyebben fognak szép C kódot írni, mint a C-hekkeléssel gyerekkoruktól foglalkozók, de hogy pont a Javat hozza mint jó szokásokra szoktató nyelvet... jézusom.
----
Hülye pelikán
Valami vérgagyi fordítón lehet belőle kód konstans helyett
Sehol sem lehet. ISO C99 "6.5.3.4 The sizeof operator":
Egy példa az "integer constant"-ra:
.
Gyakorlati oldalról megközelítve: ha a sizeof nem értékelődne ki fordítási időben (VLA-kat most félretéve), akkor lehetetlen volna használni például struct-ok és egyéb típusok definíciójában.
Most ezzel magad ellen beszéltél. Pont a hülye c99-es variable lenght arrayek miatt hezitáltam, mert amúgy minden másnak előre ismert mérete van fordítási időben. De egy ilyen változó hosszúságú tömbhöz kód kell, nem lesz belőle konstans, nem is lehet.
----
Hülye pelikán
szerintem a kitranszformálást alatt arra ogndolhatott, hogy a double-t makrózza, nem az egész sizeofos dolgot.
Arra tudok gondolni, hogy #define MAINARRAYTYPE double [blablabla] sizeof(MAINARRAYTYPE), így simán átállhat double-ról long double-re pl. azt hiszem.
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
Te szerintem a typedefet akarod újra feltalálni?
----
Hülye pelikán
nem én, csak elkezdtem értelmezni a kollega hozzászólásait megint.
Ha typedefelni akart volna, akkor annyit irt volna, hogy "gondolj a jövőre, typedefelj".
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
A kód szép, kezdőknek érthető, mégis azt mondom, hogy ahol lehet a realloc-ot kerülni kell.
Ennek két oka van:
- 17 MB elemed van, akkor 32 MB memóriát foglal le legalább a fenti rutin a duplázás miatt, a másolás sebességéről ne is beszéljünk
- realloc = malloc új + free előző
A hülye C-ben csak pointerezni tudsz, így ha realloc-olsz, máshol meg a pointert már eltároltad, annak fagyás a vége.
C-ben a free + realloc hihetetlen gondos vizsgálatot igényel, hogy valahol máshol a kód nem tart-e referenciát rajta, így minimalizálni kell a memória foglalások és elengedések számát (arról ne is beszéljünk, hogy vannak programok, ahol az idő 90%-át malloc+free-ben tölti, kegyetlen lassú rutinok).
Lentebb a láncolt listát említették, én abban hiszek (most nem egy 5 elemű double-ről van szó, hanem komoly adatmennyiségről).
[egyik munkatársam mondta, aki egyetemi tanár is, hogy a realloc leírása egyenértékű a rossz programszerkezettel. Ha tudod hány elem kell előre lefoglalod, ha nem, akkor meg láncolt lista.]
Sok éves programozói tapasztalatom az, hogy a C-t kellene utoljára hagyni a tanulásban. Sokkal nehezebb rajta programot írni, mint java-ban, C#-ban, C++-ban, vagy mit tudomén hol.
A C rossz szerkezetű nyelv. Nincsenek objektumok és kezdőként hibás gondolkodásmódra szoktat rá (ha java-ban realloc-olgatni kezdesz, kirúg a főnököd fenébe, ROSSZ A SZERKEZET!). Ha egy objektumorientált nyelvet tanulsz meg és utána a C-t szebb és jobb kódot fogsz írni, mint ha eleve C-vel kezdenél.
Ez akkora netto hulyeseg hogy muszaj az utokornak rogziteni.
Hétfő reggel már ne jöjjön be, ROSSZ A SZERKEZET!
A C++, a java, meg a többi nyelv pont azért kellett, mert a C-nek kurva jó a szerkezete és túl egyszerű volt vele programozni. Az okosok kitalálták, hogy ugyan csesszünk már ki magunkkal és programozzunk java-ban.
Észrevették, hogy létező és egyre szélesedő piaci lehetőséget jelent azok tábora, akik nem tudják elolvasni és/vagy értelmezni a *alloc föggvények manját, vagy a többszörös indirekciónál akadnak el. Ezért aztán leprogramozták nekik.
Ez tetszik.:-))) Felhasználhatom?
Még én sem gondolom annyira szögletesen, ahogyan leírtam, de ellenpontnak megteszi - és nem, nem bánom, ha holnap az én fejemhez vágja valaki a neten ellenpontként, amikor az ellenpont ellenpontját írom le. ;)
Ezt évekig fogom idézni :-)
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
Hát ekkora marhaságot még nem olvastam. jól esik vitatkozni veled.
:)
" 17 MB elemed van, akkor 32 MB memóriát foglal le legalább a fenti rutin a duplázás miatt, a másolás sebességéről ne is beszéljünk"
pont ez a lenyege, memoriat aldozunk fel a sebessegert...
"- realloc = malloc új + free előző"
nem feltetlenul, egy okosabb allokator talan megoldja ugyesebben ;)
"A hülye C-ben csak pointerezni tudsz"
ok, igazabol a hozzaszolasod innentol komolytalan.
"Lentebb a láncolt listát említették, én abban hiszek"
ahahaha, ok. lancolt listat mindenre!
majd 10 000 elemnel kulonosen pikans lesz vegigiteralni rajta O(1) helyett
masik pikans dolog, hogy miert eppen nagy adatmennyisegre ajanlod a lancolt listat, amire mar pont inkabb valami fa az ertelmes, de egyszerubb esetekben a tomb (mint pl matrixot mint jelen esetben)
"Sokkal nehezebb rajta programot írni, mint java-ban, C#-ban, C++-ban"
c++-szal vitatkoznek, de amugy ez igy van. a c az egy rendszerprogramozashoz kitalalt nyelv. lehet utalni vagy szeretni, de erre meg mindig a C a legjobb
"A C rossz szerkezetű nyelv."
ellaborate plz
"Nincsenek objektumok"
:-) (megjegyzem ha akarom vannak)
"Ha egy objektumorientált nyelvet tanulsz meg és utána a C-t szebb és jobb kódot fogsz írni, mint ha eleve C-vel kezdenél."
szerintem meg nem azon mulik egyaltalan, es a pusztan OO-n nevelkedett programozokrol most inkabb nem mondok semmit :D
--
NetBSD - Simplicity is prerequisite for reliability
Ehhez meg annyit fuzok hozza hogy:
"A hülye C-ben csak pointerezni tudsz, így ha realloc-olsz, máshol meg a pointert már eltároltad, annak fagyás a vége."
Tisztelt OO kollega meg nem hallott a **-rol, amivel elkerulheto a szegyenletes "fagyas". Remelem hetfon mar nem jon be dolgozni.
A hajam egnek allt a post olvasasa kozben.
Mert a ** az nem pointer, csak jól mutat...
Nem véletlen, hogy nincs java-ban pointer, a C# alapból tiltja, C++-ban meg sokan managed pointert használnak helyette.
Leccine.
A pointereket a java azért tiltotta ki, mert a hibák több mint felét ez okozta. Ha olyan nyelvet készítesz amiben nincsenek, fele annyi bajod lesz.
Ez egy fejlődés eredménye:
- a C++ a destruktorokkal a memory leak-ek és dupla free-k előfordulását jelentősen csökketette
- a Qt túlment ezen, az objektumokat fába rendezte, a szülő szabadítja fel a gyermeket is, bevezette a guarded pointert, ami nullázódik, ha az objektumot felszabadítod. Ezt olyan szintre vitte, hogy ha deletet nyomsz egy objektumra az összes listából hash-ből is törlődik. Ritkán is fagy a Qt...
- a java kompletten kitiltotta őket a rengeteg hibalehetőség miatt
Minél több a pointer, annál több bajod is lesz. Éppen ezért ha a sebesség nem kritikus a C a legrosszabb választás.
Koszonom Captain Obvious, rengeteg ujat mondtal. Kar hogy ennek semmi koze azokhoz a suletlensegekhez, amiket az eredeti postodban osszehordtal. Azota lenyegeben csak terelsz, ugyhogy ezert nem reagaltam erdemben.
Nem győztetek meg az ellenkezőjéről, ezért továbbra is fenntartom.
Ami új volt, hogy a * az pointer, a ** meg referencia.
Van neve a *** meg a ****-nak is?
Az 1d tömb legelső elemét pointer-rel címzem a 2d-t referenciával, a 3d-t nem árultátok el.
[szándékosan csinálom, hogy vedd észre mennyi f@szságot sikerült a C-be belenyomni]
Megtudtam milyen hasznos a realloc, mert az optimizált malloc+memcpy+free könnyebben leírható, meg hogy veri sebességben a láncolt listát is.
Agyzsibbasztó.
Írj ide egy kódrészletet, amiben kiolvasod a láncolt listád 635563424. elemét, aztán megnézzük, mennyire lesz gyors.
PERL-ben a tömb egy hash tábla, láncolt listán+indexen alapul.
Gyors és ha az elemek 99%-át kitörlöd, felszabadítja a helyet.
Természetesen a szabvány C egy nyomott hash táblát nem tartalmaz, de ez ugye már más tészta.
Az áhított kód:
my @array = ('a') x 1000000000;
print $array[635563424];
Rád bízom a C-s megoldást.
:)
Hogyan is sikerült idekavarni a PERL-t? Írd csak meg C-ben.
Meg a hash táblát sem értem, eddig láncolt listáról regéltél, vagy neked a kettő ugyanaz?
Annyira konzisztens vagy, eredetileg nem politikus a foglalkozásod?
Szerintem ne varj tole tul sokat. Mar elverzett a tobbi kritizalt ponton, azokrol most mar melyen hallgat, de ehhez meg gorcsosen ragaszkodik, holott a Perl array speciel nem lancolt listas megoldast alkalmaz, ez kiderul a perlfaqbol (csak a pop es shift O(1), mig a beszuras egyertelmuen nem az), plusz ofkoz Javaban is van reallocos tomb megoldas, annak ellenere hogy szerinte a kod szerzoje jobb ha nem megy mar hetfon dolgozni.
[szerk] Arrol nem beszelve hogy o inkabb mallocot hiv minden egyes elemre, mint _joval_ kevesebbszer reallocot, raadasul mindezt kifejezetten javasolja nagy elemszamra. Elkepzelem a fenti peldaban a 635563424 malloc hivast es az index plusz az index hash overheadjet. Hat igen, meggyozo. *Sohaj*
Sajnos esz nelkul keveri a tombot, lancolt listat es hasht.
Sajnos a hash tábla indexen és láncolt listán alapul.
Nézd csak meg javaban, hogy hogyan implementálják, van next/prev linkje.
Ez már csak így van.
hat van HashSet, ami HashMappel van implementalva, ami viszont egy hash fuggvennyel es tombbel (annyi valoban igaz, hogy az utkezesek lancolt listaval vannak feloldva). melyik javas hashtable-re gondolsz, ami tiszta lancolt listas implementacio lenne?
--
NetBSD - Simplicity is prerequisite for reliability
Eredeti hozzászólás (amiről vitatkozunk):
PERL-ben a tömb egy hash tábla, láncolt listán+indexen alapul.
joh de tomb vs lancolt listaban lancolt lista mellett pont olyan peldat felhozni, hogy hashtable, mikor az pont a tomb O(1) tulajdunsagara epit, eleg nagy hulyeseg.
hastable utkozest lehet eppenseggel tombbel is kezelni, vagy faval, vagy barmi massal, viszont tomb helyett nem alapozhatod semmire, mert akkor nem hashtable lesz ;-)
szoval melyik az a java hashtalb implementacio, ami tomb nelkul mukodik? :-P
--
NetBSD - Simplicity is prerequisite for reliability
Eloszor:
"PERL-ben a tömb egy hash tábla, láncolt listán+indexen alapul."
Aztan:
"Sajnos a hash tábla indexen és láncolt listán alapul."
Neked a leghalvanyabb fogalmad sincs se a Perlrol, se a C-rol, se a programozasrol; vagy direkt adod az ertetlent.
Elmagyaráznád, hogy mi a két mondat között a különbség?
Indexelt rész: egy mezei tömb. A hash code leképződik egy indexre.
Láncolt lista: a mezei tömbben láncolt lista van, ami a torlódásokat kezeli.
Van a hashben indexelt+láncolt rész is, sőt még láncolt+indexelt is van. Mert ugye az ÉS művelet sorrendje mindegy.
Neked a leghalvanyabb fogalmad sincs se a Perlrol, se a C-rol, se a programozasrol; vagy direkt adod az ertetlent.
Úgy látom ezt a stílust szereted: szóval mivel te egy hülye barom állat vagy, lassan elmagyaráztam az idióta fejednek, hogy hogy múködik egy hash tábla. Persze lehet, hogy csak szimplán húzol és nem vagy akkora kókler, amekkorának mutatod magad.
Ha mégsem nem tetszene ez a stílus, természetesen válthatunk. Én nem ragaszkodom hozzá.
A ket mondat kozott az a kulonbseg, hogy a perl array es a perl hash table ket kulon adatstruktura, te megis egykent emlited oket, mar nem eloszor.
Kezdem elveszteni a fonalat. Most kinek mi az allaspontja?
Most akkor valamelyikotok szerint a ** referencia? (magatol max. ket operator egymas melle irva, szemantikajat tekintve viszont pointer egy pointerre - gondolom en)
Kedves Csab. Bevezetokent, ha annyira ruhelled a pointert es a c/c++-t, legyel szives ne hasznalj JVM-et, leven az is abban irodott. Koszonom.
Aki szerint a ** nem pointer C-ben, az inkabb ne ossza az eszt ha nem muszaj. Megsugom, hogy a 2D tombot sem **-al hivatkozod, szerintem teljes felreertesben leledzel hogy mi a ** szerepe es hogy egyaltalan miert emlitettem.
C-ben nincs dinamikus tomb beepitve, igy reallocolt memoria teruletekre szokas tenni. Nem azert, mert a realloc baszott geci gyors, hanem mert mint Replaced mar celzott ra, egyetlen lepesben hozzafersz az N-ik elemhez, ellentetben a lancolt listaval.
A szal pedig innen indult, amikor kijelentetted hogy a vilag fekete es feher: a C szar nyelv, a pointer miatt nem mukodik a realloc (meg mindig konnyezek bazmeg, igazabol halas vagyok ezert a szep szolasert, ki fog kerulni a szegyenfalra), a referencia az uberkiraly es fokeppen hogy minden aminek nem tudod az elemszamat, az lancolt lista kell legyen. Azota konzekvensen tereled altalanos igazsagokkal a szalat, amit egyebkent senki nem tett szova neked. Azt, hogy nem erted, azt leginkabb magadnak koszonheted, a felhozott peldak magukert beszelnek egy C-t ismero embernek.
Olvasd el alább a PERL megoldást. Kurva gyorsan indexel, szúr be és FELSZABADÍT HA MÁR KISEBB KELL...
Nyilván a C-s múltadból következik, hogy úgy gondolod a realloc valamire is megoldás lehet. Megrekedtél ezen a szinten.
Ertem. Perl hash (ami valojaban C hash) vs C array. Meggyoztel. I'm out folks.
Biztosan realloc-kal csinálja. Tényleg agyzsibbasztó, ami itt van. Magam részéről befejeztem.
Ha már ostoba vagy, legalább hatalmas arcod legyen. Pipa.
Kartácsam a zúrban! Kincs, amit itt összehoztál. Ezzel szinte bárkit meg lehet győzni arról, hogy miért nem szabad javával kezdeni a prog oktatását, ha valaha a C is képbe fog kerülni.
A pikans az egeszben az, hogy a perl array pont hogy realloc-kal mukodik, raadasul pont C-ben irodott. Ekkora ertetlenseg lattan elkapott parszor a gondolat hogy csak trollal beszelgetek, de sajnos a vegere be kell latnom, tevedtem.
Azon tul, hogy minden mas alap dolgot ossze vissza kevert, a szomoru az, hogy bevallasa szerint tobb eves programozoi hatterrel rendelkezik. Azert remelem valamit tanult az esetbol.
Hát én Java fejlesztő vagyok, de egyetemi tanulmányaimból felidézve még én is tudom, hogy félrebeszélsz. Nem kellett volna a buli előtt inni, vagy legalábbis nem ide írogatni, ha már ittál...
A perl vm es runtime env c-ben irodott. Az indexeles, az atmeretezes es a felszabaditas is.
Nyilván a C-s múltadból következik, hogy úgy gondolod a realloc valamire is megoldás lehet. Megrekedtél ezen a szinten.
Nyilvan a javas/perles multadbol kovetkezik, h lovesed sincs arrol, h az os hogyan mukodik amin dolgozol, de nem az a baj, h megrekedtel ezen a szinten, hanem az, h konkretan nem is erdekel, h hogyan mukodik. :)
---
pontscho / fresh!mindworkz
"az, h konkretan nem is erdekel, h hogyan mukodik. :)"
Óóó még ez sem lenne baj, ha legalább tudná, mit nem tud. De nem... Osztja az észt...
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o
ne keverd a c-t es a c++-t
nezz utana a pointer aritmetikanak
---
Egy jól megállapított probléma félig megoldott probléma.
- Charles Kettering
Jeeeezusom...
A ** egy pointerre mutato pointer... A *** egy olyan pointer, amely olyan pointerre mutat, amely ugyancsak egy pointer... Es igy tovabb... Spec, ha tobb, valtozo hosszusagu tombot akarsz csinalni es ezeket egy tombben kezelni, akkor jo a **. De ilyen van C# alatt is van (jagged array a neve): Foo[][]; (Ami persze nem osszekeverendo a tobbdimmenzios tombbel, pl. Foo[,])
Referencia tipust idekeverni eleg nagy fassag, foleg, hogy szerintem te a C++ fele referenciakra gondolsz... C-ben "referencia" cimszo alatt max a reference(&)/dereference(*) operator jatszik, de az is csak annyi, hogy megmondja, hogy az adott cimen milyen adat van/adott valtozo memoriacimet adja vissza)
Hashmappet, lancolt listat es tomb kozotti kulonbseget nem tudni -> fail.
----------------
Lvl86 Troll
foleg, hogy c-ben csak pass-by-value van :D
--
NetBSD - Simplicity is prerequisite for reliability
sok jegyzetben ezt nem magyarazzak el normalisan. ha *, akkor az cim szerinti. volt mar ebbol vitam
---
Egy jól megállapított probléma félig megoldott probléma.
- Charles Kettering
pontosabban, ha * az argumentum, akkor egy pointert ad at, de szinten ertek szerint
--
NetBSD - Simplicity is prerequisite for reliability
igen, ezzel tisztaban vagyok, csak sokan masok nem :) (bar nem ez johetett le a hozzaszolasombol)
---
Egy jól megállapított probléma félig megoldott probléma.
- Charles Kettering
Az viszont kényelmes absztrakció, hogy érték szerint átadott argumentum nem változik meg, míg a cím szerint átadott megváltozhat.
--
Debian - The "What?!" starts not!
http://nyizsa.uni.cc
Megtudtam milyen hasznos a realloc, mert az optimizált malloc+memcpy+free könnyebben leírható, meg hogy veri sebességben a láncolt listát is
fyi: realloc normalis operacios rendszereken sokszor az os reszerol megoldhato sima page remappal, csak a legutolso esetben el memcpy-vel. Ez barmelyik lancolt listad kenterbe veri sebessegben.
---
pontscho / fresh!mindworkz
Köszi, ez az első értelmes hozzászólás a témához.
Valóban kipróbáltam és minimális az overheadje.
"Köszi, ez az első értelmes hozzászólás a témához."
Ez azért lehet, mert eddig leginkább te szóltál a témához, sok örömteli percet okozva az olvasóknak.
:)
+1 :) :)
---------------------------------------------------
Talisker Single Malt Scotch Whisky aged 10 years :)
"ez az első értelmes hozzászólás a témához"
Nabazmeg....
+1 ...
Hát asszem ki fogom nyomtatni ezt a topicot én is megőrzés gyanánt. Ennyi nettó hülyeséget ekkora nagy lelkesedéssel nem sok helyen olvasni.
---------------------------------------------------
Talisker Single Malt Scotch Whisky aged 10 years :)
mremap FTW
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
"- a C++ a destruktorokkal a memory leak-ek"
Ha a konstruktor rendben lefutott.
--
unix -- több, mint kód. filozófia.
Life is feudal
"a Qt túlment ezen, az objektumokat fába rendezte, a szülő szabadítja fel a gyermeket is, bevezette a guarded pointert, ami nullázódik, ha az objektumot felszabadítod. Ezt olyan szintre vitte, hogy ha deletet nyomsz egy objektumra az összes listából hash-ből is törlődik."
Csak szólok - ha tényleg érdekelnek a szoftvertervezés "tankönyvi";) alapelvei:
Ha így van, itt megjelenik egy erős és implicit függőség: olyan gyűjtemények belső állapota is erősen módosulhat adott esetben egy elem törlésekor, amiknek létezéséről és/vagy céljairól moduláris tervezés esetén esetleg nem is kell/kéne tudnod...
Talán ezért is terjedt el inkább a Garbage Collectorokkal az a mentalitás, hogy minden objektumnál saját hatáskörében/környezetében explicit módon döntünk arról, hogy valamilyen adatra szüksége van-e vagy sem: azaz amíg van valaki aki hivatkozik rá, addig az adott adat/objektum sosem kerül teljes felszabadításra/törlésre
A QT-nél valóban nem tudod, hogy törléskor mit csinál (egy csomó egyéb objektumot meghívhat és kódot is lefuttathat).
Nem elegáns, de a semminél azért jobb. Mindenesetre a 'delete' kiadása QT alatt nem jellemző. A new sokkal gyakoribb, mint a delete (a gyermekek automatikus törlése miatt).
C++-ban GC implementációt még nem láttam. Nem tudom, hogy hogyan működik, de úgy emlékszem nincs arra lehetőség, hogy meggátold a fejlesztőt, hogy pointer-t készítsen bizonyos objektumokra.
ManagedPointer<Type> ptr = new Type();
List<ManagedPointer<Type> > list = new List<ManagedPointer<Type> > ();
list.add( ptr );
Ez addig tök jó, ameddig valakinek a (Type *)-ozás eszébe nem jut. Mert ha igen, akkor olyan referenciát hozol létre, amiről a Garbage Collector nem fog tudni.
Nem tudom, hogy C++-ban a garbage collector tipikus-e. Nem láttam még ilyen projektet.
> Nem tudom, hogy C++-ban a garbage collector tipikus-e. Nem láttam még ilyen projektet.
Én sem, mindenesetre egy 10mp-es google-zás után ide jutottam, érdemes lenne megnézni:
http://www.hpl.hp.com/personal/Hans_Boehm/gc/
Mozilla, Mono használja.
Erre kíváncsi lennék, hogy hogyan oldják meg:
#include "gc.h"
#include <assert.h>
#include <stdio.h>
int main()
{
int i;
GC_INIT(); /* Optional on Linux/X86; see below. */
for (i = 0; i < 10000000; ++i)
{
int **p = (int **) GC_MALLOC(sizeof(int *));
int *q = (int *) GC_MALLOC_ATOMIC(sizeof(int));
assert(*p == 0);
*p = (int *) GC_REALLOC(q, 2 * sizeof(int));
if (i % 100000 == 0)
printf("Heap size = %d\n", GC_get_heap_size());
}
return 0;
}
Honnan tudja, pl. hogy a *q referencia felszabadult?
Van egy olyan érzésem, hogy fordítási időben csinálnak néhány trükköt.
Nem csinálnak. De a honlapján elég sok és részletes magyarázat és adat van...
Természetesen így vannak környezetből (nem támaszkodhat fordítási és típusinformációkra) fakadó korlátosságai: pl. minden olyan adatot ami létező és a gc által menedzselt adatra mutató pointer bitmintázatával rendelkezik: azt - biztos ami biztos - pointernek tartja, és nem szabadítja fel a hozzá tartozó adatot
Magyarul: időnként végigmegy a stacken és a statikus adatterületen és ellenőrzi, hogy van-e ott objektum referencia.
Hát, érdekes, gondolom az esetek 90%-ában működik, de nekem kicsit brute-force-nak tűnik.
Bármilyen nyelven szénné lehet gányolni a kódot, ha akarod. A Java gc-vel is ki lehet cseszni, ha mondjuk minden valaha létrejött objektumot bepakolsz egy nagy közös gyűjtővektorba. Nem erről van szó. Ha GC-t használsz C++ alatt akkor be kell tartanod a GC játékszabályait, de ez MINDEN szolgáltatásnál így van: le van fektetve, mikor garantál mit. Nem kell ezen ennyit filozofálni.
----
Hülye pelikán
Bazzz de kár hogy csak most ötlött szembe ez a topic. Pisisre röhögtem magam rajta.
"A pointereket a java azért tiltotta ki, mert a hibák több mint felét ez okozta. Ha olyan nyelvet készítesz amiben nincsenek, fele annyi bajod lesz."
Akkor nem a balf@sz programozó okozta? Szegény pointer ... sok van már a számláján :)
:) ez így nagyon kellett már péntekre.
---------------------------------------------------
Talisker Single Malt Scotch Whisky aged 10 years :)
michelle wild sem no, csak jol mutat? :)
---
Egy jól megállapított probléma félig megoldott probléma.
- Charles Kettering
Már nem nő... ;)
Fuuu... Azert nem lenne rossz tudni, hogy mi a kulonbseg a referencia es a pointer kozott. Bar, aki szerint a ** az nem pointer...
----------------
Lvl86 Troll
Mert a ** az nem pointer
De. Az ilyen marhasagok utan jon az, h a goto hasznalata is eretnekseg, majd ennek oromere agyon pakolja a "T." programozo a kodot continue-val, break-kel es return-nel. :)
---
pontscho / fresh!mindworkz
A realloc gyorsaságáról:
átmásol 8 byte-ot, utána 16, 32, 64, ... 16 MB-ot.
Amíg eddig eljutsz 32 megát mozgatsz meg. Próbáld ki, hogy mennyi idő, nem millisec, jobb ha tudod.
nyilvan nem egybajtos kezdoertekkel kezdesz, mikor a page size 4k-nal kezdodik, hanem valami ertelmes merettel ;)
--
NetBSD - Simplicity is prerequisite for reliability
Tételezzük fel, hogy a méretet a realloc()-nál mindig duplázzuk és 1-gyel indítjuk, valamint hogy a realloc()-nak minden egyes alkalommal másolnia kell. A végső méret, amire szükségünk lesz, legyen "K". "K" helyett tekintsük a 2-nek azt az egész kitevőjű hatványát, amely nem kisebb, mint "K". Ez legyen "n".
K <= n = 2^t; t nemnegatív egész
Ebben az esetben a realloc által másolt byte-ok száma:
2^0 + 2^1 + 2^2 + 2^3 + ... + 2^(t-1) = 2^t - 1 = n - 1
Vagyis a másolások összköltsége O(n). A tömb szekvenciális feltöltése szintén O(n), tehát valamilyen konstans szorzóval romlik a teljesítmény.
A másolásra a libc feltehetően valamilyen szétoptimalizált, CPU és méretspecifikus rutint vet be. A feltöltést ezzel szemben jó eséllyel stdio-ból végezzük; a decimális- ill. hexafüzér-számábrázolást lebegőpontosra kell konvertálnunk (akár saját kézzel hívjuk a megfelelő rutint, akár az stdio hívja a kedvünkért).
Ítélet: a realloc() költsége észrevehetetlen lesz.
A másolgatást egy bizonyos méret felett egyébként is nagyon valószínűtlennek tartom. Ha nincs helyben elég nagy lyuk a virtuális címtérben, akkor sem kell feltétlenül a meglévő tömböt (= a kezdeti szakaszt) átmásolni, elég lehet a mögöttes lapokat más virtuális címtől újra-mappelni.
http://www.kernel.org/doc/man-pages/online/pages/man2/mremap.2.html
mremap() uses the Linux page table scheme. mremap() changes the mapping between virtual addresses and memory pages. This can be used to implement a very efficient realloc(3).
+1
---
pontscho / fresh!mindworkz
+1, a legtrógerebb első realloc is előbb kiterjeszti a teruletet, s csak akkor mozgat, ha nem tud tovabb terjeszkedni.
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
realloc(popcorn, sizeof(table))
hat errol lemaradtam :] neztem is hogy egy ilyen relative egyszeru" tema/kerdes miert van ennyiszer fent... nade igen, valoban, vilagklasszis idezetek szu"lettek.
"A C rossz szerkezetű nyelv. Nincsenek objektumok és kezdőként hibás gondolkodásmódra szoktat rá (ha java-ban realloc-olgatni kezdesz, kirúg a főnököd fenébe, ROSSZ A SZERKEZET!). Ha egy objektumorientált nyelvet tanulsz meg és utána a C-t szebb és jobb kódot fogsz írni, mint ha eleve C-vel kezdenél."
Nálam ez a pont nagyon kiütötte a biztosítékot. Ilyet egy normális, tapasztalattal rendelkező programozó nem mondhat.
Minden nyelvnek megvan a helye, ahol a legoptimálisabban lehet használni. Mindnek van erőssége és gyenge pontja. Programozóként tudni kell, hogy az adott feladatot a környezet ismeretében (hw, os, stb) melyik nyelvvel és hogyan lehet megoldani, az adott nyelv mennyire alkalmas rá.
Pl. statikai végestest számításnál vétek OO C++-t használni a modellezés lefuttatásához, mivel az részek közötti iteráció, illetve a részek belső változóinak lekérdezése/frissítése olyan mértékű overhead-et eredményez, ami használhatatlanná teheti az alkalmazást. Ilyenkor lapított adatstruktúrával, vagy uram bocsá asm-mel lehet (ill. SSE, SSE2, shader, GPU, OpenCL) nagyságrendekkel gyorsítani a végrehajtást.
Aki nekem azt mondja, hogy egy adott nyelvnek ROSSZ A SZERKEZET-e, az nem tapasztalt még eleget, nem dolgozott heterogén környezetben, de legfontosabb, hogy hiányzik az alázata a szakma egészének irányába.
Arról írtam, hogy mivel kell kezdeni. C-ben is lehet szép kódot írni, de jobban meg kell küzdeni, mint java alatt
Tapasztalataim szerint egy kezdo (de sok pro is) kepes barmilyen nyelven olyan fos kodot irni, h az ember agya kette all mire rajon, h tulajdonkeppen mire is gondolt a kolto.
---
pontscho / fresh!mindworkz
Kb. ez a helyzet. Persze van úgy, hogy rosszabb: amikor a kód újrafelhasználása abban nyilvánul meg, hogy mivel a javás (mert a java, az modern) IDE frappánsan kezeli a forrásokat és könnyű kopipésztelni, megy a másolás oda-vissza, modernül.
++
tizenxeve ezert hagytam abba a kodolast. de ez a topic megerosit benne, hogy az un. "programozok" kb. 90%-nak azota sincs fogalma rola, mi hogyan mukodik. ( @topiknyito : ne vedd magadra, te még fejlodhetsz :D) )
Lentebb a láncolt listát említették, én abban hiszek (most nem egy 5 elemű double-ről van szó, hanem komoly adatmennyiségről).
A lancolt lista a leglassabb es legserulekenyebb adatstruktura ami letezik.
[egyik munkatársam mondta, aki egyetemi tanár is, hogy a realloc leírása egyenértékű a rossz programszerkezettel. Ha tudod hány elem kell előre lefoglalod, ha nem, akkor meg láncolt lista.]
Remelem a GDF-en oktat. Ugyanis - az adat tipusatol es varhato mennyisegetol fuggoen - vagy hash alapon valamilyen tree-t hasznal az ember (majd masok kifejtik milyen linearis-nemlinearis kapcsolatok vannak adatszerkezetek kezelesenek sebessegeben, ehhez mar vegkep nincs semmi kedvem), vagy bizony realloc()-kal ujra foglalja az adott tombot. Mert normalis helyeken nem malloc()+memcpy()+free() van, hanem remapping, igy semmilyen koltysege nincs a reallocnak. Ugyanis te - mint programozo - virtualis cimterrel dolgozol, varjunk miota is? 30 eve. Te - mint atlagos programozo - egyetlen egy darab valos cimmel sem talalkozol a munkad soran, az mmu meg hadd dolgozzon, azert van.
Amugy fyi: c-vel ellentetben a managelt nyelveken egy array/vector/matrix/akarmicsoda atmeretezese a realloc()-kal ellentetben a te analogiaddal elve malloc()+memcpy()+free() triobol all. :)
---
pontscho / fresh!mindworkz
Na ez az. (Néha nem árt belebnézni mi fordul a kódodból.)
> Sol omnibus lucet.
Viszont ahhoz meg mar nem art ne'mi architekturalis ismeret...
----------------
Lvl86 Troll
Szerintem kezdjen mindenki assembly-vel, ahogy én is tettem anno a C64-es korszakban és azután már minden nyelv könnyü és egyértelmű lesz. :)
Hááát.
MOS6510-et valamennyire ismertem, de hogy most nem kezdenék assembly-vel az is biztos. Mármint x86-on.
Osztom :)
Úgy gondolom, ha valaki megtanul asm-ben gondolkodni és rájön hogy egy szorzást megírni mennyivel egyszerűbb a felsőbb nyelveken, akkor azonnal érezni fogja a luxust amelyet akár egy C nyelv is felkínál és eszébe se fog jutni hogy panaszkodjon.
Meg esetleg latni, hogy honnan hova fejlodott a technika, es akkor talan nem nyaladzana mindenki mindenfele uj agyonhypeolt technologian, hanem tisztan latna, hogy miben mi a valodi ujitas es mi az, ami igazabol a regebbi nyelvekben mar egy az egyben megovolt.
Ezt foleg nehany C#-n nevelkedett ismeroson veszem eszre, hogy ugy szoljak le a Delphit, hogy igazabol szerintem egy sort nem kodoltak benne, max meg kozepsuliban TurboPascal-ban. Persze, ott se olyan melysegig, hogy kijojjon, hogy mi volt jo abban a nyelvben mas nyelvekhez kepest.
Persze, ez nem feltetlen az o hibajuk, hanem az ipar igenye: sok betanitott, billentyuzetet csapkodo majom.
----------------
Lvl86 Troll
var valtozo : procedure ;
az igazi kodteruletre mutato pointer :D)
a nyocbitesek nem tudtak szorozni, csak shiftelgettunk jobbra-balra, de az x86 utasitaskeszletben van MUL/IMUL...
igazi luxus...
Igy van. Jó kis playground volt a c64 64k-ja. Az asm-es programozás legnagyobb előnyének azt tartom, hogy megtanít észben tartani a címeket. Azóta sem nagyon jegyzetelek le semmit, bár csak php-zok mostanság.
Az bizos, hogy aki megemészti az assembly-s jellegű programozás alapjait, azt nem lehet egykönnyen zavarba hozni semmilyen programnyelvel.
man realloc?
csak akkor ad vissza mas pointert ha a jelenlegi helyet nem tudja megtoldani. Az idemutato mutatoidnak meg a tombmutatora kene mutatniuk, nem a tomb tenyleges helyere...
láncolt lista lassú lesz, ha elkezdesz egy naaagy tombon vegigporgetni. Goto: http://lwn.net/Articles/250967/
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
-
Eddig nem gondoltam hogy lehet olyat hogy egy hozzaszolasbol az irasjeleken kivul minden hulyeseg.
"A kód szép, kezdőknek érthető, mégis azt mondom, hogy ahol lehet a realloc-ot kerülni kell."
Igaz.
"Ennek két oka van:
- 17 MB elemed van, akkor 32 MB memóriát foglal le legalább a fenti rutin a duplázás miatt, a másolás sebességéről ne is beszéljünk
- realloc = malloc új + free előző"
Mas oka is van. Nem biztos, hogy realloc = malloc uj, de nem lehet kizarni. Osszessegeben igaz.
"A hülye C-ben csak pointerezni tudsz, így ha realloc-olsz, máshol meg a pointert már eltároltad, annak fagyás a vége.
C-ben a free + realloc hihetetlen gondos vizsgálatot igényel, hogy valahol máshol a kód nem tart-e referenciát rajta, így minimalizálni kell a memória foglalások és elengedések számát (arról ne is beszéljünk, hogy vannak programok, ahol az idő 90%-át malloc+free-ben tölti, kegyetlen lassú rutinok)."
A sok hulye nem vette eszre, hogy mire gondol Csab:
char* ptr = malloc(..);
char * ptr_ref = ptr;
...
ptr = realloc(...);
itt ptr_ref nem lesz valid. Erre gondolt, es ez igaz.
Sok szar program tenyleg malloc-ban tolti az idejet.
"Lentebb a láncolt listát említették, én abban hiszek (most nem egy 5 elemű double-ről van szó, hanem komoly adatmennyiségről)."
Problemafuggo. A lancolt lista lehet jo, lehet rossz.
"[egyik munkatársam mondta, aki egyetemi tanár is, hogy a realloc leírása egyenértékű a rossz programszerkezettel. Ha tudod hány elem kell előre lefoglalod, ha nem, akkor meg láncolt lista.]"
Ez igy hulyeseg, a lancolt lista legalabb olyan rossz lehet, mint a realloc, igaz neha az a legjobb.
"Sok éves programozói tapasztalatom az, hogy a C-t kellene utoljára hagyni a tanulásban. Sokkal nehezebb rajta programot írni, mint java-ban, C#-ban, C++-ban, vagy mit tudomén hol."
Szerintem meg nem.
"A C rossz szerkezetű nyelv. Nincsenek objektumok és kezdőként hibás gondolkodásmódra szoktat rá (ha java-ban realloc-olgatni kezdesz, kirúg a főnököd fenébe, ROSSZ A SZERKEZET!). Ha egy objektumorientált nyelvet tanulsz meg és utána a C-t szebb és jobb kódot fogsz írni, mint ha eleve C-vel kezdenél."
Ezt hagyjuk. A C nagyon jo, ha arra hasznaljuk, amire valo.
Semmikeppen sem rossz szerkezetu: inkabb egyszeru.
"Semmikeppen sem rossz szerkezetu"
Valaki nem akarja fokozni az elvezeteket azzal, hogy kifejti, hogy egy programnyelv hogy lehet "rossz szerkezetu"?
----------------
Lvl86 Troll
+1
A sok hulye nem vette eszre, hogy mire gondol Csab:
char* ptr = malloc(..);
char * ptr_ref = ptr;
...
ptr = realloc(...);
itt ptr_ref nem lesz valid. Erre gondolt, es ez igaz.
Miert,
eseten valid lesz a ptr_ref? Ez elegge defect by design es nem realloc() problema.
Nem biztos, hogy realloc = malloc uj, de nem lehet kizarni.
Modern operacios rendszereken es hardveren elegge kizarhato.
---
pontscho / fresh!mindworkz
"Ezt hagyjuk. A C nagyon jo, ha arra hasznaljuk, amire valo.
Semmikeppen sem rossz szerkezetu: inkabb egyszeru."
Ez igaz. Ettől függetlenül nem feltétlenül hülyeség, hogy aki előbb egy magasabb szintű nyelvet tanul meg, az valószínűleg szebb C kódot fog írni, de itt olyan sok a kivétel és egyéb körülmény, hogy szabályként nem lehet megfogalmazni. Mindenesetre sokat segít, ha az ember nem szokja meg, hogy alapvető problémákat kell újra és újra megoldani.
----
Hülye pelikán
Kedves Csab, ha ANNYIRA fogalmatlan vagy, mint amilyennek latszol: menjel el kapalni inkabb, legyen beloled utcasepro, esetleg kukas. Neked nem valo a programozas, ugyanis (ha meg nem esett volna le) te vegtelenul ostoba vagy. Egyugyusegeddel ugyan nem lenne semmi bajom, de az, hogy telipofaval ugatod a nagyobbnal nagyobb faszsagokat, elkepeztoen felidegesit. Azokrol, akiktol tanultad a remek TENYEKET hogy a C miert fos, elarulok valamit. Ok legalabb annyira hulyek mint te, ha nem hulyebbek (tanarnak lenni nem mentseg es nem is volt az soha). Eltekintve attol, hogy aki veled szoba all okos ember nem lehet, vegyuk azt az egyszeru peldat, hogy odamesz hasonlo prekoncepciokkal egy C-hez erto emberhez. Valoszinuleg eszrevetted, hogy az objektiven megfogalmazott kerdesedre (jajdefosaCe'jhaszna'jjunkja'va't) merev hallgatas es bologatas a valasz. Ez azert van igy, mert az illeto probalja elkerulni a bunteto torvenykonyv azon bekezdeset, amiben az elore megfontolt gyilkossagot targyaljak. Ha eddig sikerult eletben maradnod (ami a csodaval hataros), ugy kerlek fogd a kezedbe a K&R C konyvet, es addig olvasd amig meg nem erted a pointer-aritmetikat es dupla indirekciot. Amennyiben ebben az idoben nem sikerul ehenhalnod, ugy folytasd ezt a vitat lehetoleg a munkahelyeden (amennyiben IT-s vagy es nem kukaturkasz). Remelhetoleg majd jon egy jobberzesu programozo aki a nyomtatott manpage-et lenyomja a torkodon es bevallalja erted az eletfogytot.
Amennyiben a titulusodban szerepel a head/chief/architect/java/manager, szavak tetszoleges kombinacioja, ugy tekintsd ezt a postot targytalannak, azt hittem emberrol beszelunk.
--------------------------
The OOM killer is like a surgeon that amputates the limb of a man to save his life: losing a limb is not a nice thing, but sometimes there is nothing better to do.
"Understanding the Linux Kernel" on page frame reclaiming
omg, mekkora szal lett :)
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
+1, nem ertik itt miert rohogok
Az direkt fonots, hogy c-ben legyen? Ha nem, akkor irany a c++, ott lenyegesen egyszerubb a tortenet.
Köszi, de egyelőre szeretném rendesen megtanulni a C-t.
Hogy az eredeti kérdésre is szülessen válasz: a realloc során azért csak az első elem másolódik át, mert a p_vector típusa az, hogy double-ra mutató pointer. Azaz double-t tárol. Amikor jön a realloc, akkor csak a típusnak megfelelő méret másolódik át. Bár a nagyesküt nem teszem le, hogy ez az oka, de az esély nagy rá.
Ha ugyanezt void * mutatóval csinálod, akkor ott nincs típus, így a realloc veszi a korábban foglalt terület méretét és annyit másol át. (Nyilván ha csökken a méret, akkor kevesebbet.) Itt persze bónusz feladat lesz az, hogy amikor használni akarod, castolni kell.
Wow, ez érdekes. Kipróbálom a castolást.
Amikor jön a realloc, akkor csak a típusnak megfelelő méret másolódik át. Bár a nagyesküt nem teszem le, hogy ez az oka, de az esély nagy rá.
Ez butaság.
A realloc függvény nem tudja, hogy milyen típusú pointerbe rakod be az általa visszaadott eredményt (ami belőle void *-ként jön ki), valamint nem tudja, hogy milyen típusú pointert adtál át neki (a realloc függvény pointer paramétere void *, a compiler castolni fogja az átadott paramétert). A realloc függvény kap két paraméteret, ezekből tud dolgozni. Az egyik a korábbi foglalás pointere, a másik az új méret. Fingja nincs a reallocnak a pointer típusokról, ez C, nem C++.
Egyébként pedig mindig a korábbi foglalás méretének megfelelő területet másolja át, már ha nem kisebb az új méret - mondjuk abban az esetben inkább nem is másol, hanem marad minden a helyén.
Alapvetően veled értek egyet - szerintem sem kell tudnia a realloc-nak sem a típust, sem a típus méretét.
Viszont van egy apróság: a topic nyitó hozzászólás arról szól, hogy a realloc a real tömb egyetlen elemét - konkrétan a legelsőt - viszi át. Ha elveted az én magyarázatomat, akkor mondj jobbat! ;-)
Hozzáteszem: kinézem a fordítóból, hogy optimalizálás keretén belül csak annyit másoltat át, amennyi szerinte szükséges. Ez esetben viszont a magyarázat helytálló.
ha statikus az adat (szoveg fajl, nem valtozik a futas ideje alatt), akkor elso menetben csak szamold meg mekkora adatmennyisegrol van szo, es aszerint allokalj, majd masodszorra toltsd csak fel a tombodet :-)
--
NetBSD - Simplicity is prerequisite for reliability
Ez nem rossz ötlet, de SZVSZ gyorsabb lesz bármilyen más memóriabűvészkedés (akár realloc, akár láncolt lista, akármi), ráadásul ha többször akarsz olvasni, nem tud a program pipe-ból olvasni, ami sokszor kényelmetlen.
En is erre gondoltam. Esetleg a fajl merete meghatarozhatja a szamok mennyiseget... (csak szamok + formatum?)
Soha nem használtam realloc -ot. Akkoriban amikor C -vel foglalkozni kezdtem még malloc is megbízhatatlan volt - ms és bl produkciók.
Az ilyen problémákat láncolással oldottam meg (az egyik első saját toolom egy kétirányú láncolt lista kezelő rutin készlet volt).
Szerintem ez az az eset amikor inkább azt kell nézni, mire és hogyan fogod használni a beolvasott táblázatot (régen az is szempont volt, hogy 640 MBájtba beleférjen a program, manapság a feldolgozási sebesség a cél, a memória nem számít, van belőle bőven :)
Nem tudom milyen formátumban kapod az adatot, ha nem annyira kritikus az idő (a pufferelt stream olvasás nem túl időigényes művelet), akkor mielőtt elkezdenéd a memóriába pakolni őket, akár ki is számolhatnád a memória igényt - nem kell nagyon precíznek lenned - egy-két mega ide-oda kit érdekel a gigabájtos memóriák mellett? Optimális esetben, pl. fix hosszúságú számok (mondjuk 0-kal kitöltve) akár a fájl méretéből is kiszámolhatod mennyi memória kell, de lehet hogy a sorok számával is kezdhetsz valamit.
* Én egy indián vagyok. Minden indián hazudik.
Akkoriban amikor C -vel foglalkozni kezdtem még malloc is megbízhatatlan volt
Dennis Ritchie, te vagy az?
LOL
te ne röhögj, te is hülyeségeket irogattál :)
A sizeof(double)-n vagy kiakadva?
Kiakadva nem vagyok, sőt kiváncsivá tettél, hogy szerinted hogyan működik ez a fránya sizeof... ;)
Te write-only vagy?
Azt mondtam, hogy ha egy eljárásban ugyanaz a függvényhívás többször előfordul, akkor érdemes kitranszformálni/egyszerűsíteni valamilyen módon. Nem azért, mert a fordító nem optimalizálná*, hanem azért mert kevesebb a hibalehetőség egy esetleges módosítás során.
Ennek sem a fordító optimalizációjához, sem pedig a sizeof() függvényhez közvetlenül nincs köze.
* - nem hiszem, hogy helyes eljárás vakon bízni a fordítóban és tolni be a kódot, "majd úgy is optimalizálja" felkiáltással.
attttyaúristen
> [...] sizeof() függvényhez [...]
latom, meg mindig vergodsz, segitek: a sizeof C operator, nem fuggveny.
Benéztem. Evvan :)
Igazad van. Megnéztem és a Linux kernelben is több, mint ezer sizeof(int) van. Vegyél részt aktívan a közösség munkájában és javítsd ki az érintett kódrészleteket, majd küldj be egy patchet az LKML-re. Köszi, hogy felhívtad erre a figyelmemet.
FYI: a sizeof() egy operator. Nem fuggveny.
----------------
Lvl86 Troll
de a sizeof(pöts) néha függvény! ;)
OFF:
Nem gondoltam volna, hogy ez a kis mondat így szíven üt, és alkalmat ad egy kupac embernek összerondítani egy jó kis tanuló threadet. Sajnálom.
C-vel a DOS -os világban tudtam megismerkedni, akkor kezdtek megjelenni a kommersz compilerek és ide eszközök ("fapados" kvázi grafikus felületekkel). Akár hiszitek akár nem a malloc nem volt megbízható. Kínomban (csaknem 20 évvel ezelőtti dolgokról van szó) akkor írtam egy kis stressz tesztet - malloc/free 10 "véletlen" méretű blokkot foglaltam, feltöltöttem egy mintával, kiolvastam majd felszabadítottam. A gép csak az én kis "mesterművem" súlya alatt ck. 30 ciklus után minimum arra jutott hogy elfogyott memória, vagy nemes egyszerűséggel letérdelt. Úgyhogy, ha komolyan gondolta az ember, akkor lefoglalt egy akkora méretű memória blokkot amekkorát csak lehetett és azzal "gazdálkodott".
"Robert Laforge TURBO C++ 1991 by the Waite Group Inc.
ABOUT THE AUTHOR
... has been active in programming since the days of the PDP-5, when 4K of main maemory was considered luxurious."
* Én egy indián vagyok. Minden indián hazudik.
a mestermuved valoszinuleg az allatorvosi lo kategoria volt, amin kivalon lehetett demonstralni a double free, use after free, heap overflow meg egyeb betegsegeket. ugye te sem gondolod komolyan, hogy a libc volt a hibas, amikor az akkoriban irt programok sok nagysagrenddel tobb allokaciot csinaltak es megis mukodtek? ad absurdum, maga a C fordito tobbet allokal, mint a te mestermuved :).
Mondom DOS. Nem Linux. Kezdetleges megvalósítások, épp hogy működtek.
* Én egy indián vagyok. Minden indián hazudik.
en is DOS alatti C forditokrol meg programokrol beszeltem.
A DOS mitol lenne rosszabb, mint akarmelyik masik oprendszer? Gyanitom, a Borland cegnel nem komplett idiotak ultek, es talan tudtak forditot meg platformot gyartani.
--
Hát, a DOS szerintem rosszabb, mint bármi más rendszer.
Én úgy emlékszem, hogy 1 szálas volt, interrupt-okkal lehetett időnként háttérmunkát végezni. A 16 bites pointerekről, meg a szegmentálásról ne is beszéljünk.
int k = 3;
char far * p = &k;
A Windows/FreeBSD/Solaris/Linux operációs rendszerekre elfogadom, hogy mindenre alkalmasak, de a DOS-sal nem értek egyet.
Egy hatalmas fellélegzés volt nekem, amikor az int felvehetett már 40000-es értéket is és nem ment át negatív tartományba. Egy csomó programhibát okozott, hogy 32767 után -32768 jött. A char far * és egyéb förmedvények eltűnése is csodálatos volt, meg hogy az adat/kód szegmens 64k-nál nagyobb lehetett.
Úgy emlékszem, hogy 70000 byte leforlalásához a mezei malloc sem működött, és char huge * -kellett, hogy a pointer szegmens határt is átléphessen.
Szóval a DOS ezek miatt sokkal rosszabb, mint bármi más rendszer. Legalábbis szerintem.
Ezek azért kiküszöbölhetőek voltak, igaz, védett mód kellett hozzá (DJGPP szuperjó volt ebből a szempontból)...
A huge és tsaival mennyit lehetett szívni... főleg úgy, hogy fiatal, kezdő kódolóként azt se tudtam, mi fán teremnek ezek...
De mindettől függetlenül számomra a DOS volt az utolsó rendszer, ahol még könnyen ment a programozás. Azóta, hogy más rendszereket használok egyszerűen nem vagyok annyira termelékeny, sokkal kevesebb hobbiprojektet fejezek be...
Meg lehetett Desqview-t (Desqview X-et) használni, meg volt a DRDOS taskmgr... jó volt az, kábé 2005 tájékáig ezeket használtam (konkrétan nem is volt másra lehetőségem... de nem bánom).
Ezek nem DOS fuggo, hanem az x86 valos modjabol fakado problemak ami alatt a DOS futott.
Ezt a ruszkik utana a PTS DOS-szal nativan, a DOS extenderek pedig kiegeszitovel orvosoltak, sot, meg a Caldera is megoldotta a multitaskot DOS alatt. 32 bites utasitasokat meg valos modban is lehetett hasznalni, ez sem volt akadaly.
---
pontscho / fresh!mindworkz
Használják még a DOS-t ma is valamire?
A DOS helyett egy pénztárgépbe mondjuk egy lebutított pár megás Linuxot pakolnék bele. Gyorsan indul, az ütemezője, fájlrendszere ki van tesztelve, jogosultság kezelés, prioritások,...
Kevés helyet foglal, tesztelt és sokkal kényelmesebb, mint 0-ról megírni egy TCP/IP stacket.
A DOS úgy tudom megrekedt a 90-es évek technikai szintjén, ezért nem kezdenék alá programot írni.
> lebutított pár megás Linuxot pakolnék
húúúhhhhúhúhúúhúhúúúúúú :DDDDDD
Nem lehetne o a HUP bohoca? Mostanaban tobb tole az epic fail, mint zamboriztol.
Kíváncsi lennék a lélekpszichológiájára az ilyen embereknek.
- 2011 áprilisában leírok egy baromságot
- sok okostojás ezen csámcsog, hogy realloc, meg hogy malloc, meg hogy anyám kínja. Oké, Istenem, megértem, mert mély nyomot hagyott bennük
- utána sokáig nem írok a topikba, ezidő alatt ők egyfolytában írogatnak, hogy realloc, meg malloc,...
- emellett ahány hozzászólást írok a HUP-ra, minden válasz realloc-kal jön vissza tőlük
- 2011 augusztusa van, barátok között is 3 hónap legalább eltelt, bármit írok, a válasz realloc...
Én naponta 9 órát dolgozom, 2 órát utazok, fürdetem a gyermeket,... Halvány fingom sincs, hogy ki a tököm az a persicsb, meg a kirsa74 és éppen milyen f@szságot mondott 2011 áprilisában. Sőt, nem is érdekel. Joga van mindenkinek f@szságot beszélni, Magyarország egy demokratikus állam és ha éltek ezzel a jogotokkal, engem nem zavar.
Csak azt nem értem, hogy mivel foglalkoztok egész nap, hogy ennyi idő jut lenézésre, gyűlölködésre, meg más emberek buzerálására?
Tudod, nekem nem lenne energiám 4 hónapon át egyfolytában a realloc bulshit-et kántálni.
butthurt much?
GOOD
Nem sértődtem meg, de igazából sajnállak a "GOOD" miatt.
Nekem semmilyen örömet nem jelent az, ha te, vagy bárki más megsértődik és ideges lesz egy hozzászólásom miatt. Az, hogy te ebben leled örömed, a te dolgod.
Sőt, ha holnaptól abbahagynád a buzerálásomat, én sem emlegetném fel neked az elmúlt 4 hónapot, hogy túltettél 50 vénasszonyon piszkálódásban, mert nem érdekel. Örülnék, ha végre befejeznéd.
Engem nem zavar, ha minősíted, amit leírok. Igen, időnként hülyeségeket beszélek, jogom van hozzá. A realloc tekintetében hasznos is volt a felvilágosítás, bár finomabb stílusban jobb lett volna.
Tanultam a beszélgetéssel, de nem a ti épületes hozzászólásaitokkal (te mekkora köcsög vagy stílus), hanem azzal, hogy valaki elmagyarázta, például hogy a realloc miért nem másol semmit. Szerencsére vannak olyan emberek, akik képesek voltak értelmes választ is leírni egymás fikázásán túl.
> túltettél 50 vénasszonyon piszkálódásban
köszi az elismerést!
hagyd rá, így dolgozza fel, hogy képtelen megérteni alapvető társadalmi normákat (pl. köszönés) és bonyolult nyelvi konstrukciókat (pl. feltételes mód, kérdő mondat).
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
meg azt is képtelen, hogy hogyan kapcsolódik a realloc-hoz, meg a DOS-hoz a köszönés, a feltételes mód és a kérdő mondat...
Nagyon érik már egy a Hupper plugin install a Firefoxra.
Hát nézd, ismerősök nem olvassák a hupot, maximum néha, ha kapnak egy-egy topicot, "ez üt, mint az úthenger" felkiáltással valakitől, de a "rossz szerkezetű nyelv" mém a mai napig az eszükbe égett.
Nézd a jó oldalát: híres lettél ;)
----------------
Lvl86 Troll
A DOS még gyorsabban indul. A DOS ütemezője még jobban ki van tesztelve. Remélem tudod, hogy többszálú programokat elméletileg sem lehet debugolni rendesen, a nemdeterminisztikusság miatt (pontosabban: futásról futásra más lehet az eredmény). A DOS ezzel szemben egyszerre egy processzt futtat, teljesen determinisztikus. Filerendszere a legjobban elterjedt filerendszer a világon, ez van a legjobban letesztelve. Miért kéne 0-ról megírni egy TCP/IP stacket? Szerinted a DOS-hoz nem írtak TCP/IP stackeket 30 év alatt?
> teljesen determinisztikus
Álljálljállj. Interruptról hallottál-é? Innentől kezdve...
Ezt fejtsd ki. Az interruptok nem vezetnek többszálúsághoz, csak "eseményvezéreltté" teszik a programot. Ezek az események, ha mindig ugyanakkor történnek, akkor mindig ugyan az fog történni. Ez a determinisztikusság. Ha két azonos körülményű futás alatt ugyanakkor jönne egy keyboard interrupt, mégis máshogy reagálna a program, na akkor nem lenne determinisztikus.
----
Hülye pelikán
Az interruptok sokmindenbe belekavarnak. Simán előfordulhat szinkronizációs probléma.
--> Cella kiolvasás
Interrupt --> Cella kiolvasás
Interrupt --> Csökkentés 1-gyel
Interrupt --> Cella visszaírás
--> Növelés 1-gyel
--> Cella visszaírás
Az Interrupt eggyel csökkent, a fő szál eggyel növel, mégis a végeredmény +1 lesz nulla helyett.
Ráadásul szinkronizálni nem tudom, hogy hogyan lehetne ebben az esetben. Nem tudsz várakozni, mert egy szál van.
És mi indította el ezt az interruptot, drága egyetlen fiam?
----
Hülye pelikán
timer?
hardverből jön az órajel és időnként megszakít.
Az "int 67" szoftver interrupton kívül hardver még van egy pár hardver is. Arra végképp nem lehet felkészülni.
Az integrált áramkörök az IRQ vonal állapotát cseszegetik.
Timer lejár:
- IRQ vonal alacsonyba megy
- a CPU vagy megszakít, vagy ha az IRQ tiltva van, akkor nem foglalkozik vele
- amint az IRQ-t engedélyezed, azonnal megszakít
- a program beszól a timernek, hogy elengedheted az IRQ vonalat
- IRQ vonal magasra megy, engedélyezve új megszakításokat
Randa egy dolog, C64-en tipikus volt. Az IRQ tiltásával szinkronizáltál.
És ez mitől nem determinisztikus, azt áruld el nekem. Fentebb leírtam, mitől lenne nem determinisztikus.
----
Hülye pelikán
Attól, hogy fingod sincs, hogy a timer interruptja mikor jön.
C64 kernel ROM alatti terület olvasása:
SEI -> interrupt tiltása
LDA #$30
STA $01 -> kernel ROM lekapcsolása
LDX $FF00 -> RAM érték olvasása
LDA #$37
STA $01 -> kernel engedélyezése
CLI -> interrupt engedélyezése
A kurzort a C64 timer interruptok alapján villogtatta. Szimplán a kernel-t nem lehetett lekapcsolni, mert a timer bármikor megszakíthatott, ami fagyáshoz vezetett. Ezért kellett letiltani az interruptot mialatt a kernel mögötti RAM-ot olvastad.
A lényeg, hogy az IRQ nagyon nem determinisztikus. Arról nem is beszélve, hogy egértől kezdve minden köcsög küldözgette az interruptokat.
Determinisztikus: mindig ugyanazokat az utasításokat hajtod végre egymás után.
Amikor az egér benyom neked egy interrupt-ot, amint Pistike megrázza a kezét, a determinisztikus viselkedésnek azonnal vége. Leginkább egy 2 szálas környezetre fog hasonlítani. Vagy interrupt, vagy főszál.
Megfelelően sokat szoptam C64 alatt az interruptokkal, hogy megtapasztaljam, hogy mennyire nem determinisztikusak.
Simán előfordult, hogy 5 percig jól ment minden, utána elszállt, mert az interruptot elfelejtettem itt-ott letiltani. Kísértetiesen hasonlít az egész interruptos viselkedésmód egy többszálú környezetre.
Kísértetiesen hasonlít, mert TE elfelejted letiltani. Igen, az EMBER nem determinisztikus (legalábbis nem ezen a szinten), így a hibái sem azok.
Szerinted a determinisztikus az, hogy mindig ugyan azt hajtja végre. Elég szűk és elég haszontalan kör ez. Gyakorlatilag semmi igazán értelmes dolog nem determinisztikus szerinted. Én meg újra leírom: determinizmus az, hogy ugyanolyan körülmények között ugyanolyan viselkedést produkál. Azaz ha két teljesen azonos gépet egyszerre elindítasz és ugyanúgy "ingerled", akkor ugyanazt fogják kihozni. A timer interruptokkal együtt.
----
Hülye pelikán
Az ilyet el kell adni valódi véletlenszámgenerátornak, és akkor nem kell beérni a pszeudoval.
Elszoktam az assemblytől az elmúlt 10 évben.
A szinkronizáció az IRQ tiltásával történt, CLI, STI.
Megnézném, hogy te egy megszakítást hogyan állítasz be (maradjunk annál, hogy DOS rendszer (IT tiltás nem ér)), hogy mindég ugyanott érkezzen, mindég az adott utasításnál.
Értem, mire akarsz gondolni, de ez villamosmérnöki szempontból - amennyire engem tanítottak - elvben ugyan determinisztikus, de hogy soha nem fogod végigjárni az összes lehetőséget, az is biztos.
Az, hogy az IDŐTŐL függ a program lefutása, nem sérti a determinizmust. Az indítási idő egy jól definiált dolog. A nem determinizmus amikor ugyanakkor indítva ad más eredményt.
----
Hülye pelikán
oké,
- elindul a DOS
- elindul az időzítő és 20ms-enként megszakít
(eddig determinisztikus)
begépeled: a következőt - nc.exe (Norton Commander)
- elindul a Norton Commander
A Norton Commander honnan tudná, hogy hol jár az óra? Attól függ, hogy milyen gyorsan gépelted be, hogy nc.exe.
Lehet, hogy indulás után 1 ms és megszakít, de ha más a gépelési sebesség, elképzelhető, hogy 19ms múlva jön az IRQ. A Norton Commandernek elképzelése sem lesz arról, hogy mikor jön az interrupt.
Az, hogy mikor szakít meg, kizárólag attól függ, hogy mikor nyomsz ENTER-t.
Igen, de ha mindig ugyanakkor jön az interrupt, akkor mindig ugyanúgy fog működni. Érted már a determinisztikusság jelentését? Azt már fent tisztáztuk, hogy az ember nem determinisztikus, így az ember gépelési sebességét idekeverni elég hülye dolog. Az, hogy mikor jön az enter az egy elég jól meghatározható dolog viszont, így mint esemény nagyon jól beleillik a környezet fogalmába, ami ugye ha nem azonos két lefutásnál, akkor nem kell a lefutásnak sem hasonlónak lennie.
----
Hülye pelikán
Ki kellene lépned a laboratóriumi körülmények közül.
- van egér
- van billentyűzet
- ezek viselkedése befolyásolja, hogy a program milyen ágon megy végig
- van merevlemez, ahol a fej állása tetszőleges és véletlenül sem tudod megmondani, hogy mikor töltődik be a szektor.
- az óra egyszer elindul és ketyeg
Mire az nc.exe betöltődne, már az interrupt gyakorlatilag teljesen véletlen időközben fog meghívódni.
Természetesen ha nincs merevlemez, nincs billentyűzet, nincs egér,... akkor, de csak akkor determinisztikus. Az esetek 0.00001%-a ez.
C64-en meglépték, hogy letiltották az interrupt-ot, lekapcsolták a képernyőt hogy a CPU-t ne fékezze és az óra aktuális értékével XOR műveletet hajtottak végre a programkódon, így titkosították. Az óra és a CPU ilyenkor determinisztikusan járt, ezért lehetett vele titkosítani. De amikor a videókártya DMA-zik, meg minden marhaságot csinál, onnantól a timer és a CPU külön életet él, teljesen.
Hallod, az a baj, hogy még ha igazad sem lenne, akkor sem értenéd, hogy miért. Annyira nem fogod fel amit írok. Tényleg, őszintén, ugorj neki mégegyszer, és olvasd el amit írok, hátha leesik, hogy amit írsz az egyáltalán nem cáfolja azt, amit én írok. Lejjebb van már egy kis értelemmorzsa, de persze nem tőled.
----
Hülye pelikán
Azért egy kicsit kevésbé gorombán kérlek.
Inkább elméleti oldalról fogod fel.
Vedd észre, hogy több szálú, sőt több processzoros rendszer is tud determinisztikusan viselkedni. Ha kiszűröd teljesen a környezeti hatásokat, akkor mindig minden 23 processzoron is ugyanúgy fog viselkedni.
A beszélgetés arról szólt, hogy az interrupt már kilép az egyszálú világból. A Citizen 120D nyomtatón interrupttal 4 szálat implementáltak. Az IRQ átállította a stack pointert és mindig máshová tért vissza.
Az 1541 floppy az interrupt kezelőben olvasta be a szektorokat, a fő szál meg a logikai részeket kezelte.
3-4 szálat interrupt segítségével egy Commodore is elkezelt.
jah ez azok tudnak majd *egyszerre* futni?
--
NetBSD - Simplicity is prerequisite for reliability
A nyomtató ütemezője tetszett nekem a legjobban:
- a 256 byte-os stacket 4 egyenlő részre osztották, minden szál 64 byte-ot kapott működésre
- minden interruptkor a stack pointert átállította, hogy a következő szálra mutasson
- a szinkronizálás az interrupt letiltásával történt
- amikor egy szálnak nem volt dolga, szoftveres interruptot hívott, az ütemező a vezérlést meg másik szálnak adta át
Mindezt max. ~128 byte-on írták meg. Nem egy mai tudomány az a számítástechnika.
:)
"- amikor egy szálnak nem volt dolga, szoftveres interruptot hívott, az ütemező a vezérlést meg másik szálnak adta át"
És akkor most térjünk vissza oda, hogy a párhuzamosság arról szól, hogy (legalább) két utasítás egyidőben, egyszerre, egy órajelre dolgozódik fel.
----------------
Lvl86 Troll
Hardver szempontból. De ez így nagyon szűklátókörű definíció, és szerintem egyáltalán nem jellemző így meghatározni a párhuzamosságot.
Ugyanis szoftverszempontból: egy utasítás amit tetszőleges magas szintű programnyelven megejtesz általában összetett, azaz több gépi utasításból áll -> így azok egy szálat kezelő processzoron is futhatnak párhuzamosan: azaz ha két utasítás S1,S2 időpontban indul és T1, T2 időpontban fejeződik be fennállhat, hogy: S1<T2 és/vagy S2<T1
Szerintem a programozók nagyon nagy hányada élte le úgy a karrierjét, hogy többszálú és párhuzamos programokkal egyprocesszoros rendszeren foglalkoztak, ha hiszed ha nem! ;)
A szuperskalár architektúrát a programozó semmilyen formában nem látja (azon kívül, hogy a teljesítmény magasabb), kifelé ugyanúgy soros a végrehajtás, különösen abban az esetben, ahol az utasítások között adatfüggőség van. Ez csak arról szól, hogy egy órajelciklus alatt több utasítás feldolgozása is megtörténik, de ettől azok az utasítások még nem párhuzamosan futnak egymás mellett. Csak éppen a pipelineban egyszerre több utasítás van benne, eltérő fázisban (fetch, vagy decode, vagy execute, stb...). De ettől ez még nem valódi párhuzamos végrehajtás a külső szemlélő szempontjából, akkor lenne az, ha egyszerre több utasítás olvasódna be a CPU-ba. Az, hogy a CPU-n belül mi történik (skalár vagy szuperskalár), édesmindegy, mert a programozási modellje ugyanaz. Amíg egy CPU-ban egy regiszterkészlet van (azaz egyszerre csak egy állapotban lehet), addig ott nincs valódi párhuzamosság, csak szimulált, sok context switch-csel emulált többszálúság.
A valódi többszálúság és a szimulált többszálúság között programozástechnikailag lényeges különbség nem sok van.
- a szinkronizációra mindkét esetben oda kell figyelni
- a tényleges többszálú környezetben viszont egyenletesen kell leterhelni az összes processzort, különben 1 CPU-t fullra nyomsz, a többi meg nem csinál semmit (skálázhatóság)
1 processzoron jól megírt programnak működnie kell több processzoron is, a legrosszabb, ami történhet, hogy lassú lesz.
Szerintem neked kimaradt az életedből az számítógép architektúrák.
Nem csak logikai, szálszintű párhuzamosság létezik. (Ami valójában csak egy "virtuális" valami, hiszen hardver szempontjából ismeretlen fogalom a thread, csupán programozástechnikai kérdés. Mint ahogy a változó fogalma is csak egy logikai fogalom a magasabb szintű nyelvekben, HW szempontjából csak (rejtett és nem rejtett) regiszterek és memória létezik.)
----------------
Lvl86 Troll
Villamosmérnök vagyok nem infós.
Természetesen egy DSP-t/GPU-t rohadtul másképp kell programozni, mint egy Pentium-szerű CPU-t.
Nem fejtettem ki bővebben, de a Pentiumra gondoltam a hozzászólásnál.
Egy Pentium szeru CPU is kepes utasitasszintu parhuzamossagra a pentium 1-tol kezdve, ugyanis ket futoszallagot tartalmazott. Megse kellett maskepp programozni.
(Bar teny, hogy egy jobbfajta forditoval egy kis statikus optimalizalassal lehetett konnyiteni a proci dolgan).
A GPGPU meg mar megint mas teszta, mert az inkabb SIMD[-nek indult], mint MIMD, ami a fizikailag torteno parhuzamossaghoz utasitasvegrehajtast jelenti.
----------------
Lvl86 Troll
GPU sosem lett MIMD es architekturalis okok miatt sosem lesz az jelen felallas szerint. Legfeljebb ugy tunhet, de ez csak optikai csalodas a kartyara telepitett utemezo miatt.
---
pontscho / fresh!mindworkz
Még mindig ott tartunk, hogy nem értünk egyet abban, mi számít lefixálandó ingernek, és mi véletlenszerű külső tényezőnek. A többszálas oprendszerek ütemezői például úgy tűnik egy ilyen határmezsgye.
----
Hülye pelikán
Elméletben igaz, amit írsz, de működő eszköznél sajnos hajadra kenheted az elméletet. Szóval tényleg determinisztikus lehetne - ideális körülmények közt. Valószínűleg mást értünk determinisztikusságon. Nálam ez egy gyakorlatban (szinte?) elérhetetlen ideális valami.
Azt hiszem, mindkettőnknek igaza van a maga érvényességi körén belül, szerintem ne vitázzunk róla.
Igen, kéne valami szagértő, aki pontosan megmondja, de valószínűleg nincs neki ennél pontosabb definíciója. Így nyílván alkalmazási területtől függ, hogy mennyire kell determinisztikusnak lennie ahhoz, hogy annak tekintsük.
----
Hülye pelikán
Ez csak tipp, de szerintem a determinisztikussag altalad felvetett fogalmanak csak akkor van jelentossege, ha egy program lefutasarol beszelunk. Tehat, egy printf() futasa ket gepen nagyjabol determinisztikus lesz, idotol fuggetlenul.
Egy program effektiv mukodese, vagy egy gep hasznalata sosem lesz determinisztikus, hacsak nem egy ketkaru gep uti a gombokat parhuzamosan a ket gepen - mert akkor pont ugyanannak kell tortennie.
--
Erről van szó: azonos ingerre azonos lefutás. Különböző ingerre ez nem garantált, akár determinisztikus, akár nem. Ha nem egyszerre ütöd a billentyűket, akkor hogy mondhatod, hogy azonos az inger?
----
Hülye pelikán
A nézőpontok keverésével lehet itt probléma. A számítógép alapvetően összességében determinisztikus működésű (direkt ilyennek van tervezve, leszámítva a hardveres véletlen generátorokat persze).
Ebből a szempontból nézve minden program determinisztikus.
Azonban fejlesztés közben a program szempontjából kell nézni a dolgokat:
a programok meg általában információhiányos környezetben működnek, számos eseményt lehetetlen előre "megjósolni" (nincs a számítógépeken belül egy tökéletesen ugyanolyan de gyorsabb számítógép ami előre lemodellezgeti a programnak az egyébként determinisztikus jövőt), illetve adott esetben nem férhetnek hozzá bizonyos - kívülről szintén determinisztikus - részekhez amik az ő működését befolyásolják (ütemező, más programok, megszakítások, óra stb. állapota)
Az információhiány SZUBJEKTÍV indeterminizmusként jelenik meg a programozó előtt:
Azaz úgy kell fejleszteni, hogy BÁRMIKOR bekövetkezhet interrupt, Joli néni pedig BÁRMIKOR megnyomhatja az entert, stb...
A szubjektív valószínűség matematikai, elméleti és gyakorlati kezelése egyébként tökéletesen azonos az objektív valószínűséggel:
pl. a dobokócka dobás eredménye tfh. valódi objektív véletlen: minden szám esélye egy a hathoz, ha azonban úgy dobunk, hogy egy átlátszatlan poharat lefordítunk a kockával - akkor a dobás eredménye már eldőlt és így bizonyosan determinisztikus, csak fel kell fordítani a poharat:
DE amíg ez nem történik meg mi információhiányos állapotban vagyunk, ezért TOVÁBBRA IS ugyanazt a matematikát kell alkalmaznunk a kockára (minden szám valószínűsége 1/6) mint a dobás előtt, annak ellenére, hogy ekkor ez már csak a mi tudatlanságunkból fakadó SZUBJEKTÍV valószínűségi esemény
+1
valóban, bár a számítógép determinisztikus, de a bekövetkező különféle külső események miatt (DMA, billentyűzet, egér, merevlemez késleltetés,...), igencsak jól közelíthető egy interrupt úgy, mintha előre nem látható időpontban jönne.
Az interrupt kezelésénél, az alkalmazás nem tudja megjósolni, hogy mikor jön, csak annyit tud, hogy valamikor jöhet és a kritikus helyeken tiltja.
Olyan kódot írsz, hogy véletlenszerűen működő timerrel is menjen. Nem használod ki, hogy egyenletesen működik, úgy programozol, mintha indeterminisztikus lenne.
A gyakorlatban ez mondjuk sohasem az időtől (ami egy elméleti absztrakció) hanem mindig csak az órától (ami egy gyakorlati eszköz) függhet!
A jelenleg elterjedt órákban pedig van véletlen (de minimum kaotikus) faktor, annyira, hogy többek között épp ez az egyik kihasznált alkalmazási területük:
http://en.wikipedia.org/wiki/Clock_drift#Random_number_generators
http://en.wikipedia.org/wiki/Hardware_random_number_generator#Clock_dri…
szerk.: még annyit, hogy az információhiányos helyzeteket (pl. ebben az esetben ilyen, ha nem ismerhetjük minden utasítás előtt pontosan az óra állapotát), elméletileg és gyakorlatilag tökéletesen ugyanúgy kell kezelni, mintha az ettől függő dolgok indeterminisztikusak LENNÉNEK (még akkor is ha nem azok)
Most őszintén egy pénztárgépre miért kell, hogy az operációs rendszerben jogosultság kezelés legyen? Elég, ha program szintjén lekezeled. A felhasználó úgysem fér hozzá a konzolhoz...
A FAT12 és FAT16 meg elég jól ki lett tesztelve az elmúlt 30 évben. Amire tervezték arra jó.
Nagyon el vagy tévedve, amikor nem jösz rá, hogy vannak helyek ahová nem kell Linux, Windows vagy akármi, bőven elég egy DOS is. Pl. a villanyóraleolvasó kis gépében is DOS van. Ezen fut egy program amivel rögzíti az óraállásokat egy nagyon egyszerű adatbázisba. Esténként meg felviszik őket az SAP-be.
A 90-es évek szintjét meg én nem szidnám, mert annyira nem volt az rossz. A technikai lehetőségek korlátozottabbak voltak, mint most, de az igazi programozó akkor is tudott programot írni, a kontár meg most sem tud...
Ennek ellenere meg ma is fejlesztik, sot van ceg, amely az arusitasabol el:
http://www.phystechsoft.com/ptsdos/products.php
http://www.freedos.org/
----------------
Lvl86 Troll
A DOS úgy tudom megrekedt a 90-es évek technikai szintjén, ezért nem kezdenék alá programot írni.
Ehhez kepest pl. a pts dos 32 bites os, multitaszkkal, network stack-kel es mindennel ami egy embeded oshez kell. :)
---
pontscho / fresh!mindworkz
Pedig a DOS-nal jobb platform nincs, ami celeszkozok programozasara hasznalhato. Pont, mert olyan regi, a rendszer legalacsonyabb szintjeit is tudod vezerelni vele konnyeden.
Raadasul a Linux mindig is tobbet fog enni, mint egy DOS, hacsak nem akarsz egy 2.4-es Linux kernelt, ami... hogy is mondtad... "úgy tudom megrekedt a 90-es évek technikai szintjén, ezért nem kezdenék alá programot írni".
--
"Használják még a DOS-t ma is valamire?"
Vonalkódos címkéket küldenek vele célnyomtatóra párezertől pármillió dollárig terjedő árú termékekhez.
ezt megirod neki is?
http://dosmandrivel.blogspot.com/2007/09/design-of-dos.html
aztan pasztold ide a valaszt, hadd rohogjunk
--
NetBSD - Simplicity is prerequisite for reliability
A DOS kiváló bootloader volt.
O, Gott im Himmel, és tényleg, használtuk azt a bizonyos loadlin parancsot. Nem hiányzik egy kicsit sem :-)
Fuszenecker_Róbert
Nem csak ezert, a Netware konkretan meg ma is igy bootol (pontosabban tud igy bootolni).
--
Hihetetlen ez a topic :-)
https://groups.google.com/group/comp.lang.c/msg/08f9f7cd8186067a?hl=pt ( 1991 ! )
/* Ha ezt ciklusban követték el, pillanatok alatt elfogyott az amúgy sem túl sok memória */
egyebekben :
Anno mikor én tanultam a C-t,
maga a tanár ( C könyvet is írt azóta, és szerintem értett is hozzá )
mondta hogy konkrétan ennél a fordítónál a malloc() egy sz*r,
ezért házifeladatba adta, hogy mindenki írjon egy sajátot és a továbbiakban azt használja.
Én ennek anno nem jártam utána, de megírtam a saját "malloc()" függvényemet és azt használtam... :-)
1. elolvastad amit belinkeltel? eppenseggel pont az ellenkezojerol szol, mint amit a joember mondott: a malloc/free teljesen jol mukodtek, de a printf/gets memoriat leakeltek (tegyuk fel legalabbis, hogy tenyleg az volt). az utobbiaknak rohadtul semmi koze se a C forditohoz, se a malloc implementaciohoz (ertsd: az a printf/gets implementacio mas C forditoval es mas malloc implementacioval ugyanugy leakelt volna).
2. a C-t a GDF-en tanitottak neked? mert leirom sokadszorra most mar: a malloc meg a C fordito ket KULON ALLAT. olyan nincs, hogy a 'ennél a fordítónál a malloc() egy sz*r'. olyan lehet, hogy az adott C fordito/toolchain altal belinkelt malloc implementacio (tipikusan a rendszer libc-jebol, de van sok mas malloc implementacio is) 'szar', de az akkor se a C nyelv vagy fordito problemaja (es persze lehet olyan is, hogy a C fordito hibas kodot general, de akkor a libc/malloc lesz a legkisebb problemad).
a malloc/free teljesen jol mukodtek, de a printf/gets memoriat leakeltek
Még csak a printf() sem leak-elt. Naggum, nyugodjon békében, arra mutatott rá, hogy az stdio stream userspace buffer-elést használ (tud használni). Pongyolán megfogalmazva, az ember ezt a buffer-t az első IO művelet előtt beállíthatja kézzel is, de ha nem teszi, és a körülmények / az implementáció olyan, akkor majd az első IO művelet foglal egy ilyen buffer-t "valahol". Ez logikailag nem leak, mert az fclose() az automatikusan foglalt buffer-t felszabadítja.
setvbuf() (Linux/glibc), setvbuf() (SUSv4), Standard I/O Streams (SUSv4).
A cikket elnezve, inkabb a memoriakezeles korul volt gond, tekintve hogy elvben a s-nek egyertelmuen meg kellene cimeznie a malloc-cal foglalt teruletet, es erdektelen, hogy ez volt-e a "topmost allocation" vagy sem. Ha valami szar is volt, az inkabb a free, meginkabb az stdio lehetett, a malloc teljesen jol mukodik a peldaban.
--
Megvan még az a kódod? Tedd már be!
[ OFF ]
Megnyugtató olvasni a hozzászólásokat. Jó tudni, hogy lesz állásom :)
[ /OFF ]
Ajánlanám a [] operátor használatát, nagyban áttekinthetővé teszi a kódot, főleg a tanulók esetében. Persze csak ha nem az a cél, hogy rögtön minden memóriaműveletet azonnal értelmezni akarsz.
+1
(-::
Annyit tennék hozzá még, hogy, ami C-ben nem írható meg az
C++-ban és javában sem.
A témához is: amikor írsz egy programot, azért nagyjából
illik tudni, hogy milyen és mennyi inputot fogsz vele
feldolgozni. A megoldás ebből levezethető.
> Sol omnibus lucet.
[OFF]
A problema az, hogy a munka nagy resze mas utani rendrakas lesz...
[/OFF]
----------------
Lvl86 Troll
van az a penz.. :D
Már az első program is rossz. Kívül címzel a lefoglalt memórián. Amikor csak egy elemű a tömb, akkor nem kéne semmit hozzáadnod a p_vector mutatóhoz, de te i+1 miatt hozzáadsz. További hiba, hogy ha double* típusú mutatóhoz hozzáadsz egyet, az rögtön egy egész double-nyi helyet fog lépni, ezt már nem kell szorozni sizeof(double)-val.
Pár gondolat:
A build_vector rows, this_row_elements, first_row változói (értsd: a pointerek által mutatott változók) nem változnak. Akkor minek ökörködünk a pointerekkel?
(Persze ha jól értem mit szeretnél, akkor kellenek a pointerek. Ebben az esetben illene változtatni is őket.)
Ez teljesen átláthatatlan:
Annyira nem írunk ilyet szinte soha, hogy a fentebb szövegelő okostojások, és még a kevés hozzáértő figyelmét is elkerülte, hogy hihetetlen módon túlindexelsz...
Mert itt most *p_vector double*, azaz (*p_vector)+1 nem a következő byte-ot, hanem a következő double-t címzi, azaz nem kell a sizeof(double) felszorzás.
Ez valamivel tán jobban mutat:
A realloc használata teljesen korrekt, de érdemes lenne (ahogy fentebb is írták) nem double-önként, hanem a területet mindig duplázva használni...
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o
Hello! Az első kódrészed kicsit egyszerűsítve:
Szóval, mint feljebb már említették:
- A feltöltő ciklusban (illetve a kiíratóban is, csak ott nem annyira ;) ) túlindexelsz, valamint teljesen felesleges előre lefoglalni, elég a ciklusban (a man realloc azt mondja, hogy ha NULL-t adsz be neki, akkor a realloc malloc-ként működik).
- Átláthatóbb, ha
[]
-t használsz*(ptr+index)
helyett.- Persze okosabb, ha nem egyesével foglalod le a double helyeket, a duplázós pl. jó gyakorlat, csak általában célszerű nem 1-et választani kezdőméretnek ;) .
- Meg persze jobban kell hibát kezelni, ez itt csak kezdetleges.
Bocs, kétszer ment...
a [ code ] blokk erre van.
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
Köszi, <code> -ot használtam, azzal nem volt jó a behúzás, [ code ]-dal jól megy.
igen, pedig ugyanannak kéne lennie, fura dolog ez...
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
Drupal5/HUP sajatossag.
--
az nem már 7-nél jár? ha már verziók...
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
Az ott igen, ez itt nem. Bovebben: HUP, powered by Drupal 5
--
flamebait volt, de nem jött be :)
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
malloc_usable_size()
http://lxr.e2g.org/source/bionic/libc/include/malloc.h#L64
Ha nagyon hekkelni akarsz. Asszem libc alap fícsör.
Happy Hacking :-)
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.