|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Sep 2009
Città: Nel mondo dei sogni
Messaggi: 4131
|
[C] Struct, puntatori e liste
Sto studiando le liste e ho una situazione di questo tipo:
Codice:
struct node{
int info;
struc node *next;
};
typedef struct node ElementoDiLista;
typedef ElementoDiLista* ListaDiElementi;
Codice:
ListaDiElementi aux, lista; aux = malloc(Sizeof(ElementoDiLista)); aux->info = 15; lista = aux; lista->next = NULL; aux = malloc(Sizeof(ElementoDiLista)); aux->info = 10; aux->next = lista; lista = aux; aux = malloc(Sizeof(ElementoDiLista)); aux->info = 5; aux->next = lista; lista = aux; Ma torniamo a noi, il problema è questo: ho notato che in alcune funzioni, cioè in quelle che *non* devono modificare la lista, come argomento la funzione ha ListaDiElementi l. E quindi passiamo l'indirizzo alla lista. E fino a qua ci siamo. Però, nelle funzioni che *modificano* la lista, come argomento abbiamo un puntatore a puntatore, cioè ListaDiElementi *l. Ora la mia domanda è semplice: perchè? La lista non la posso modificare usando il puntatore come nella prima funzione, invece di avere un puntatore a puntatore? Mi sa che mi sono perso qualcosa per strada. |
|
|
|
|
|
#2 | |||
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2788
|
Quote:
Quote:
Quote:
Codice:
struct node* sostituisciNodo(struct node** n){
//Sostituisce il nodo passato come argomento con un nuovo nodo
//e restituisce il vecchio nodo
struct node* ret= *n;
*n=(struct node*)malloc(sizeof(struct node));
return ret;
}
void chiamante(){
...//Creo una nuova lista l
//Ora voglio sostituire la testa di l con un nuovo nodo e mettere il nodo rimosso in un'altra lista l2
addNode(&l2,sostituisciNodo(&l));
...
}
|
|||
|
|
|
|
|
#3 | |||||||
|
Senior Member
Iscritto dal: Sep 2009
Città: Nel mondo dei sogni
Messaggi: 4131
|
Quote:
Quote:
Ma la malloc in pratica mi mette in memoria il nodo "da riempire" perchè risale al fatto che aux è un puntatore a struct node? Quote:
Quote:
In che senso potrebbe assegnarlo al puntatore dereferenziato una sola volta? Quote:
Quote:
Quote:
Però devo dirlo: il C anche se fa sbattere la testa insegna molto, infatti lo sto studiando anche per i fatti miei oltre che per l'uni |
|||||||
|
|
|
|
|
#4 | |||||||
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2788
|
Quote:
Quote:
Quote:
Quote:
Ma negli esempi sotto credo di essermi spiegato molto meglio Quote:
Quote:
Quote:
es: Codice:
int* p //p può puntare ad un int struct node* p2 //p2 può puntare ad una struct node ListaDiElementi* l //l può puntare ad una ListaDiElementi, cioè un struct node* Codice:
int a=10;
printf("%d",a);
scanf("%d",&a);
Nel secondo invece ho passato la copia del suo indirizzo. La funzione scanf ha quindi accesso alla locazione di memoria in cui si trova il valore di a. Questo implica che dopo la chiamata il valore di a potrebbe essere stato modificato. Ora invece facciamo un esempio analogo con le liste: Codice:
ListaDiElementi l=NULL; //l inizialmente è vuota (punta a NULL) aggiungiInTesta(&l,11); //12 è l'info del nuovo nodo aggiungiInTesta(&l,02); aggiungiInTesta(&l,2010); aggiungiInCoda(l,23); Al contrario l'ultima chiamata non può modificare il valore di l (questo implica che se la lista è vuota, cioè l==NULL non potrà essere aggiunto l'elemento) ma può agire sul nodo puntato da l (quindi di fatto, se l!=NULL è possibile aggiungere un elemento in fondo) Anche a me è piaciuto studiarlo, specialmente all'università (lo conoscevo già dalle superiori ma non ce l'avevano spiegato granché bene). Ultima modifica di wingman87 : 08-02-2010 alle 02:29. |
|||||||
|
|
|
|
|
#5 | ||||||||
|
Senior Member
Iscritto dal: Sep 2009
Città: Nel mondo dei sogni
Messaggi: 4131
|
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
EDIT: mi è appena venuto un flash: può essere che passando semplicemente l io riesco a modificare solo il nodo successivo(perchè ho ha disposizione l'indirizzo immagazzinato nel puntatore next), ma non il primo nodo? Guarda questi due sorgenti: Codice:
void stampalista(ListaDiElementi *l)
{
ListaDiElementi aux;
aux = l; /* riporto aux al primo elemento */
printf("\n\nLista: [ ");
while(aux->next != NULL)
{
printf("%d ", aux->info);
aux = aux->next;
}
printf("]");
};
Codice:
void StampaLista(struct node *list)
{
struct node *aux;
aux=list;
while(aux != NULL)
{
printf("%d - ", aux->data);
aux = aux->next_node;
}
printf("\n");
};
Ma ho anche trovato questo che in pratica fa come hai fatto tu prima(passa l'indirizzo della lista, anche l è già un puntatore). E' questa la cosa che mi svia. Codice:
int main(){
ElementoLista n1, n2, n3, n4;
ListaDiElementi l = &n1;
n1.info = 1;
n1.next = &n2;
n2.info = 3;
n2.next = &n3;
n3.info = 5;
n3.next = &n4;
n4.info = 7;
n4.next = NULL;
stampalista(&l);
inser(&l, 0);
stampalista(&l);
return 0;
}
Questa cosa non è chiara: Codice:
delete_node(list, &n2);
printf(" - l'elemento 200 (INESITENTE) è in posizione %d**\n\n", get_pos(list, &n2));
int get_pos(struct node *head, struct node *nodo)
{
int conta = 1, trovato=0;
struct node *aux;
aux = head;
while(aux != NULL && trovato == 0)
{
if (aux == nodo)
trovato = 1;
else
{
aux=aux->next_node;
conta = conta+1;
}
Codice:
void delete_node(struct node *l, struct node *delnode)
{
int trovato = 0;
struct node *aux;
aux = l;
if (l==NULL)
{
if(aux->next_node==delnode) l = aux->next_node;
}
else
{
struct node *prec, *corr;
prec=l;
corr=prec->next_node;
while(trovato==0 && corr!=NULL)
if (corr==delnode)
trovato = 1;
else
{
prec = corr;
corr=corr->next_node;
}
if(trovato==1)
{
prec->next_node=corr->next_node;
}
}
};
Mi sono fatto dare alcuni appunti, scrivo ciò che c'è messo, ma ancora non mi è chiara la questione del doppio puntatore. Quote:
Ho lo scritto tra tre giorni Ultima modifica di Ryuzaki_Eru : 08-02-2010 alle 13:33. |
||||||||
|
|
|
|
|
#6 |
|
Senior Member
Iscritto dal: Sep 2009
Città: Nel mondo dei sogni
Messaggi: 4131
|
Edit.
Ultima modifica di Ryuzaki_Eru : 08-02-2010 alle 13:29. |
|
|
|
|
|
#7 |
|
Senior Member
Iscritto dal: Sep 2009
Città: Nel mondo dei sogni
Messaggi: 4131
|
Edit.
Ultima modifica di Ryuzaki_Eru : 08-02-2010 alle 13:29. |
|
|
|
|
|
#8 | ||||||||
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2788
|
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Riguardo get_pos il nodo può essere trovato in due casi: o il nodo era in testa e quindi delete_node non lo ha cancellato, oppure era stato inserito due volte nella lista (che schifo però). Quote:
"Questa procedura non funziona perchè terminato il blocco si cancella tutto quello che si era creato e la variabile che è rimasta non viene modificata" io direi che il nodo creato rimane in memoria ma non abbiamo più riferimenti ad esso (e quindi non possiamo liberare la memoria che occupa) perché l nella funzione chiamante è stato passato per copia e quindi non risente delle modifiche effettuate all'interno della funzione, in particolare non punta alla nuova testa ma alla stessa di prima. |
||||||||
|
|
|
|
|
#9 | |||||||||||
|
Senior Member
Iscritto dal: Sep 2009
Città: Nel mondo dei sogni
Messaggi: 4131
|
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Nodo1 che ha valore 1 e punta a NULL e salvo questo nodo nella variabile lista, poi in aux ad esempio creo un altro nodo e lo collego alla lista precedente e cosi via. Quote:
Quote:
Quote:
Quote:
|
|||||||||||
|
|
|
|
|
#10 | |||||||
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2788
|
Questi post iniziano a diventare troppo lunghi...
Quote:
Codice:
struct prova{
int a;
int b;
int c;
};
struct prova var;
Non solo è facile, è corretto e serve proprio per capire a fondo. Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Come dicevo sopra quello che ottieni è un puntatore al primo nodo della lista ma quello che passi è la copia del contenuto di l, cioè l'indirizzo del primo nodo della lista. |
|||||||
|
|
|
|
|
#11 | ||||||
|
Senior Member
Iscritto dal: Sep 2009
Città: Nel mondo dei sogni
Messaggi: 4131
|
Hai ragione, cerco di accorciare
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Codice:
struc list n1, n2, n3; n1.info = 2; n2.info = 3; n3.info = 4; n1.next = &n2; n2.next = &n3; n3.next = NULL; struct node *l = &n1; |
||||||
|
|
|
|
|
#12 | |||||
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2788
|
Quote:
Quote:
Quote:
Quote:
Codice:
...
int a=10;
int* p=&a;
int** pp=p;
printf("%d",**p);
...
Quote:
|
|||||
|
|
|
|
|
#13 | |||||
|
Senior Member
Iscritto dal: Sep 2009
Città: Nel mondo dei sogni
Messaggi: 4131
|
Quote:
Quote:
Quote:
Quote:
Quote:
Ultima modifica di Ryuzaki_Eru : 08-02-2010 alle 20:46. |
|||||
|
|
|
|
|
#14 | |||
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2788
|
Quote:
Quote:
Quote:
Stesso motivo per cui ho detto che l'assegnamento di quello spezzone di codice era sbagliato, lo riporto qui: Codice:
void stampalista(ListaDiElementi *l)
{
ListaDiElementi aux;
aux = l; /* riporto aux al primo elemento */
printf("\n\nLista: [ ");
while(aux->next != NULL)
{
printf("%d ", aux->info);
aux = aux->next;
}
printf("]");
};
Una cosa è "cosa" fai, un'altra è "perché" lo fai. Quello che dico io è che quel "cosa" è un passaggio per copia di un indirizzo. Sul "perché" ovviamente sono d'accordo. |
|||
|
|
|
|
|
#15 | |||
|
Senior Member
Iscritto dal: Sep 2009
Città: Nel mondo dei sogni
Messaggi: 4131
|
Quote:
Quote:
Quote:
|
|||
|
|
|
|
|
#16 |
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2788
|
Ti faccio un esempio completo di uso di doppio puntatore e puntatore singolo:
Codice:
//File lista.h typedef struct node* Lista; Lista creaLista(); //Restituisce una lista vuota void addElem(Lista* pL,int info); //Aggiunge un nuovo nodo con il campo info specificato in testa alla lista puntata da pL void printLista(Lista l); //Stampa gli elementi della lista Codice:
//File lista.c
#include "lista.h"
#include <stdio.h>
#include <stdlib.h>
//Definizione della struttura nodo. Chi usa la lista (il file prova.c) non sa come è
//definito e quindi non può accedervi direttamente (incapsulamento)
struct node{
int info;
Lista next;
};
Lista creaLista(){
return NULL;
}
//creaLista(int,Lista) non è presente nell'header, è una funzione di supporto che uso solo all'interno di questo file
//(volendo potrei anche aggiungerlo all'header).
//Ritorna una lista con in testa un nodo con il campo info e next specificati
Lista creaLista(int info, Lista next){
struct node* n=(Lista)malloc(sizeof(struct node));
if(!n) return NULL;
n->info=info;
n->next=next;
return n;
}
void addElem(Lista* pL,int info){
if(*pL==NULL){ //Se la lista puntata da pL è vuota la sovrascrivo con una nuova lista di un elemento
*pL=creaLista(info,NULL);
}else{
//Se la lista puntata da pL non è vuota la sovrascrivo con una nuova lista avente in testa
//un nuovo elemento e in coda la vecchia lista
*pL=creaLista(info,*pL);
}
}
void printLista(Lista l){
while(l){
printf("%d\t",l->info);
l=l->next;
}
printf("\n");
}
Codice:
//file prova.c
#include "lista.h"
int main(){
Lista l=creaLista(); //Creo una lista vuota
addElem(&l,3); //Passo l per indirizzo in modo che dopo la chiamata l conterrà una nuova lista uguale alla precedente ma con 3 in testa
addElem(&l,2);
addElem(&l,1);
printLista(l);
}
Ultima modifica di wingman87 : 08-02-2010 alle 22:43. Motivo: Corretti alcuni errori e aggiunti dei commenti |
|
|
|
|
|
#17 |
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2788
|
Io per indirizzo di una variabile intendo l'indirizzo della locazione di memoria in cui si trova il valore della variabile
Mi sembra strano ma mi fido. Vedi sopra |
|
|
|
|
|
#18 | ||
|
Senior Member
Iscritto dal: Sep 2009
Città: Nel mondo dei sogni
Messaggi: 4131
|
Leggo domani, intanto grazie.
Quote:
Quote:
Ultima modifica di Ryuzaki_Eru : 08-02-2010 alle 22:10. |
||
|
|
|
|
|
#19 |
|
Senior Member
Iscritto dal: Sep 2009
Città: Nel mondo dei sogni
Messaggi: 4131
|
Negli appunti c'ho scritto che questa procedura non funziona perchè terminato il blocco si cancella tutto quello che si era creato. Ma alla fine, assegnando aux ad l modifico effettivamente la lista passata. Perchè non dovrebbe funzionare?
Codice:
void add(ListaDiElementi l, int val){
ListaDiElementi aux;
aux = malloc(sizeof(ElementoLista));
aux->info = val;
aux->next = l;
l = aux;
};
|
|
|
|
|
|
#20 |
|
Senior Member
Iscritto dal: Sep 2009
Città: Nel mondo dei sogni
Messaggi: 4131
|
Dopo un flash(bellissimi i lampi di genio
Codice:
#include <stdio.h>
void prova(int *num);
int main(){
int a = 10;
int *p = &a;
printf("Il valore di a e' %d\n", a);
prova(p);
printf("Ora il valore di a e' %d %d\n", a);
return 0;
}
void prova(int *num){
int b = 100;
num = &b;
printf("Il valore di a dentro la func e' %p %d\n", num, *num);
};
|
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 17:34.



















