Salve ragazzi, oggi girovagando per il forum ho visto una discussione che parla di come convertire un float per poterlo memorizzare su una EEPROM, si è arrivato a parlare di puntatori di una variabile.
Ho cercato su internet e sono arrivato a questo link: http://www.bo.cnr.it/corsi-di-informatica/corsoCstandard/Lezioni/19Puntarray.html
Ma non ho capito molto! Qualcuno è in grado di spiegarmi cosa sia un puntatore ad una variabile e a cosa serva?
Ciao Xfox, devi dotarti di un compilatore c/c++ (o un ide) per sperimentare i puntatori, perchè è molto facile confondersi se non puoi vedere i valori che contengono le variabili puntatore.
Sostanzialmente quel link è un buon punto di partenza, ti manca sapere scrivere un programma i C, che possa essere avviato sul tuo sistema, ti manca anche sapere come visualizzare il contenuto delle tue variabili.
Immagina di avere tanti cassettini che contengono un dato, i cassettini (celle di memoria) sono numerati.
Quando scrivi "int i = 100;" il compilatore trova un cassettino vuoto (es il cassettino n°1000) e ci mette dento il numero 100. Quindi il valore 100 si trova nella cella di memoria n°1000.
posso usare una variabile per salvare l'indirizzo di memoria (1000)? Si
int i = 100;
int ptr_i = &i;
L'operatore & estrae l'indirizzo della cella in cui è allocata la variabile "i".
Solo che ptr_i dove essere dichiarate per una variabile di tipo puntatore ad tipo "int"
e quindi scrivi;
int *ptr_i;
L'asterisco serve in questo contesto a dichiarare una variabile puntatore.
Per gli array il nome dell'array e già un puntatore al tipo, sapendo che il tipo è unsigned char, che è ampio 8 bit, il compilartore ricava la quantita di memoria per l'array moltiplicando la dimenzione del tipo X il numero di elementi che ha specificato.
Ciao.
Xfox:
Salve ragazzi, oggi girovagando per il forum ho visto una discussione che parla di come convertire un float per poterlo memorizzare su una EEPROM, si è arrivato a parlare di puntatori di una variabile.
Ho cercato su internet e sono arrivato a questo link: Puntatori ed Array CPP
Ma non ho capito molto! Qualcuno è in grado di spiegarmi cosa sia un puntatore ad una variabile e a cosa serva?
È una differenza come le scarpe sui piedi e sapere dove le hai lasciate ieri.
La variabile é in valore memorizzato nella "locazione di memoria" della variabile
Un puntatore dice quale in quale "locazione di memoria" é scritto il valore della variabile.
Ciao Uwe
flameman:
una volta non esistevano linguaggi di alto livello
e nemmeno la distinzione netta fra variabile e puntatoreuna volta, prima del linguaggio C, si usavano solo puntatori
e cosa sono questi oggetti tanto temuti ?
sono un costrutto, una assunzione
del tutto astratta per il linguaggio assembler
(che altro non conosce che indirizzi e dati)ma questa assunzione, utile per gli umani che preferiscono scrivere ad alto livello
sono cio' che un linguaggio ad alto livello utilizza per considerare
l'indirizzo di una zona di memoria dove e' contenuto qualcosa di interessantequindi si assume che un puntatore non sia un dato
ma che sia un indirizzo che punta ad un datoil concetto sembra una inutile complicatume
in realta' ha delle giustificazioni pratiche
che potrei sintetizzare in
per come sono fatte le funzioni
e' grazie ai puntatori che si possono passare varibili il cui contenuto debba essere modificatonon fosse cosi' si sarebbe costretti a far impilare sullo stack tutta la strutturona della variabile modificata
cosi' da recuperarlatypedef struct
{
uint32_t real;
uint32_t imm;
} complex_t;complex_t add(complex_t a, complex_t b)
{
complex_t c;c.real=a.real + b.real;
c.imm=a.imm + b.imm;return c;
}piuttosto che:
void add(complex_t a, complex_t b, complex_t* c)
{
c->real=a.real + b.real;
c->imm=a.imm + b.imm;
}inutile dire: (1) bello dal punto di vista stilistico, una porcata dal punto di vista pratico
(e tanto + porcta tanto + e' grossa la struttura da passare indietro
xke' son tutti byte che frullano sullo stack
con buona pace per le performance)anche le variabili sono un indirizzo, a voler sindacare
la label con cui si identifica una variabile altro non e' che un indirizzo per il compilatore
un indirizzo che ora pero' e' riferito ad un contesto (global, local)mi spiego meglio:
le variabili definite all'interno di una function sono un indirizzo relativo
relativo allo spazio dati di quella function
(concetto di variabile locale, indirizzamento relativo, la cu base e' lo stack pointer)le variabili definite globali sono invece un indirizzo assoluto
un puntatore definito in una function non ha il concetto di indirizzo relativo
puntera' sempre e comunque ad un oggetto con indirizzamento assolutoe questa e' una prima differenza
ma cosa differenzia allora una variabile da un puntatore
a parte il ruolo che abbbiamo appena visto avere nel passaggio di parametri nelle functio
e a parte la diversa sintassi ?beh, a parte questo, c'e' che:
uint_32_t var_integer; /* dichiarazione di una variabile /
uint_32_t p_var_integer = &var_integer; /* dichiarazione del puntatore che punta alla variabile */questo esempio chiarisce quanto c'e' da sapere
ovveroil grosso del concetto e' che
dichiarando una variabile
il compilatore gli riserva automaticamente uno spazio all'interno dell'are dati
uint32_t riserva 4 byte e associa l'indirizzo del primo byte a var_integerdichiarando un puntatore, invece
il compilatre non riserva nulla
semplicemente viene istruito il namespace (ecco qui cosa intendo con assunzione, costrutto)
che ad una data label (p_var_integer) e' associato un indirizzobene, quale indirizzo ?
se io avessi dichiarato
uint_32_t* p_var_integer;
invece di
uint_32_t* p_var_integer = &var_integer;
/* NOTA l'operatore & serve proprio per recuperare l'indiriizzo di un oggetto */p_var_integer punterebbe in una zpna caso della memoria
(oppure a 0x0000.0000,
se il compilatore e' cosi' smart da inizializzare a NULL
i puntatori non inizializzati#define NULL 0)
Potresti spiegarmi questo codice?
typedef struct
{
uint32_t real;
uint32_t imm;
} complex_t;
Cosa significa typedef? E il complex_t?
E cosa significa c.real e c.imm?
Cioè prendendo l'esempio dei cassetti è come se all'interno del cassetto "c" ci fossero altri due cassettini chiamati "real" e "imm"?
Occhi con i principianti, non mettere troppa carne al fuoco. Cioè non introdurre una istruzione sconosciuta per spiegare un'altra.
Quella typedef struct ecc definisce un alias per il nome complex_t che si riferisce ad una struttura.
Quindi non consideriamo typedef, togliamolo e togliamo anche i numeri complessi.
struct account
{
String uname;
String passwd;
};
account myaccaount;
myaccaount.uname = "mauro";
myaccaount.passwd = "la password più lunga che riesco a ricordare e questa";
Quindi ora si ho un oggetto myaccount, di tipo struttura (account) che contiene due variabili uname e passwd, e per accedervi uso l'operatore ".".
ps: continua a leggere quella guida e fai gli esperimenti non usando arduino e compagni.
Ciao.
fermo, stai confondendo strutture e puntatori.
una struttura è un TIPO di dato creato da te.
metti che, per X persone, vuoi memorizzare età e nome. Allora ti crei un tipo di dato, mettiamo di nome INFO, che contiene un'array di lettere(il nome) e un intero (l'età).
si scrive:
struct INFO{
char nome[30];
int eta;
};
ora abbiamo un tipo di dato, ma non possiamo scriverci niente, abbiamo solo detto al compilatore come è fatto il nostro nuovo dato.
per usarlo abbiamo 2 alternavi senza usare i puntatori:
struct INFO primaPersona;
ora abbiamo la variabile di nome "primaPersona" e di tipo "struct INFO"
per inserire i dati facciamo
primaPersona.nome = "Lesto";
primaPersona.eta = "22";
poi ovviamete possiamo anche fare un'arry, piuttosto che una variabile per persona:
struct INFO persone[12];
per inserire i dati facciamo
persone[0].nome = "Lesto";
persone[0].eta = "22";
ora, per evitare ogni volta di scrivere "struct INFO" possiamo usare un tipedef:
typedef struct INFO info
ora al posto di scrivere "struct INFO" possiamo scrivere solo "info"...
ora, se vuoi evitare completamente di avere tra le balle "struct INFO" e usare direttamente "info", metti la dichiarazione di struttura all'interno del typedef, come ha fatto il tipo che ha scritto il codice che posti, non ha fatto altro che creare un tipo di dato personalizzato.
le strutture, spesso e volentieri si usano attraverso i puntatori. Un esempio sono le liste dinamiche, ovvero array di dimensione variabile in cui ogni elemento è una struttura, che contiene l'indirizzo (puntatore) al prossimo elemento (e alle volte anche del precedente).
Il vantaggio di una lista, oltre ad essere dinamica, è che l'array deve essere uno spazio in memoria tutto "attaccato", per la sua particolarità di come si muove tra gli elementi. se una struttura contiene tanti dati o ci sono molti elementi, non sempre è possibile avere questo spazio. invece con una lista ogni elemento è sparso in memoria, tanto gli elementi li ritrovi attraverso i puntatori.
In oltre, quando passi una variabile ad una funzione, questa viene messa nello "stack", il problema è che è facile mandarlo in overflow, quindi di nuovo, se la struttura è grossa, passarla per valori può non essere possibile, quindi si passa un puntatore alla struttura (che alla fine dei conti è un int, quindi molto leggero) e si risolve il problema all'origine.
ci sono varie inesattezze e incompletezze, ma per capire il meccanismo dovrebbe bastare
edit: preceduto da maurotec ![]()
In linea di massima ho capito! Grazie per la spiegazione dei puntatori e delle strutture ![]()
Siete davvero gentilissimi! ![]()
Xfox:
In linea di massima ho capito! Grazie per la spiegazione dei puntatori e delle strutture
Siete davvero gentilissimi!
Scusami che insisto; cerca di imparare con qualche tutorial e capire bene i puntatori perché sono una delle cose forte del C e se li conosci Ti semplificano in certe situazioni la programmazione.
PS: esistono anche puntatori di puntatori e il simbolo per avere il contenuto della variabile a cui punta un puntatore.
Adesso sto zitto per non incasinare di piú.
Ciao Uwe
Una definizione di stack?
Altra domanda:
complex_t è un tipo di dato che immagazina un numero immaginario a quanto ho capito, giusto?
Nella "busta c" in pratica non c'è bisogno di assegnare a una variabile il return di una struttura (come per esempio fuffa=(fuffa, fuffa)) ma gli si passa direttamente il puntatore (nonchè indirizzo di allocazione della memorira) di dove salvare il "ritorno" (quest'ultimo è complex_t* c) correggetemi se sbaglio! ![]()
Xfox:
Una definizione di stack?
auguri:
si tratta di architettura dei sistemi. In pratica come funziona una CPU, esiste un buon manuale free su internet, si occupa della cpu 8086 ma per darti un'idea di funzionamento va benissimo, io ho studiato solo quello (per ora) e ho capito che non credo mi farò un mia CPU ![]()
Xfox:
complex_t è un tipo di dato che immagazina un numero immaginario a quanto ho capito, giusto?
sì.
Xfox:
Nella "busta c" in pratica non c'è bisogno di assegnare a una variabile il return di una struttura (come per esempio fuffa=(fuffa, fuffa)) ma gli si passa direttamente il puntatore (nonchè indirizzo di allocazione della memorira) di dove salvare il "ritorno" (quest'ultimo è complex_t* c) correggetemi se sbaglio!
NO! gli sia passa il puntatore, ovvero l'indirizzo della cella prima cella in ram che contiene la struttura.
la struttura occupa 8 celle, ovvero 8 byte (2 * sizeof(uint32_t)), e queste celle sono una di fila all'altra. E' così, fa tutto la malloc(anche se non la vedi)
dunque ora la funzione modifica I DATI ORIGINALI, gli stessi che usa la funzione chiamante!
Infatti questo crea molti problemi, non con arduino, ma nei normali PC quando si usano i thread o i processi... ovvero quando nasce la possibilità che 2 segmenti di codice leggono e o modificano lo stesso dato contemporaneamente!
ti stai infilando a fare domande MOLTO avanzate, probabilmente perchè non sai nemmeno da dove iniziare. studia studia studia, che nessuno nasce imparato! inizia da quì, salta pure i capitoli che sai già, oppure (meglio) dagli un'occhiata che fa sempre bene: http://programmazione.html.it/guide/leggi/32/guida-c/
Una definizione di stack?
Altra domanda:
complex_t è un tipo di dato che immagazina un numero immaginario a quanto ho capito, giusto?
Per questo dicevo non tiriamo in ballo l'esempio del numero complesso, alla fine non importa cosa realmente sia il numero complesso, l'importante capire che è un tipo di dato "struct" che contiene la definizione di alcuni "membri" della struttura.
Nella "busta c" in pratica non c'è bisogno di assegnare a una variabile il return di una struttura (come per esempio fuffa=(fuffa, fuffa)) ma gli si passa direttamente il puntatore (nonchè indirizzo di allocazione della memorira) di dove salvare il "ritorno" (quest'ultimo è complex_t* c) correggetemi se sbaglio! smiley
Flameman si esprime come un professore, ti mette in secondo piano la cosa che andrebbe posta in evidenza e lascia a te il compito di metterla in risalto, poi tutti sti fuffa io mi confondo facile.
Semplicemente: la dimensione della variabile puntatore è fissa e dipende dall'architetture (microcontrollore o microprocessore) pertanto se un puntatore impegna 4 byte e punta ad un ogetto molto più complesso che impegna 512 byte, conviene passare (o ritornare) il puntatore ad una funzione anziche l'oggetto stesso, perchè è più rapido e occupa meno spazio nello stack. Passando un puntatore dici alla funzione di operare sul dato che si trova qui, passado il dato stesso dici alla funzione opera con questo dato.
Mi viene un esempio allucinante: Nel cortile ho un masso (pietra) 180x180 cm, lo devo rompere, cosa mi conviene fare? prendo il masso (me lo carico sulle spalle) e lo porto a frantumare da chi ha l'attrezzatura o gli dico di portare l'attrezzatura per rompere il masso. Il bello che il masso c'è l'ho nel cortile per davvero.
Esempio a parte creare programmi che devono essere eseguiti da hardware con risorse limitate come i microcontrollori è un compito per niente semplice, puoi fallire in qualunque momento, basta che aggiungi una variabile e il programma va in palla, basta un puntatore che punta dove non dovrebbe, e allora impazzisce il programma e tu appresso ad esso.
Sul PC, il sistema di aiuta a non far danni ed il debug è più semplice.
Ciao.
Edit: lesto mi ha preceduto.
Esempio a parte creare programmi che devono essere eseguiti da hardware con risorse limitate come i microcontrollori è un compito per niente semplice, puoi fallire in qualunque momento, basta che aggiungi una variabile e il programma va in palla, basta un puntatore che punta dove non dovrebbe, e allora impazzisce il programma e tu appresso ad esso.
Sul PC, il sistema di aiuta a non far danni ed il debug è più semplice.
non funziona così, è più;
io ho il sasso, lo predo, ne creo una copia perfetta a casa del tizio(passaggio alla funzione per valore) che frantuma LA COPIA, e poi sostituisco il sasso originale con la copia della copia(copia della copia perchè la copia, passando per il return passa attraverso un'altra copia). Nella realtà non sta molto in piedi, ma è così che funziona.
Invece con un puntatore dai l'indirizzo della pietra e il tizio arriva a frantumarla.
Se volevi solo vedere com'è la pietra frantumata senza intaccare l'originale, allora il primo metodo può essere ancora ancora accettabile, ma se dovevi rompere direttamente la pietra iniziale....
studia studia studia, che nessuno nasce imparato!
mmmm...
while (true) {
if (!myMind->stack->overflow())
myMind.setPrimaryActivity("Studia") ;
else
myMind.setPrimaryActivity("Sleep");
}
Non va bene, si devono inserire nel ciclo alcune attività ricreative/rigenerative.
Ciao.
All'ultimo minuto:
non funziona così, è più;
Si si, l'esempio non è calzante solo che io c'è l'ho per davvero quel masso e se gli potessi passare un puntatore me ne sarei sbarazzato subito. Ho equiparato la difficolta di spostare un peso gravoso da spostare al carico gravoso di spostare un dato. Certo ora che rileggo forse non è lampante che quando si passa il puntatore ad oggetto come argomento di una funzione, dentro la funzione operi/modifchi l'oggetto stesso. Mentre passando il dato, viene creato un oggetto locale all'interno della funzione che contiene il valore che hai passato come argomento alla funzione. Comunque se possibile conviene sempre passare un puntatore e se non vuoi modificare il dato crei una copia in locale su cui operare, qua la cosa va valutata caso per caso.
Ciao.
flameman:
dai, diciamocelo ... un po' e' pigrizia
No, questo non posso lasciartelo dire!
Sono un ragazzo di 17 anni, quest'anno entrerò nel quinto superiore nella specializzazione di Elettronica e Telecomunicazioni. Sono sempre stato appassionato di elettronica e informatica e ho cominciato a studiare il C++ acquistando un libro durante la gita di terza media.
Per mia sfortuna nella mia scuola nessun professore è in grado di spiegarmi qualcosa sul C (a malapena qualcosa di assembler per programmare gli scenix o basic per i pic) quindi son venuto qui sul forum di arduino, dove devo dire che mi trovo bene perchè le persone sono garbate ed educate. Però non son venuto per porre qualsiasi domanda, odio quando mi rispondo "fai una ricerca sul forum, l'argomento è stato già trattato", prima di chiedere ho cercato un po per la rete, semplicemente, la risposta di un'essere umano è più soddisfacente poichè da una domanda ne nasce sempre un'altra!
esatto, ma proprio perche' NON mi piace fare il prof
e non mi piace ripetere quanto ha appreso sui libri
Ok, è evidente che non era una critica, solo un modo per argomentare e dire come stanno le cose per me.
Io ho uno stack piccolo e pochi registri e quindi se mi tiri fuori una typedef per spiegarmi una cosa ottieni il risultato contrario, cioè vado in confusione. Magari poi ci arrivo facendo ordine, allora io penso che se rispondo ad un principiante voglio che capisca quello che dico, altrimenti non rispondo affatto. Quindi per raggiungere l'obbiettivo rispondo in modo più semplice possibile, poi e chiaro che mi aspetto che l'utente apporti pepe alla discussione perchè non si finisce mai di imparare.
Alla fine flameman ne sai più di me di programmazione molto probabilmente sei fresco di scuola come mi pare di capire.
Ciao.
flameman:
ed e' una vergogna che mi fa un filo alterare
nella mia vita di studente ho incontrato ottimi docenti all'ITIS,
e un autentico asino che "insegnava" programmazione oggetti a ingegneria.
comunque non si può generalizzare.
il problema è che in italia non c'è meritocrazia: un bravo docente viene pagato quanto l'asino, se non di meno.
Domanda banale per gli esperti:
come faccio sa salvare il valore di dove punta il puntatore ?
Ho un puntatore *pluto che punta ad una allocazione di memoria in cui è contenuta una serie di caratteri.
Questi caratteri li voglio assegnare una una variabile . . . pensavo che la cosa fosse banale del tipo
String pippo;
pippo = *pluto ma il compilatore mi da errore, che funzione devo usare ?
Grazie in anticipo a chi mi darà qualche suggerimento
si fa esattamente come hai fatto... ovviamente pippo deveessere dello stesso tipo del valore puntato da pluto.
Ma se pluto è una serie di carater (un array), allora se vuoi assegnare i valori contenuti in pluto in un array dovrai copiarli uno per uno (o usare la strlcpy() se è una stringa chefinisce con \0 )