honnan tudja a C, mekkora egy double tömb?

Fórumok

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:


double* array = calloc(1, sizeof(double));
double d = 3.1415;
int size=0, last=0;

while (yourdoublereader(&d))
{
    if(last == size-1) /* elobb utolso helyre irtunk */
    {
        size *= 2;
        array = realloc(array, size*sizeof(double));
    }
    last++;
    array[last] = d;
}

last++;
array = realloc(array, last*sizeof(double));
/* Innentol a tomb akkora, amekkoranak kene lennie */

Try, modify.
--
"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.

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 :)

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

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":


  Semantics

2 The sizeof operator yields the size (in bytes) of its operand, which may be an
  expression or the parenthesized name of a type. The size is determined from the type of
  the operand. The result is an integer. If the type of the operand is a variable length array
  type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an
  integer constant.

Egy példa az "integer constant"-ra:

12

.

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.

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.

" 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.

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.

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.

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.
:)

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.

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

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

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á.

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.

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.

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

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

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

"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.

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

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 :)

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).

"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.

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

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

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.

"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.

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,

ptr = malloc()

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

Az direkt fonots, hogy c-ben legyen? Ha nem, akkor irany a c++, ott lenyegesen egyszerubb a tortenet.

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.

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

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.

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.

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 :).

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.

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.

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.

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?

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.

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.

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

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.

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

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.

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

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

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.

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.
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal 

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...

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".
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal 

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.
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal 

[ 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.

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:


 *( *p_vector + ( ( *rows -1 ) * *first_row * sizeof( double ) ) + ( ( *this_row_elements - 1 ) * sizeof( double ) ) ) = next_num;

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:


(*p_vector)[(*rows-1)*(*first_row)+*this_row_elements-1] = next_num;

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:


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

int main(){
    double * p_vector = NULL;
    const double inc = 5.63451;
    int i;

    // write 5 doubles into array
    for( i = 0; i < 5; i++ ){
        p_vector = realloc( p_vector, ( ( i + 1 ) * sizeof( double ) ) );
        if (NULL == p_vector){
            printf("Error while (re)allocating memory!\n");
            return 1;
        }
        p_vector[i]= (i*inc);
    }

    // print the elements of the array
    for( i = 0; i < 5; i++ ){
      printf( "%f\n", p_vector[i] );
    }
    free(p_vector);
    return 0;
}

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.