Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Recensione Lenovo Idea Tab Plus: il tablet da 12 pollici che costa meno di 300 euro
Recensione Lenovo Idea Tab Plus: il tablet da 12 pollici che costa meno di 300 euro
Lenovo Idea Tab Plus prova a portare un display da 12,1 pollici 2.5K, quattro speaker Dolby Atmos e una batteria da 10.200 mAh sotto la soglia psicologica dei 300 euro, penna inclusa. Lo abbiamo usato per oltre una settimana per capire dove l'azienda ha tagliato e dove invece ha tenuto il punto
Oltre il contante e le crypto: tutto sull'Euro Digitale e la nuova sovranità monetaria europea
Oltre il contante e le crypto: tutto sull'Euro Digitale e la nuova sovranità monetaria europea
L'euro digitale è una valuta fiat che entrerà in vigore nei prossimi anni. L'obiettivo principale è quello di ridurre la dipendenza dalle piattaforme di pagamento digitali statunitensi e offrire ai cittadini un modo semplice per trasferire denaro. Anche offline, anche in maniera (pseudo)anonima
Recensione HONOR Magic V6: spessore record e super batteria. È lui il fold da battere?
Recensione HONOR Magic V6: spessore record e super batteria. È lui il fold da battere?
HONOR Magic V6 è arrivato in Italia a 2.299,90 euro con una promessa precisa: unire 4 mm di spessore da aperto (8,75 mm chiuso nel modello White, 9 mm negli altri colori) a una batteria da 6.660 mAh, la più capiente mai vista su un pieghevole. Lo abbiamo usato per oltre una settimana in versione Red 16/512 GB per capire se lo Snapdragon 8 Elite Gen 5 tiene testa alla concorrenza anche fuori dai benchmark ufficiali
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 22-01-2014, 10:17   #1
sharkkk
Member
 
L'Avatar di sharkkk
 
Iscritto dal: Oct 2013
Messaggi: 158
[C] liste dinamiche

Passo passo sto cercando di comprendere a fondo l'utilizzo dei puntatori e mi sono imbattuto in questo codice elementare.
Ma cosa fa esattamente passo per passo?

Codice:
typedef struct lista{
       int val;
       struct lista* next;
       } LIST;

int main(){...

    LIST* element;
     element = (LIST*)malloc(sizeof(LIST));


LIST* element;
- Creo un puntatore di tipo LIST, che ha un valore casuale e che non punta a nulla.

element = (LIST*)malloc(sizeof(LIST));
- malloc(sizeof(LIST)) alloca tanta memoria per element tanta quanto ne occupa il tipo LIST
- element = (LIST*)malloc(sizeof(LIST)); fa un cast al tipo LIST* perchè element è di tipo LIST*

Le domande sono:
a) Quello che ho scritto è giusto?
b) Ma in quale punto creo una nuova istanza di tipo LIST in cui posso già accedere agli elementi della struttura?
c) perche devo fare la malloc se faccio LIST* element? con questa dichiarazione element non è già grande quanto LIST?


p.s.
LIST* testa;
testa = NULL;

testa = NULL; imposta tutti gli elementi della struttura a NULL oppure il puntatore non punta piu ad una struttura ma solo a NULL?



grazie a chiunque mi aiuterà
sharkkk è offline   Rispondi citando il messaggio o parte di esso
Old 22-01-2014, 10:37   #2
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Ciao,
a) la descrizione che hai dato è giusta;
b) la domanda non ha una risposta soddisfacente, nel senso che LIST è una struttura, ovvero una definizione di come sono organizzati i dati in memoria, il concetto di istanza è legato alla programmazione ad oggetti, anche se spesso viene utilizzato in modo improprio. La funzione malloc alloca la memoria necessaria, poi, facendo il casting del puntatore, istruisci il programma a trattare quell'area di memoria come se vi si trovasse una struttura LIST.
c) LIST* alloca solo lo spazio per un puntatore, lo spazio per la struttura va allocato separatamente, o con malloc, oppure dichiarando la variabile con LIST (senza asterisco), però tieni presente che sono due operazioni diverse e non sempre interscambiabili (la prima alloca nell'heap, la seconda sullo stack).

In fine, testa = NULL imposta la variabile testa - che è un puntatore - a NULL; se prima puntava a qualche elemento, questo resterà allocato in memoria, disperso (ma non diventa NULL, e mai potrebbe farlo, e solo memoria).
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 22-01-2014, 10:42   #3
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Ora che ci penso, sarebbe meglio dire che il programma è già istruito a trattare element come una LIST; assegnando a element un'indirizzo, indichi al programma dove si trova la memoria da utilizzare quando accedi ai campi di element.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 22-01-2014, 11:04   #4
sharkkk
Member
 
L'Avatar di sharkkk
 
Iscritto dal: Oct 2013
Messaggi: 158
grazie daniel

quindi scrivere
LIST* element; oppure void* element ipoteticamente a questo livello sarebbero la stessa cosa visto che non stanno puntando a nulla?

penso di aver capito che il primo puntatore, con la malloc, eredita la dichiarazione di LIST, tramite cui posso accedere agli elementi della struttura (con il dovuto cast).

pero ho visto un esercizio di un professore e lui senza fare la malloc o la new, in una funzione, accede ai campi di un puntatore a struttura. (il programma funziona correttamente, C++)

Codice:
//Funzione che crea una lista di n interi prendendoli da tastiera
lista* crea_lista(int n){
	lista *l,*aux;
    lista *root=NULL;
    cout<<"Inserire "<<n<<" interi crescenti \n";
    for (int i=0; i<n; i++) {
        aux= new lista;
        if (root==NULL)
        	root=aux;
        else
        	l->next=aux;
        l=aux;
        cin>>l->val;
        l->next=NULL;
    }
    return (root);
}
aux correttamente viene allocato ma l no, eppure lui accede al campo next (l->next=aux;)
come fa?
sharkkk è offline   Rispondi citando il messaggio o parte di esso
Old 22-01-2014, 11:17   #5
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
LIST* element e void* element hanno lo stesso effetto in termini di memoria, ovvero allocano 4 byte (8 su sistemi a 64 bit) per un puntatore, naturalmente il compilatore si arrabbia di brutto se dichiari element come void* e poi scrivi element.next

malloc alloca solo memoria, il casting in questo caso serve per evitare che un programmatore inesperto o distratto faccia in modo inconsapevole assegnazioni tra dati di tipo diversi. Il compilatore tratta element come LIST anche se non gli assegni un indirizzo allocato con malloc. Ovviamente questo comporta l'accesso ad aree di memoria protette o peggio, dove sono conservati altri dati, facendo crashare il programma. L'assegnazione di un indirizzo valido ad element serve per riservargli uno spazio che non sia già utilizzato o che potrebbe essere utilizzato in futuro.

aux= new lista; alloca spazio per un elemento lista e assegna l'indirizzo ad aux;
l=aux; assegna ad l lo stesso indirizzo di aux, pertanto l punta alla stessa area di memoria allocata in precedenza;
if (root==NULL) questa condizione assicura che l'accesso al campo next attraverso il puntatore l avvenga solo alla seconda iterazione, per cui l è già stato inizializzato con un indirizzo valido.

Ultima modifica di Daniels118 : 22-01-2014 alle 11:20.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 22-01-2014, 11:29   #6
sharkkk
Member
 
L'Avatar di sharkkk
 
Iscritto dal: Oct 2013
Messaggi: 158
Quote:
Originariamente inviato da Daniels118 Guarda i messaggi
aux= new lista; alloca spazio per un elemento lista e assegna l'indirizzo ad aux;
l=aux; assegna ad l lo stesso indirizzo di aux, pertanto l punta alla stessa area di memoria allocata in precedenza;
if (root==NULL) questa condizione assicura che l'accesso al campo next attraverso il puntatore l avvenga solo alla seconda iterazione, per cui l è già stato inizializzato con un indirizzo valido.
mi ero lasciato sfuggire che quell'else avveniva nella prima iterazione


credo di aver capito per bene tutto anche se ora con questa cosa mi hai mandato in panico

Quote:
Il compilatore tratta element come LIST anche se non gli assegni un indirizzo allocato con malloc.
se la malloc è facoltativa, quindi LIST* element basterebbe da solo per ereditare la dichiarazione della struttura (e farci tutte le operazioni)?
a questo punto void* element farebbe la medesima cosa?



p.s.
un mio professore tempo fa disse che il primo elemento di un array, il primo elemento di una struttura, una funzione sono in realtà dei puntatori, è esatto?
anche le classi?

Ultima modifica di sharkkk : 22-01-2014 alle 11:40.
sharkkk è offline   Rispondi citando il messaggio o parte di esso
Old 22-01-2014, 11:42   #7
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
malloc non è facoltativa, semplicemente se non la usi il compilatore non ti da errore, ma quando esegui il programma ottieni risultati imprevedibili e comunque non desiderabili. Al posto di malloc potresti utilizzare new, ma una delle due la devi utilizzare comunque.
C'è una terza possibilità, ovvero quella di allocare un LIST invece di un LIST*, ma non è la stessa cosa rispetto agli altri due metodi. Se ti interessa approfondire questo aspetto chiedilo esplicitamente.

LIST* element; basta a far capire al compilatore che element è un puntatore ad un area di memoria e che element ha dei campi definiti come indicato in "typedef struct lista".
LIST* element; basta anche ad allocare lo spazio sufficiente per un puntatore, che nel nostro sorgente chiameremo element.
LIST* element; non alloca la memoria necessaria per una struttura di tipo LIST; per quello bisogna usare malloc o new.
void* element; fa la stessa cosa di LIST* element; ma poi il compilatore non saprebbe che element ha dei campi chiamati val e next, quindi ti darebbe errore se provassi ad accedervi tramite element.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 22-01-2014, 11:58   #8
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Per puntatore si intende una variabile che non contiene direttamente un dato utile all'elaborazione, ma indica il luogo dove si trova questo dato (o un altro puntatore).
Qualunque dato risiede in memoria, e pertanto ha un indirizzo. Tu puoi definire un puntatore e farlo puntare a qualunque indirizzo. Puoi anche valorizzare un puntatore in modo che punti nel mezzo di una struttura.

Quello che probabilmente ti ha detto il tuo professore è che:
il puntatore ad un array punta al primo elemento in quell'array;
il puntatore ad una struttura punta al primo campo in quella struttura;
il puntatore ad una stringa punta al primo carattere in quella stringa.

Una funzione è una porzione di codice che risiede in memoria, quindi ha un indirizzo, di conseguenza un puntatore potrebbe puntare ad una funzione. I puntatori a funzioni vengono utilizzati per chiamare le funzioni dinamicamente; l'utilizzo più comune ed ignorato dei puntatori a funzione in ambiente windows è la registrazione della callback per la gestione dei messaggi, indispensabile per la creazione delle finestre.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 22-01-2014, 12:02   #9
sharkkk
Member
 
L'Avatar di sharkkk
 
Iscritto dal: Oct 2013
Messaggi: 158
Quote:
Originariamente inviato da Daniels118 Guarda i messaggi
malloc non è facoltativa, semplicemente se non la usi il compilatore non ti da errore, ma quando esegui il programma ottieni risultati imprevedibili e comunque non desiderabili. Al posto di malloc potresti utilizzare new, ma una delle due la devi utilizzare comunque.
C'è una terza possibilità, ovvero quella di allocare un LIST invece di un LIST*, ma non è la stessa cosa rispetto agli altri due metodi. Se ti interessa approfondire questo aspetto chiedilo esplicitamente.

LIST* element; basta a far capire al compilatore che element è un puntatore ad un area di memoria e che element ha dei campi definiti come indicato in "typedef struct lista".
LIST* element; basta anche ad allocare lo spazio sufficiente per un puntatore, che nel nostro sorgente chiameremo element.
LIST* element; non alloca la memoria necessaria per una struttura di tipo LIST; per quello bisogna usare malloc o new.
void* element; fa la stessa cosa di LIST* element; ma poi il compilatore non saprebbe che element ha dei campi chiamati val e next, quindi ti darebbe errore se provassi ad accedervi tramite element.
ora mi hai tolto ogni dubbio.

ho letto, e credo di aver capito che es. LIST element non si usa molto nei casi in cui abbiamo bisogno di usare e rimuovere strutture, perche occuperemmo memoria inutile sullo stack, mentre tramite LIST* element dinamicamente posso allocare/liberare lo spazio occupato in memoria (nello heap invece che sullo stack) dalla struttura

Ultima modifica di sharkkk : 22-01-2014 alle 12:05.
sharkkk è offline   Rispondi citando il messaggio o parte di esso
Old 22-01-2014, 12:22   #10
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Una precisazione: dichiarare una variabile (o un puntatore) ha sempre effetti diversi a seconda che lo si faccia in una funzione o all'esterno.
Nel primo caso lo spazio per la variabile viene allocato nello stack e deallocato all'uscita dalla funzione: se la funzione non viene mai richiamata, quella variabile non occuperà mai spazio; nel caso di funzioni ricorsive la "stessa" variabile può essere allocata più volte contemporaneamente in memoria.
Nel secondo caso, la variabile finisce nell'area dati, che si trova fisicamente nel file eseguibile e quindi contribuisce alle sue dimensioni; queste variabili esistono per tutta l'esecuzione del programma, anche se non vengono utilizzate.

Il motivo principale per cui non vediamo spesso strutture allocate direttamente sullo stack è che esso è un'area abbastanza piccola e allocarvi una struttura (che può avere anche molti campi) può facilmente saturarlo, producendo un errore di stack overflow. Per lo stesso motivo array con molti elementi vengono sempre allocati con malloc invece che dichiararli con la dimensione tra parentesi quadre.
Ci sono poi delle vere e proprie esigenze, come far persistere la variabile all'uscita di una funzione; in questo caso è d'obbligo l'allocazione nell'heap, perchè lo stack viene sempre liberato al return.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
Old 22-01-2014, 12:30   #11
sharkkk
Member
 
L'Avatar di sharkkk
 
Iscritto dal: Oct 2013
Messaggi: 158
a questo punto allora daniele la domanda è d'obbligo, lo stack generalmente che dimensioni ha?

immaginandosi un giorno di trovarsi davanti ad un progetto importante, presumo che questa domanda sia particolarmente importante.

la sua dimensione dipende dalla macchina, è possibile aumentare lo spazio di memoria riservato allo stack, come è possibile sapere la sua dimensione?
sharkkk è offline   Rispondi citando il messaggio o parte di esso
Old 22-01-2014, 13:16   #12
Daniels118
Senior Member
 
L'Avatar di Daniels118
 
Iscritto dal: Jan 2014
Messaggi: 852
Parlando di PC, lo stack è parte della memoria e per questo può essere dimensionato dal programma stesso.
Nei sistemi Windows la dimensione dello stack per il thread principale di un programma è specificata nell'header del file eseguibile e può essere modificata inserendo gli opportuni parametri in fase di link; la dimensione predefinita è 1 MB, che è più che sufficiente anche per progetti importanti, basta che non allochi strutture enormi sullo stack. Per i thread secondari avviati con CreateThread è possibile specificare una dimensione diversa o quella predefinita.

Per i sistemi Unix non so, ma suppongo ci sia qualcosa di simile.

Per completezza aggiungo che molti microcontroller hanno uno stack hardware che ovviamente non può essere ingrandito.
Daniels118 è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Recensione Lenovo Idea Tab Plus: il tablet da 12 pollici che costa meno di 300 euro Recensione Lenovo Idea Tab Plus: il tablet da 12...
Oltre il contante e le crypto: tutto sull'Euro Digitale e la nuova sovranità monetaria europea Oltre il contante e le crypto: tutto sull'Euro D...
Recensione HONOR Magic V6: spessore record e super batteria. È lui il fold da battere? Recensione HONOR Magic V6: spessore record e sup...
Redmi Pad 2 9.7: ampio display, economico e peso contenuto, ma qualche limite nelle prestazioni Redmi Pad 2 9.7: ampio display, economico e peso...
Peugeot Polygon Concept: ecco il futuro delle utilitarie Peugeot Polygon Concept: ecco il futuro delle ut...
Anthropic, approvato in via definitiva i...
Cornici ancora più ridotte su iPh...
Samsung lancia la Galaxy Card con cashba...
Dal 2 agosto entrano in vigore nell'UE l...
Vicino a Parma il parcheggio dimenticato...
Sony Music fa la guerra a Udio: contesta...
Telegram integrerà un portafoglio...
Il debito nascosto dei giganti tech dell...
Amazon dà il via libera alla seri...
Addio crisi dell'elio-3? Questa tecnolog...
Google Pixel 10a a 399€ e crolla anche i...
Haier I-Pro Serie 3 a 359€: la lavatrice...
Claude Code ora collauda le app iOS da s...
Unity mostra per la prima volta un gioco...
Fotonica programmabile: un chip sudcorea...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 11:37.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Served by www3v