PDA

View Full Version : [C] PUNTATORI help


Dbz
30-10-2012, 17:24
Salve a tutti,non ho capito nulla dei puntatori,qualcuno potrebbe darmi una spiegazione molto facile per capire il concetto e la loro utilità pratica?

Ad esempio
se scrivo

int a,b,c;
a=&b ( Assegno alla variabile a l'indirizzo in memoria della variabile b?)
l'indirizzo in memoria è un numero esadecimale?
se scrivo:
c=*a (cosa vuol dire?)

ho molta confusione sui puntatori,chiaritemi un pò le idee

Dbz
30-10-2012, 17:46
Ho visto una guida dove c'era questo codice
#include <stdio.h>
#include <stdlib.h>

main()

{


int b,c;
int *a;

b=10;

a=&b;

c=*a;

printf("b%d\n",b);
printf("c%d\n",c);

return EXIT_SUCCESS;
}


Fatemi capire....
a b viene assegnato 10;

ad a viene assegnato l'indirizzo in memoria di b;

e a c viene assegnato il valore contenuto nell'indirizzo di memoria di b? dato che prima ho assegnato l'indirizzo di memoria di b ad a?

Quindi il puntatore mi dà due informazioni: Il valore di un'altra variabile (b) e il suo indirizzo in memoria (sempre di b) ?

Non ho capito però perchè nella dichiarazioni di variabile non viene dichiarata a, ma bensì *a..

Dbz
30-10-2012, 18:34
Era meglio programmare in pascal,almeno non esistevano sti problemi dato che il passaggio di parametri ad una funzione era sempre by reference

lorenzo001
30-10-2012, 18:37
Secondo me era meglio comprare un libro da studiare prima di scrivere del codice.

Dbz
30-10-2012, 18:55
Sto studiando da degli appunti,ma non riesco a capire appunto i puntatori,se qualcuno me li spiegasse ne sarei grato.

lorenzo001
30-10-2012, 21:15
Devi studiare dai libri non dagli appunti.

E comunque non si può spiegare un argomento così vasto su un forum.

Qui si dovrebbero fare domande precise per ottenere risposte precise.

goldorak
31-10-2012, 19:38
Sto studiando da degli appunti,ma non riesco a capire appunto i puntatori,se qualcuno me li spiegasse ne sarei grato.

Un puntatore e' semplicemente una variabile il cui valore e' un indirizzo di memoria.


Ogni variable in C e' caratterizzata da determinati attributi tra cui :

- il nome
- lo scope
- il left value
- il right value
- il tipo

Il right value di una variable e' il suo valore. Il left value e' invece l'indirizzo di memoria della variabile. Tanto per fare un esempio :

Prendi due variabili a e b di tipo integer.

a = b questo e' un assegnamento. Questa istruzione corrisponde a prendere il right value di b (da qui deriva l'origine del termine right value, compare a destra di un assegnamento) ovverosia corrisponde a prendere il valore di b e lo memorizza nella variabile a (cioe' lo memorizza nel indirizzo di memoria che e' il left value di a).

Ora un puntatore e' una variabile, quindi ha sia il left value che il right value.
Ma siccome il right value di un puntatore e' un indirizzo di memoria, si puo' accedere al contenuto di quel indirizzo mediante l'operazione di dereferenziazzione.

Se a e' una variabile, &a e' il suo indirizzo.
Se a e' un puntatore, &a e' l'indirizzo del puntatore; a e' il valore del puntatore e (*a) e' il contenuto della cella di memoria il cui indirizzo e' il valore di a.

Per dichiarare un puntatore occorre sempre specificare a che tipo di dato punta.


Quindi se vuoi dichiarare un puntatore a interi o a char :

integer * a (a e' un puntatore a interi)
char * a (a e' un puntatore a char)
etc....

Se a e' un puntatore a integer e b e' una variabile di tipo integer allora scrivere

a = b non ha senso. Perche' non puoi assegnare un intero ad un una variabile puntatore. Puoi solo assegnare degli indirizzi (ricordati della definizione di puntatore, una variable il cui valore e' un indirizzo di memoria).
Quindi l'assegnamento va corretto in questo modo : a = &b. Ora e' giusto perche' &b e' l'indirizzo della variabile b, e questo lo puoi assegnare al puntatore a.

Se a e b sono puntatori dello stesso tipo allora puoi fare l'assegnamento
a=b. Perche' il right value di b e' un indirizzo (e' il valore del puntatore b) e visto che e' un indirizzo lo puoi assengare al puntatore a.

Ora supponiamo che

integer *a
integer b

b=5 (assegno il valore 5 a b)
a = &b (assegno l'indirizzo di b ad a)
se stampo a avro' un numero esadecimale che mi rappresenta l'indirizzo di b.
se stampo *a avro' invece il valore della variabile il cui indirizzo e' il valore di a. Quindi siccome il valore di a e' indirizzo di b, *a e' 5 (il valore di b).


Ma come altri ti hanno gia' consigliato, non studiare sugli appunti. Prendi un libro e studia quello. Chesso', il K&R, altrimenti un qualsiasi manuale sul C dovrebbe andare bene.

Dbz
01-11-2012, 17:30
Grazie per la risposta,adesso mi ci metto con calma per capirli.

Dbz
01-11-2012, 18:17
Perfetto ora ho capito.

Però non riesco a capire perchè in una funzione che scambia due variabile che poi viene chiamata nel MAIN il passaggio dei parametri (by value) non Funziona.

lorenzo001
01-11-2012, 20:09
Perfetto ora ho capito.

E' bastato poco ... dopo tante guide e tanta confusione sono bastate poche righe per farti capire ... un miracolo ... :)

Però non riesco a capire perchè in una funzione che scambia due variabile che poi viene chiamata nel MAIN il passaggio dei parametri (by value) non Funziona.

Cioè? Cosa vuoi dire?

Dbz
01-11-2012, 21:21
Ho scritto questo codice:

#include <stdio.h>
#include <stdlib.h>
void scambia (int *n,int *m);
int main()

{
int a,b,*n,*m;



printf("dammi il valore della prima variabile");
scanf("%d",&a);
printf("dammi il valore della seconda variabile");
scanf("%d",&b);

n=&a;
m=&b;

scambia(n,m);

printf("%d\n",a);
printf("%d\n",b);

return EXIT_SUCCESS;
}
/*--------------------------------------------------------------------------*/


void scambia (int *n,int *m)
{
int temp;

temp=*n;
*n=*m;
*m=temp;

}

Praticamente la funzione scambia,scambia i valori delle due variabili per fare ciò ho usato un passaggo by reference ho passato i puntatori n,m alla funzione che rispettivamente puntano alla variabile a e b (ho assegnato a n ed m gli indirizzi di a e b)
il programma funziona.

Però Non ho capito perchè questo programma NON funziona se uso un passaggio by value. ovvero se passo alla funzione le variabili a e b e non uso alcun puntatore.

Dânêl
01-11-2012, 22:55
non funziona perchè quando fai un passaggio by value non usi gli indirizzi di memoria dove sono memorizzate le variabili originali. Ogni volta che viene chiamata una funzione e vengono passate delle variabili by value, queste vengono copiate (detto in modo molto terra terra, invece di avere due variabili ne hai 4, a due a due uguali come valore, ma non come indirizzo). Ciò significa che uno scambia by value ti scambia le variabili solo all'interno della funzione e non a livello "globale". Usando i puntatori, e quindi un passaggio by ref, la funzione lavora direttamente sulle variabili "esterne" alla funzione.

Sperando che la spiegazione sia chiara, ribadisco quanto detto da altri: procurati un buon libro sul C. Ce ne sono migliaia e tutti chiariscono questi dettagli in modo molto chiaro (se non tutti, quantomeno la maggior parte).

Dbz
02-11-2012, 17:03
Ok Adesso mi è chiaro tutto.

Comunque devo realizzare un checkdate ovvero un programma che controlla le date è da 4 ore che ci provo ma non mi riesce nulla.

Pensavo di strutturare il mio programma così

-Il main legge la data immessa e tramite una stampa dice se è valida o meno.

-Creo una funzione che mi permette di controllare la validità della data

-Creo una funzione che mi permette di calcolare i giorni di un determinato mese

-Creo una funzione che mi permette di calcolare i giorni di Febbraio in base all'anno se è bisestile o meno.



Ho scritto il tutto ma non funziona una bega :muro: :muro:

Dbz
02-11-2012, 17:21
#include <stdio.h>
#include <stdlib.h>
int giorni_febbraio(int m, int a);



int main()

{

int g, m, a,ng;


printf ("Inserire la data (g m a): ");
scanf ("%d %d %d", &g, &m, &a);

ng=giorni_febbraio(m,a);

printf("%d",ng);


return EXIT_SUCCESS;




}

/*---------------------------------------------------------------------------------------------------------------------------------------------*/
/*Funzione che calcola i giorni di febbraio in base alla bisestilità*/


int giorni_febbraio(int m, int a)
{
if(m==2)
{
/* l'anno e` bisestile se:
e` divisibile per 4 e non divisibile per 100
oppure
e` divisibile per 400
*/
if(((a % 4 == 0) && (a % 100 != 0)) || (a % 400 == 0))


{

return 29;

}

else
{
if(!(((a % 4 == 0) && (a % 100 != 0)) || (a % 400 == 0)))
{
return 28;
}


}
}

else
{


/*Il mese immesso è !=2 quindi non è febbraio*/

printf("il mese immesso non è febbraio");
return;
}

}


Mi succede una cosa molto strana: Se metto una data come 2 3 2012 mi viene fuori una stampa con scritto "il mese immesso non è febbraio3"

Perchè viene fuori quell'3?

Non riesco a capire dov'è sta l'errore

lorenzo001
02-11-2012, 17:30
Viene visualizzato da questa linea

printf("%d",ng);

Dbz
03-11-2012, 00:09
si ma io non ho scritto un 3 nella printf perchè viane fuori quel 3?

[Kendall]
03-11-2012, 00:49
si ma io non ho scritto un 3 nella printf perchè viane fuori quel 3?

Tu prima chiami la funzione:

ng=giorni_febbraio(m,a);

che ti stampa "il mese immesso non è febbraio".
Subito dopo chiami

printf("%d",ng);

come ti diceva Lorenzo, che ti stampa "3".

Dbz
03-11-2012, 14:47
Non riesco proprio a capire...Dov'è l'errore quindi?

[Kendall]
03-11-2012, 15:09
Io ti consiglierei di seguire un percorso più graduale e lasciar stare i puntatori per ora, che sono un argomento delicato e per nulla banale (quando poi cominci a trattare l'allocazione dinamica diviene ancor più delicato).

lorenzo001
04-11-2012, 01:17
;38414092']Io ti consiglierei di seguire un percorso più graduale

Concordo ... il problema non sono i puntatori (non solo almeno).

Hai scritto


ng=giorni_febbraio(m,a);
printf("%d",ng);


quindi visualizzi *comunque* un valore (che è ng) e che viene restituito dalla funzione ... concordi?

Adesso entra in gioco il tuo compilatore che, stranamente, non dice nulla circa quel


return;


solitario che hai scritto nella funzione e che restituisce, casualmente, il valore 3.

In realtà, non dovresti poter compilare il programma perché dovresti *comunque* restituire un valore dato che la funzione è fatta per restituirlo. Quindi, anche nell'ultimo caso dovresti scrivere

return qualcosa;

e quel qualcosa verrebbe visualizzato dalla printf.

Ecco perché concordo sul fatto che devi rivedere il percorso di apprendimento dato che non hai ancora chiaro neanche l'uso delle funzioni e i puntatori vengono molto dopo ...

Dbz
10-11-2012, 16:03
Come consigliato da voi mi sono procurato un ottimo libro di C,mi sono rivisto tutte le cose e ho capito che in una funzione che restituisce un int.

Un'istruzione del tipo return; non ha senso,
avrebbe senso se e solo se la funzione sarebbe di tipo void

lorenzo001
10-11-2012, 17:04
... avrebbe senso se e solo se la funzione fosse di tipo void ...