Newsgroup: it.comp.lang.c++
Titolo: creazione di un array bidimensionale sullo heap

Salve a tutti,
sto provando a creare un array di array totalmente sullo heap ma
ho qualche difficoltï¿œ: il codice compila ma in esecuzione dï¿œ
segmentation fault.
 
il cuore del codice ï¿œ il seguente:
n ed m vengono iseriti da console via cin.
 
    int ** array = 0;
 
     try
     {
         *array = new int[n];
 
 
 
     }
     catch(...)
     {
         cout << "Errore di allocazione,"
                 " memoria non disponibile." << endl;
     }
 
     try
     {
         for(int i=0; i < n; i++)
         {
             array[i] =  new int[m];
         }
     }
     catch(...)
     {
         cout << "Errore, di allocazione"
                 " memoria non disponibile." << endl;
     }

 int ** array = 0;
 
È *MALE* 
 
I puntatori non si inizializzano!
 
Qui dichiari un puntatore ad un puntatore che punta alla celle
di memoria con indirizo nullo; dove sia questa cella nessuno 
lo sa. Potenzialmente hai un baco di proporzioni colossali.
Il Segmentaton fault è la cosa migliore che ti possa accadere.
 
PS Ricordi come è implementato NULL?


 
Non vorrei sbagliarmi, ma per default new ritorna NULL se non riesce ad 
allocare
 
in C++ 98:
The default definition allocates memory by calling the nothrow version 
of operator new: ::operator new (size,nothrow).
If replaced, both operator new and operator new[] shall return pointers 
with identical properties.
 
in C++11:
  The default definition allocates memory by calling the the first 
version: ::operator new[] (size).
 
 
http://www.cplusplus.com/reference/new/operator%20new%5B%5D/
 
 
 

          *array = new int[n];
Qui stai dereferenziando il puntatore array, che al momento ï¿œ null (0). 
Deve essere:
 
array = new int*[n];
 
 
S.
 

 allocare
Di default la new solleva un'eccezione di tipo std::bad_alloc se non 
riesce ad allocare. Se vuoi usare la versione che *non* solleva 
l'eccezione (e che restituisce null in caso di fallimento) la devi 
chiamare esplicitamente:
 
int* p = new (std::nothrow) int*[10];
 
S.
 

 segmentation fault.
 
Perdona la curiositï¿œ, ma stai provando a scopo didattico?
Perchï¿œ nel complesso non vedo proprio nessun caso d'uso valido a
giustificare il codice che stai tentando di scrivere.
 


In questo caso l'inizializzazione del puntatore era inutile, però non è 
certo un problema inizializzare un puntatore a NULL o 0 (nullptr in 
C++11). Il problema è l'uso che si fa del puntatore nullo. Se lo si 
dereferenzia, cosa che accadeva in questo caso, è undefined behavior, se 
gli assegni un valore il codice è corretto.
 
S.


Non ho studi di informatica, sono autodidatta. Spiegami tu come è
implmentato il NULL così imparo qualcosa di nuovo
 
grazie


Certo che ï¿œ didattico, ï¿œ un limite che non ho ancora raggiunto e
superato e sto cercando di affrontarlo. Voi siete tutti dottori,
io da autodidatta ho studiato solo sui tutorial e un paio di libri
sul C++.
 
 


grazie mille,
adesso il codice funziona. Ecco dove era il maledetto errore. Io 
anzicchè allocare n interi devo allocare n puntori ad intero.
E dereferenziavo il puntatore inizializzato a 0.
 
Già che sono qui mi consigli qualche lettura che possa aiutarmi?
Il livello può essere elevato perchè non sono messo poi così male.
Ad esempio ho a disposizione il libro di Stroustrup
programming principles and practice ma vorrei imparare anche qualche
atro altro aspetto più tecnico della programmazione.
Pensa che iniziai ad avere un approccio con il compilatore solo
alla facoltà di chimica e allora, era il 1997 mi avevano insegnato
[e io avevo imparato male] in un corso di appena 4 mesi il FORTRAN 77.
Però fu amore a prima riga. Da lì venni a conoscenza di Java, solo
che non essendo ancora capace di pensare ad oggetti [e non sono
ancora molto capace a dirla tutta], decisi di imparare il C.
Poi dopo aver fatto un pratica per qualche anno, ho deciso di
imparare C++.
 
ancora grazie,
 

 gli assegni un valore il codice è corretto.
 
 
E questo è il vero punto. Non ha senso assegnare un valore ad un puntatore
tranne in casi particolari (per esempio NULL) e usarlo senza assegnarlo ad 
una area allocata. Questo è il vero errore.
 
Nell'esempio dell'OP poi, non si capiva neanche cosa voleva fare, un 
esercizio senza nè capo nè coda.

 implmentato il NULL così imparo qualcosa di nuov
 
http://lmgtfy.com/?q=C%2B%2B+NULL+POINTER
 

 }
 
 
-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)
 

 Matrice [3][5] = 2;
 
qui parte un'eccezione non gestita.
Sono ancora perplesso che compilasse, ma che doveva esserci 
qualche rogna mi era stato chiaro da subito. PEccato che 
emerga solo a runtime. Boh.


 SERGIO, laddove suggerisce :
 
Sergio ha corretto il mio errore: io dichiaravo un doppio puntatore
 
int array **;
 
poi allocavo erroneamente la prima dimensione dell'array non come 
puntatore a (int *) ma semplice puntatore ad int
e in piï¿œ dereferenziavo nella mia grafia un array inizializzato a null 
[cosa che ï¿œ buona e giusta].
 
*array = new int[n];
 
successivamente io correttamente allocavo ogni posizione della prima
dimensione dell'array ad array di m colonne.
 
for(int i=0; i < n i++)
{
     array[i] = new int[m];
}
 
dove n ï¿œ il numero di righe e m il numero di colonne.
 
Ti posto il codice che ho scritto cosï¿œ ci dai un'occhiata:
 
Ciao.
 
PS quando passi un array a funzione puoi dichiarare tutte le
dimensioni tranne la prima che ï¿œ opzionale perï¿œ non ho mai capito il 
perchï¿œ :o)
 
#include <iostream>
#include <climits>  // utilizzato per LONG_MAX
#include <cstdlib>  // utilizzato per srand e rand
#include <ctime>    // utilizzato per time()
 
using std::cout;
using std::cin;
using std::endl;
 
void stampa_array(int **, int, int);
void inizializza_array(int **, int, int);
 
int main()
{
     int n = 0;
     int m = 0;
 
     // imposta il seme del random
     // utilizzando l'ora corrente
 
     srand(time(0));
 
     cout << "Inerisci la dimensione dell'array: ";
 
     // la procedura che segue permette di controllare
     // un input errato
 
     while((cin >> n) == 0 )
     {
         cin.clear();
         cin.ignore(LONG_MAX,'\n');
 
         // a rigore dovrei usare
         // cin.ignore(numeric_limits<streamsize>::max() ,'\n')
         // ma il mio compilatore non
         // lo supporta ancora
 
         cout << "Per favore reinserisci: ";
     }
 
      cout << "Inerisci la seconda dimensione dell'array: ";
 
     // la procedura che segue permette di controllare
     // un input errato
 
     while((cin >> m) == 0 )
     {
         cin.clear();
         cin.ignore(LONG_MAX,'\n');
 
         // a rigore dovrei usare
         // cin.ignore(numeric_limits<streamsize>::max() ,'\n')
         // ma il mio compilatore non
         // lo supporta ancora
 
         cout << "Per favore reinserisci: ";
     }
 
     int ** array = 0;
 
     try
     {
         array = new int * [n];
     }
     catch(...)
     {
         cout << "Errore di allocazione,"
                 " memoria non disponibile." << endl;
     }
 
     try
     {
         for(int i=0; i < n; i++)
         {
             array[i] =  new int[m];
         }
     }
     catch(...)
     {
         cout << "Errore, di allocazione"
                 " memoria non disponibile." << endl;
     }
 
     inizializza_array(array, n, m);
     stampa_array(array, n, m);
     // da implementare il rilascio della memoria
 
     return 0;
}
 
void stampa_array(int ** array_p, int N_sz, int M_sz)
{
     for(int i=0; i < N_sz; i++)
     {
         for(int j=0; j< M_sz; j++)
         {
             cout << array_p[i][j] << " ";
         }
         cout << endl;
     }
 
     cout << endl;
}
 
void inizializza_array(int ** array_p, int N_sz, int M_sz)
{
     for(int i=0; i < N_sz; i++)
     {
         for(int j=0; j < M_sz; j++)
         {
             array_p[i][j] = (rand() % 10);
         }
     }
}
 
 

 
 
In C NULL può avere qualsiasi valore, in C++ è sempre uguale a 0.
 
Ciao!

 ... NULL  ...  in C++ è sempre uguale a 0.
 
Ok, prendo nota.
 

 sul C++.
 
Mi sembra strano, Con (buoni) tutorial e un paio di libri sul C++ (letti 
dall'inizio alla fine) dovresti avere imparato una cosa fondamentale: 
evitare ove possibile di usare i puntatori "grezzi" come in C. La 
libreria C++ oggi offre std::shared_ptr<> o std::unique_ptr<> al loro 
posto (anche la buonanima di std::auto_ptr<> faceva in molti casi il suo 
dovere), dovrebbero ridurre quello che hai scritto a 3 o massimo 4 
righe, rendendolo oltretutto il codice più sicuro.
 

 massimo 4 righe, rendendolo oltretutto il codice piï¿œ sicuro.
 
mi farebbe veramente piacere se mi consigliare qualcosa da leggere
 
graie


verbo consigliare a parte ti ringrazio
 
ciao


 
 


 
 
Non sto seguendo il post e non entro in merito di tutti i commenti, ma mi è
saltata all'occhio questa frase.
Uno dei problemi ricorrenti nelle spiegazioni di dynamic programming è la
giustificazione del testo; di solito si portano in esame gli algoritmi dei
vecchi microsoft word (che usavano un algoritmo greedy) e del più comune
compilatore latex (che usa un algortirmo DP).
In ogni caso il testo in un documento è un array di parole (o, se si fa un
break ogni paragrafo, un array di paragrafi).
Quindi no, solitamente un file di testo non utilizza un array sparso (se non
per problemi di prestazioni su file enormi), ma un array monodimensionale
indicizzato. :-)
 
Ciao!

 mi farebbe veramente piacere se mi consigliare qualcosa da leggere
 
Altrove hai detto di avere lo Stroustrup, suppongo la terza edizione.
Quindi ricomincia da lì per capire cosa è uno smart pointer e perchè è
utile: capitolo 14.4. Poi vedi cosa sono i nuovi shared/unique_ptr di
C++11, puoi rifarti all'ultima edizione di Josuttis per quelli o aspetti
la quarta edizione dello Stroustrup che esce uscirà a giorni.
 

 Ciao!


 
 
Bah, su questo... parliamone.
 
Facciamo conto sia una implementazione dei due casi quasi ingenua: l'inserire
una parola in un array monodimensionale comporta una copia di parte dell'array,
se hai un array di linee di lunghezza fissa comporta comunque di spostare le
parole eccedenti alla riga sotto, in cascata fino alla fine.
 
Se, come avevo accennato, fai break ad ogni paragrafo, puoi avere un array
(adesso sì, anche sparso) di parole, ma anche perché no di linee, e gestire
la cosa in maniera più efficiente.
 
La differenza tra la sequenza di parole e la sequenza di linee è solo per
la gestione della formattazione della linea stessa, cosa che ogni editor
di testo visuale cerca di fare.
 
Non ho mai implementato nulla del genere per cui vado a naso e per sentito
dire, però direi che più o meno ha un senso..
 
Ciao!

 Ciao!
 
 



OK,allora probabilmente era per le vecchie versioni del c++, quelle 
prima del c++98
 

 Ciao!
 
 
Ciao   Manlio