[c++] Problema di stack overflow

valentino861
Credo ormai abbiate capito che non sono un grandissimo esperto di programmazione ma sto cercando di fare un programmino anche se ogni tanto incappo in qualche errore.
Per esempio ho un programma che fa delle elaborazioni su una variabile e funziona perfettamente, appena ho implementato lo stesso per 3 variabili mi da erore e mi dice stack overflow. Mi sono un pò documentato e ho capito che praticamente satura la memoria di stack.
La soluzione che ho trovato sul web (alla mia portata), e inizializzare parte delle variabili con static in modo di allocare parte della memoria in global.
Giusto?

E' veramente brutto come modo di procedere?

Risposte
valentino861
no cosi non mi funzionava bene, ora ho dichiarato quasi tutte le variabili in globale, cioè fuori dalla funzione e non mi da problemi.

Sono un macellaio?? :oops:

apatriarca
Mostreresti il codice? Qual'era il tipo di queste variabili?

Non dichiarare come globali variabili che non lo sono, solo perché lo stack è troppo piccolo. Gli oggetti molto grossi normalmente si preferisce allocarli dinamicamente. Puoi inoltre aumentare le dimensione dello stack aggiungendo l'opzione del compilatore /F seguita dalla dimensione in Visual Studio.

valentino861
allora le variabili sono di tipo double e d_complex (dalla libreria CLN http://www.vni.com/products/imsl/docume ... ctions.htm).

Saranno una ventina di array da 16384 valori e altrettante variabili poco più piccole.
Dinamicamente quindi con la funzione malloc??

Ma cosa cambia da globale?

apatriarca
Per lavorare con i numeri complessi in C++ puoi fare uso della classe template standard std::complex (http://stdcxx.apache.org/doc/stdlibug/20-2.html).

Ci sono grosse differenze tra dichiarare una variabile globale e allocare localmente gli array dinamicamente. La prima differenza riguarda la posizione in cui vengono allocati. Nel primo caso incidono sulla dimensione della tua applicazione, mentre nel secondo vengono allocati nell'heap. Quale sia il metodo migliore dipende molto da quale sia lo scopo della tua applicazione. Dovrebbero essere 128KB ad array e quindi un totale di 2.5MB. Non è tantissimo per gli attuali standard.
Una differenza più importante riguarda lo scope delle variabili. In un caso sono globali e accessibili da tutte le funzioni della tua applicazione, nel secondo caso solo nelle funzioni e classi che contengono un puntatore a quella memoria. Se ha senso che questi array siano accessibili globalmente, considerando la dimensione della tua applicazione, è perfettamente accettabile la scelta di dichiarare tutto globale. In caso contrario è normalmente preferibile utilizzare la memoria dinamica.

In C++ non si usa più malloc e free ma è preferibile usare gli operatori new e delete (new[] e delete[] per gli array).

valentino861
Bhè in realtà non hanno molto senso dichiarate globalmente perchè mi servono solo all'interno di una funzione. Ora mi studio bene new e delete e vediamo un pò che ne esce.

Per la grandezza dell'applicazione credo sia anche qualcosa di più mi pare stia sui 12MB.

apatriarca
20 array di double di 16384 elementi sono 2.5MB, se ovviamente sono di tipi diversi la dimensione potrebbe essere maggiore. In ogni caso sulla dimensione dell'applicazione incidono molti altri fattori (c'è anche il codice della tua applicazione e di tutte le librerie che vengono linkate staticamente).

Puoi anche provare ad usare la classe std::vector.

valentino861
ok mi sto studiando l'operatore new e delete per allocare dinamicamente gli array ma ho un problema.
Praticamente l'array di valori double poi lo inserisco in una funzione che vuole come input un tipo double, e durante la compilazione mi da errore perchè riconosce l'array come un puntatore e non come un array double....come posso fare?

double *com_accz;
com_accz=new double [MAX_INT];

 for(int i=0;i<MAX_INT;i++)
	{
	 com_accz[i].re=accz[i];
	 com_accz[i].im=0.000000;

}
accfz = imsl_z_fft_complex(MAX_INT,com_accz, 0);

delete [] com_accz;


Ho postato solo il codice di interesse

apatriarca
Ho guardato il prototipo della funzione... Il problema non è nell'uso di puntatori al posto di array (dal punto di vista della funzione le due cose sono equivalenti), ma nell'uso di double al posto di d_complex.

Il seguente dovrebbe funzionare
d_complex *com_accz = new d_complex[MAX_INT];

for (int i = 0; i < MAX_INT; i++) {
    com_accz[i].re=accz[i];
    com_accz[i].im=0.000000;
}

accfz = imsl_z_fft_complex(MAX_INT, com_accz, 0);

delete[] com_accz;

free(accfz); // <- ricordati che devi anche deallocare questo array quando hai finito di usarlo...

valentino861
Che stupido ero convinto che nel prototipo ci fosse un double...ok grazie ora provo

valentino861
scusa ma qui mi da lo stesso problema:

double *x=new double;
//Crea le curve di ponderazione
for(int i=0;i<=MAX_INT;i++)
    {

	 x=i*freq_max/MAX_INT;

	 weight_z[i] = imsl_d_cub_spline_value(x,ppz,0);

    }

delete x;


freq_max è una variabile double. Se dichiaro x come double normale funziona

valentino861
bha a quanto ho capito io questa tecnica di allocazione dinamica va benissimo sugli array invece non è il massimo per le variabili, perche se queste vengono usate da una funzione il programma da errore. Credo che la funzione in ogni caso lo veda come un puntatore, invece se è un array...mmm...array e puntatori sono parenti giusto?!

apatriarca
Ho scritto qualche tempo fa un lungo post sulle relazioni che ci sono tra puntatori ed array (dopo lo cerco e te lo posto). Quando ti ho detto di usare l'allocazione dinamica non volevo dire di usarla per qualsiasi cosa ma solo per gli array che usi. Insomma per le variabile che occupano più spazio Nel caso di una variabile double è meglio non farlo. Quando lavori con i puntatori lavori con un indirizzo di memoria e non con il valore della variabile a cui punti. Quindi per esempio se scrivi p + 1 con p array di double non sommi uno al valore double contenuto nella locazione di memoria a cui punti ma si sposta alla locazione di memoria successiva (nel senso al double successivo). Per modificare il double devi deferenziare il puntatore usando l'operatore * (l'operatore & è invece usato per ottenere un indirizzo):

double *x=new double; 
//Crea le curve di ponderazione 
for(int i=0;i<=MAX_INT;i++) 
    { 

    *x=i*freq_max/MAX_INT; 

    weight_z[i] = imsl_d_cub_spline_value(*x,ppz,0); 

    } 

delete x;

valentino861
Ok grazie.

Per ora va bene cosi ho messo tutti gli array da 16384 valori double allocati dinamicamente quindi penso di aver fatto un buon lavoro, qualche variabile (i non array) rimasti li ho lasciati in globale e via.

Ma quanta memoria c'è nello heap che non ho capito? C'è un modo per vederlo?

apatriarca
Era questa la discussione: http://www.matematicamente.it/forum/2-es-puntatori-t37018.html

Di memoria ne hai più o meno quanta è a disposizione sul tuo PC. Puoi allocare anche array molto grossi senza problemi (per esempio di qualche centinaia di MB). Non lasciarli in globale, sono locali alla funzione e quindi vanno allocati nello stack come immagino facessi all'inizio. Quindi semplicemente:
{
double x;

// qui usi la variabile

}
// qui ha cessato di esistere

valentino861
Ho provato a rimettere tutte le variabili nella funzione ma ancora sono troppe e mi da sempre problemi di stack.
Provo a usare new anche su variabili non array vediamo se ci riesco

valentino861
anche se ora non mi da come errore stack overflow ma :

Eccezione non gestita a 0x3fb05288 in unione.exe: 0xC0000005: Violazione di accesso nella lettura del percorso 0x3fb05288.

apatriarca
Si tratta di un errore diverso con causa sicuramente molto diverse. Prova ad usare il debug in modo da capire in che funzione viene lanciata questa eccezione e scrivi il codice di quella funzione. Si tratta probabilmente in un errore nell'uso dei puntatori. Hai cercato di accedere oltre i limiti di qualche array secondo me.

valentino861
si si esatto, avevo fatto un array troppo piccolo.

Ok ora ho messo quasi tutte le variabili nella funzione allocandole dinamicamente...finalmente sto capendo qualcosa di c++.

Sto anche capendo che la mia funzione è decisamente troppo grande e che potrei benissimo suddividerla in minimo 5-6 funzioni diverse. MA a parte l'ordine che potrei dare al programma posso avere dei benefici a suddividere la funzione in tante più piccole?

apatriarca
I vantaggi sono "solo" nella maggiore semplicità di gestione e manutenzione. D'altra parte se crescono troppo diventano poco gestibili. Quando si progetta un'applicazione si cerca di trovare il giusto compromesso tra numero di funzioni e loro lunghezza. In generale una funzione dovrebbe svolgere una singola operazione. Se nella tua funzione puoi "vedere" diverse parti allora può valer la pena di creare delle nuove funzioni.

valentino861
ci sono una decina di parti diverse....ehehehhe.

Ma la memoria di stack è del programma o di ogni singola funzione?

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.