Dinamikus memória kezelés hiba C

Dinamikus memória kezelés hiba C
2014-04-28T00:21:53+02:00
2014-05-01T16:24:04+02:00
2022-08-08T19:55:30+02:00
BB3
Sziasztok,
C nyelvben adódott a következő problémám:

A feladatom az az, hogy a program egy fileból beolvas értékeket csv-ből és dinamikusan eltárolja egy 3 dimenziós tömbben. Ez elvileg működik is.  Mivel a feltöltő while ciklusban kiíratom, de ha a ciklus után akarom kiiratni akkor kifagy a fordítóm.



Tudnátok nekem ebben segíteni?
Hol lehet a probléma a tárolásom nem jó vagy a kiíratásom, esetleg egyik sem? :O
Előre is köszönöm a segítségeteket.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <locale.h>



int main (int argc, char *argv[]){

char akt_ertek; //file beolvasásakor az aktuális karakter ide tárolódik

int hossz = strlen(argv[1]); // első arumentum hossza
int hossz2 = strlen(argv[2]); //második arg hossza
char atmeneti[100]; // ezt dinamikussá kell majd tenni ebben tárolódnak a karakterek ameddig nem lesz ; majd innen kerül átírásra a din tömbbe [cella érték]
int i=0, j=0, idezodb=0; //segédváltozók idezodb kell az idézőjelek számolásához
int enter = 0; // logikai segéd változó, elértük-e a sor végét 1=igen 0=nem

//tároláshoz
char ***ptomb; //3D char tombre mutató pointer
char *cella; //ebben tárolódnak a karakterek ameddig nem lesz ; majd innen kerül átírásra a din tömbbe [cella érték]

//sor/oszlop számolás
int sor = 0; //segédváltozó, hány soros a bemeneti adat
int oszlop = 0; //segédváltozó, hány oszlop van az aktális sorban
int *szeles; // 1D tömb amiben tároljuk, hogy egy adott sorban, hány oszlop van! kiíratásnál lesz fontos

//fájl kezelés
FILE*in;

setlocale(LC_ALL, ""); // nyelv beállítása jó
//SetConsoleCP(1250); // nyelv beállítása - nűlam nem működik

in = fopen("valami.csv","r");
szeles = (int*)malloc(1*sizeof(int)); // szélesség tömb lefoglalása
szeles[0] = (int)malloc(1*sizeof(int));
szeles[0] = 0;


ptomb = (char***) malloc(1 * sizeof(char**)); // első sor elem-re mutató pointer létrehozása
ptomb[0] = (char**) malloc(1 * sizeof(char*)); // első oszlop-ra mutató pointer létrehozása
ptomb[0] = (char**) realloc(ptomb[0], 1 * sizeof(char*)); //új oszlop létrehozva (A oszlop)

cella = (char*) malloc(1024 * sizeof(char)); // ideiglenes "puffer" tárolónk



while((akt_ertek=getc(in))!=EOF){
if (akt_ertek == '\n'){ // sor / oszlop miatt //sor vége vizsgálat
enter = 1; //beállítom a logikai segédválzotót 1-re mert végig értem a soron
}

if(akt_ertek == '"'){// ha találtam idézőjelet akkor növeljük az értékét
idezodb++;
}

if((akt_ertek != ';' && akt_ertek!= '\n') || idezodb%2 == 1){ //Ha az aktuális elem nem ; és nem is sorvég vagy az idezojelek száma páratlan akkor az átmeneti változóba bekerül az aktuális karakter
cella[j] = akt_ertek;
j++;
}else{
cella[j] = '\0'; //null érték esetén is ezt tárolja
oszlop++;
ptomb[sor] = (char**) realloc(ptomb[sor], oszlop*sizeof(char*)); //oszlop pointerek területének növelése

ptomb[sor][oszlop] = (char*) malloc((strlen(cella)+1) * sizeof(char)); //terület lefoglalása a cellának

strcpy(ptomb[sor][oszlop], cella); // sor oszlop-ba eltárolni az aktuális cellát
printf("%s(%i, %i) \t", ptomb[sor][oszlop],sor, oszlop); //ellenőrzés


if (enter == 1){
szeles[sor] = oszlop;
//szeles[sor] = (int)realloc(szeles,(sor+1)*sizeof(int)); megkérdezni
szeles[sor+1] = (int)malloc(1*sizeof(int));
oszlop=0;
sor ++;
ptomb = (char***) realloc(ptomb, sor * sizeof(char**));
ptomb[sor] = (char**) malloc(1 * sizeof(char*)); //legeső oszlopra mutató létrehozása
printf ("enter \n");
enter = 0;
}
j=0;
strcpy(cella,"");
}
i++;
}

//azért kell mert az utolsó sor végén nincs enter
cella[j] = '\0';
printf("%s(%i,%i)\n", cella, sor, oszlop); //az utolsó elem miatt kell kiíratni
//azért kell mert az utolsó sor végén nincs enter
//sor/oszlop kiiratása
szeles[sor] = (int)malloc(sor*sizeof(int));
szeles[sor] = oszlop+1;
oszlop=0;
sor ++;
printf ("Sor: %i \n", sor);

printf("%p(%i, %i) \n", ptomb[0][0],sor, oszlop); // így működik
printf("%s(%i, %i) \n", ptomb[0][0],sor, oszlop); // így nem


for (i = 0; i<sor; i++){
printf ("%i sor: %i \n", i+1, szeles);
}

return 0;
}
//vége
Mutasd a teljes hozzászólást!
csak a "lényeget" ismétlem:
// ... char ***ptomb; //3D char tombre mutató pointer // ... ptomb[sor][oszlop] = (char*) malloc((strlen(cella)+1) * sizeof(char)); //terület lefoglalása a cellának // ...

"egyébként szbzs.2 nem teljesen értem mire akarsz kilyukadni?! A fordító a mallokkal maga dönt el, hogy hova hivatkozik nem?"

igen, a malloc-cal foglalsz valamekkora helyet, tfh. az sikerül is, azaz kapsz egy "érvényes" memóriacímet, azaz nem NULL-t,

hova is mentsük, írjuk ezt a memóriacímet? a baloldal milyen szintén memóriacímet azonosít, ahol majd "elraktározzuk" az értéket a későbbi hivatkozásokhoz?

a ptomb[sor][oszlop] aktuális értéke kell, hogy meghatározza azt, ugye, és ez "rendben is lehetne", de...

a leírásod/kódod alapján azt látom, hogy tisztában vagy a pointer aritmetikával (legalábbis az alapjaival), és azt szeretnéd itt is használni, azaz "1 dimenzió" esetén, ha van mondjuk egy valamiTípus *s-ed, akkor az s[k] az (s + k) "helyet" azonosítja, ahol a "lépésnagyság" a sizeof(valamiTípus), tehát a *(s + k) az s[k]-val ekvivalens címzés,

ugye ezt szeretnéd itt használni, de nem "1 dimenzióra",

egy "2 dimenziós" tömb esetén az adott elem hol is van?

ugye, ebben az esetben az elemek hasonlóan egymás után helyezkednek el a memóriában, csak az "egyik index mentén kiterítve", azaz pld. a valami t[2][3]; definíció a következő "sorrendet" adja ki: t[0][0] t[0][1] t[0][2] t[1][0] t[1][1] t[1][2],
tehát a t[j][k] címét a t + j * 3 + k adja meg, azaz a 3-ra "szükségünk van", tudnia kell a fordítónak arról, hogy ki tudja számolni az elem "jó" címét,

ha a definícióban nincs megadva a tömbnek ez a kiterjedése (lásd nálad a char ***ptomb-öt) akkor nyilván nem fogja tudni kiszámolni (rosszul fogja számolni?), nem?

azaz szerintem "nem jó" a fenti hivatkozásod, neked kellene számolnod az aktuális sor, oszlop értékeket felhasználva (meg azt is szükséges tudnod, hogy mennyi elem is van egy sorban),
persze ezzel csínján kell bánnod, mert az első sornál (annak a feldolgozása közben) nem tudhatod még, hogy mennyi oszlop is van/lesz abban, továbbá "figyelned" kell arra is, hogy minden sorban ugyanannyi oszlopnak kell szerepelnie,
tudtommal egy helyes csv-ben ez utóbbival nem kell bajlódnod, mert abban garantálva minden sorban ugyanannyi oszlop kerül kiírásra, tehát az üres cellák is kiíródnak (két elválasztó jel között a "semmi", azaz ekkor két elválasztó jel közvetlenül jön majd egymás után, kivéve persze a (sorban) utolsó elemet, mert azt a sorvége jel zárja),

a címszámításhoz "gondolatébresztőnek": Ideone.com

szerintem ez IS lehet a hiba forrása, mivel nem néztem át tüzetesen, ezért csak az "is",

szerintem,


szerkesztés: szerintem ha nem sikerül mégsem dűlőre jutnod, akkor a forrásgomb/<> segítségével illeszd be újra a kódot, és amennyire lehet próbálj meg úgy indentálni, hogy egyértelmű legyen mi-mihez tartozik (bár gondolom az indentálás valójában azért "tűnt el", mert nem forráskódként illesztetted be, és ugye a többlet fehér szóközök egy html-ben "nem játszanak", kivéve ha...),
Mutasd a teljes hozzászólást!

  • Forráskód gomb! Ha nem forráskódként illeszted be, akkor szétcsúszik pl az indexelés, meg eleve egyáltalán nem átlátható..

    Mit értesz az alatt, hogy kifagy a fordító? Le sem fordul? Mi a hibaüzenet?

    Debuggolj:
    1. printf-eket raksz a programodba és látod, hogy meddig jut el.
    2. -g debug opciókkal fodítod és gdb segítségével megnézed, hogy hol száll el
    3. assert-eket helyezel a kódodba, hogy lásd nem-e túlindexelsz valahol..
    Mutasd a teljes hozzászólást!
  • ha te lennél a fordítóprogram, akkor szerinted:
    // ... char ***ptomb; //3D char tombre mutató pointer // ... int sor = 0; //segédváltozó, hány soros a bemeneti adat int oszlop = 0; //segédváltozó, hány oszlop van az aktális sorban // ... // oszlop, sor értéke valamennyi // ... ptomb[sor][oszlop] = (char*) malloc((strlen(cella)+1) * sizeof(char)); //terület lefoglalása a cellának // ...

    a ptomb[sor][oszlop] címét hogyan számolnád ki, mi alapján tudnád meghatározni? azaz honnan tudnád, hogy a ptomb-höz képest hova is hivatkozol?
    Mutasd a teljes hozzászólást!
  • Elnézést a forráskód miatt tényleg be tehettem volna szebben.

    Egyébként printf debugokat végeztem és arra jutottam, hogy a while cikluson belül kiírja az értékeket, ha azon kívül akarom kiíratni, akkor  azt írja ki, bekeres.exe működése leállt. És csak addig fut le a program.

    egyébként szbzs.2 nem teljesen értem mire akarsz kilyukadni?! A fordító a mallokkal maga dönt el, hogy hova hivatkozik nem?
    Mutasd a teljes hozzászólást!
  • csak a "lényeget" ismétlem:
    // ... char ***ptomb; //3D char tombre mutató pointer // ... ptomb[sor][oszlop] = (char*) malloc((strlen(cella)+1) * sizeof(char)); //terület lefoglalása a cellának // ...

    "egyébként szbzs.2 nem teljesen értem mire akarsz kilyukadni?! A fordító a mallokkal maga dönt el, hogy hova hivatkozik nem?"

    igen, a malloc-cal foglalsz valamekkora helyet, tfh. az sikerül is, azaz kapsz egy "érvényes" memóriacímet, azaz nem NULL-t,

    hova is mentsük, írjuk ezt a memóriacímet? a baloldal milyen szintén memóriacímet azonosít, ahol majd "elraktározzuk" az értéket a későbbi hivatkozásokhoz?

    a ptomb[sor][oszlop] aktuális értéke kell, hogy meghatározza azt, ugye, és ez "rendben is lehetne", de...

    a leírásod/kódod alapján azt látom, hogy tisztában vagy a pointer aritmetikával (legalábbis az alapjaival), és azt szeretnéd itt is használni, azaz "1 dimenzió" esetén, ha van mondjuk egy valamiTípus *s-ed, akkor az s[k] az (s + k) "helyet" azonosítja, ahol a "lépésnagyság" a sizeof(valamiTípus), tehát a *(s + k) az s[k]-val ekvivalens címzés,

    ugye ezt szeretnéd itt használni, de nem "1 dimenzióra",

    egy "2 dimenziós" tömb esetén az adott elem hol is van?

    ugye, ebben az esetben az elemek hasonlóan egymás után helyezkednek el a memóriában, csak az "egyik index mentén kiterítve", azaz pld. a valami t[2][3]; definíció a következő "sorrendet" adja ki: t[0][0] t[0][1] t[0][2] t[1][0] t[1][1] t[1][2],
    tehát a t[j][k] címét a t + j * 3 + k adja meg, azaz a 3-ra "szükségünk van", tudnia kell a fordítónak arról, hogy ki tudja számolni az elem "jó" címét,

    ha a definícióban nincs megadva a tömbnek ez a kiterjedése (lásd nálad a char ***ptomb-öt) akkor nyilván nem fogja tudni kiszámolni (rosszul fogja számolni?), nem?

    azaz szerintem "nem jó" a fenti hivatkozásod, neked kellene számolnod az aktuális sor, oszlop értékeket felhasználva (meg azt is szükséges tudnod, hogy mennyi elem is van egy sorban),
    persze ezzel csínján kell bánnod, mert az első sornál (annak a feldolgozása közben) nem tudhatod még, hogy mennyi oszlop is van/lesz abban, továbbá "figyelned" kell arra is, hogy minden sorban ugyanannyi oszlopnak kell szerepelnie,
    tudtommal egy helyes csv-ben ez utóbbival nem kell bajlódnod, mert abban garantálva minden sorban ugyanannyi oszlop kerül kiírásra, tehát az üres cellák is kiíródnak (két elválasztó jel között a "semmi", azaz ekkor két elválasztó jel közvetlenül jön majd egymás után, kivéve persze a (sorban) utolsó elemet, mert azt a sorvége jel zárja),

    a címszámításhoz "gondolatébresztőnek": Ideone.com

    szerintem ez IS lehet a hiba forrása, mivel nem néztem át tüzetesen, ezért csak az "is",

    szerintem,


    szerkesztés: szerintem ha nem sikerül mégsem dűlőre jutnod, akkor a forrásgomb/<> segítségével illeszd be újra a kódot, és amennyire lehet próbálj meg úgy indentálni, hogy egyértelmű legyen mi-mihez tartozik (bár gondolom az indentálás valójában azért "tűnt el", mert nem forráskódként illesztetted be, és ugye a többlet fehér szóközök egy html-ben "nem játszanak", kivéve ha...),
    Mutasd a teljes hozzászólást!
  • Itt nézz szét, hogy hogyan oldják meg és valószínűleg rájössz a hibára :)-

    Dynamic memory allocation for 3D array

    Szerk:
    Talán az is segít, ha papíron lerajzolod magadnak az 1D,2D,s esetet és azt is, amit te csinálsz a bemásolt forrásban :)
    Mutasd a teljes hozzászólást!
  • köszönöm a "kiegészítést", nem néztem át igazán a kódját (mea culpa, mea maxima culpa), feltételeztem, hogy a tömbbel "ekvivalens" megoldást választotta, azaz egy összefüggő területben gondolkodik,

    szerkesztés: bár, egyből le kellett volna essen nekem (a malloc hívásokból), hogy nem így "akarja",
    Mutasd a teljes hozzászólást!
  • köszönöm mindenkinek a segítséget, az elmondottak alapján újraírtam. :)
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd