Newsgroup: it.comp.lang.c
Titolo: Problemi con coda dinamica...

Ho provato ad implementare una coda dinamica (non fate caso alla 
banalità dell'esercizio, ma è solo per provare).
Ho un problema: ogni qual'volta scelgo di inserire un nuovo oggetto (e 
quindi accodare un nuovo elemento) la coda è sempre NULL...ovvero sembra 
che il puntatore (al ritorno dalla funzione "inserisci") non aggiorni la 
sua copia all'interno del main...
Potreste dargli un'occhiata? Grazie mille in anticipo!!!
Posto il seguente codice:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct elemen *elemento;
struct elemen {
 
	int codice;
 
	elemento next;
}; // end struct
void inserisci(elemento mycoda);
void stampa(elemento mycoda);
int main()
{
	int i, scelta = 1;
 
	elemento coda; // inizio coda!
 
	coda = NULL; // inzializzazione di coda
 
	while(1){
		printf("Fai la tua scelta...\n");
		printf("1 per inserire...\n");
		printf("2 per stampare...\n");
		printf("0 per uscire...\n");
		scanf("%d", &scelta);
 
		if(scelta == 0){
 
			printf("Hai scelto di uscire...Arrivederci!\n"); return 0;
 
		} // end if
 
		if(coda == NULL){
 
			printf("\n\nmain: la coda è == NULL!!\n");
		}
 
		switch(scelta){
			case 1: inserisci(coda); break;
			case 2: stampa(coda); break;
			default: printf("Scelta sbagliata!!!\n"); continue;
 
		} // end scelta
 
 
 
	} // end while
} // end main
void inserisci(elemento mycoda){
	int temp = 0;
	elemento telem;
	if (mycoda == NULL){
 
		printf("\nLa coda è vuota...provvedo a crearne una...\n");
 
		mycoda = (elemento) malloc(sizeof(elemento));
 
		if(mycoda != NULL){
 
			printf("Coda creata...\n");
			mycoda->next = NULL;
		} // end if
		else{
			printf("Mi dispiace ma non mi è possibile creare una coda...\n"); return;
		} // end else
 
		printf("Inserisci il tuo codice...: ");
		scanf("%d", &temp);
 
		mycoda->codice = temp;
 
		printf("Codice inserito!!!\n");
		printf("\nmycoda->codice : %d\n", mycoda->codice);
		printf("\nmycoda->next : %s\n", mycoda->next);
 
		if(mycoda == NULL) {
 
			printf("\n\nATTENZIONE!!! Coda continua ad essere NULL!!!\n\n");
 
		} // end if
 
	} // end if
	else{
		// scorriamo la coda fino alla fine
		telem = mycoda;
 
		while(telem->next != NULL){
 
 
 
			telem = telem->next;
		} // end while
 
		telem->next = (elemento) malloc(sizeof(elemento));
		telem = telem->next;
 
		if(telem != NULL){
 
			printf("Nuovo elemento aggiunto...\n");
			printf("Inserisci il tuo codice...: ");
			scanf("%d", &temp);
 
			telem->codice = temp;
			telem->next = NULL;
 
		} // end if
		else {
			printf("Non è stato possibile inserire un nuovo elemento...\n"); return;
		}
 
	} // end else
 
} // end inserisci
void stampa(elemento mycoda){
	elemento telem;
	if(mycoda!= NULL){
 
		printf("\n%d\n", mycoda->codice);
 
		telem = mycoda;
 
		while(telem->next != NULL){
 
			printf("%d\n", telem->codice);
 
			telem = telem->next;
 
		} // end while
 
		printf("\nCoda terminata!!!\n");
	} // end if
	else {
 
		printf("La coda è vuota...nessun elemento da stampare!\n");
	} // end else
} // end stampa

 void inserisci(elemento mycoda);
In C tutto viene passato per valore: quando passi ad inserisci() il 
puntatore, lui inserisce sullo stack L'INDIRIZZO al quale tale puntatore 
punta...
void inserisci(struct elemen** mycoda); //questo è il prototipo da usare
Trai da solo le conclusioni così ti fissi questo concetto nella testa 
una volta per tutte.
Ciao, Alberto

 una volta per tutte.
Ok grazie mille! Proverò con la tua soluzione. Ciao.

 una volta per tutte.
Altro problema...già con i puntatori non sono a mio agio...con i doppi 
puntatori ancora peggio. Ad esempio:
All'interno di "insersci(...)" come traduco le seguenti istruzioni:
- elemento telem; (dichiarazione di elemento temporaneo)
- mycoda->codice = temp; (assegnazione a mycoda questa volta inteso come 
doppio puntatore)
- telem->next = (elemento) malloc(sizeof(elemento));
   telem = telem->next; (istruzioni del genere per scorrere la coda...)
Grazie mille per la pasienza!!!!

 valore, un char...ma un puntatore?
Tutto è passato per valore, in C, sia variabili intere, che variabili
char, che variabili puntatori, quindi se vuoi modificare il valore di un
puntatore, devi simulare il passaggio per riferimento.
Se scrivi:
void stampa_intero(int a) { printf("%d\n", a); }
Non hai bisogno di passare a per riferimento, perché non hai necessità di
modificarla (la stampi e basta).
Se scrivi:
void modifica_intero(int a) { a = a + 1; }
e chiami la funzione nel modo seguente:
int b=3;
modifica_intero(b);
la variabile b dopo la chiamata vale ancora 3, perché all'atto della
chiamata ne hai solo copiato il vlaore nello stack, passato alla funzione
e la funzione ha incrementato il valore nello stack, *NON* il valore della
variabile originale.
Il comportamento corretto, invece lo ottieni con:
void modifica_intero(int *pa) { *pa = *pa + 1; }
int b=3;
modifica_intero(&b);
In questo caso, passi per valore il puntatore a b, ma accedendo alla
memoria puntata (dentro la funzione), puoi modificare in modo permanente
il valore intero presente alla memoria puntata.
Stessa cosa vale per i puntatori.
Se hai:
int *p;
e vuoi modificare il valore di p, devi passare il suo indirizzo a una
funzione:
modifica_puntatore(&p);
E la funzione, così come quella precedente aveva per parametro un
puntatore a intero, avrà per parametro un puntatore a puntatore:
void modifica_puntatore(int **p) { *p = malloc(100); }
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 
Allora:
struct elem* coda = NULL;
te poi chiami inserisci(struct elem* miacoda);
Cosa succede? Succede che nello stack viene messo l'indirizzo che è 
contenuto nel puntatore coda (che è appunto NULL).
Quello che a te serve è invece che venga messo nello stack l'indirizzo 
di memoria del puntatore stesso, in questa maniera puoi nella funzione 
modificare quel NULL  contenuto in coda nel valore ritornato dalla malloc().
Devi fare una cosa del genere:
struct elem* coda=NULL;
inserisci(&coda);
inserisci(elem** mycoda) {
	*mycoda = malloc(.....);
	*mycoda->valore = 10;
	....
}
Ciao, Alberto

 void modifica_puntatore(int **p) { *p = malloc(100); }
Ok credo di aver capito...però mi fa riflettere il comportamento dei 
puntatori...ad esempio:
void riempiarr(int *arr);
...
...
int arr[100];
riempiarr(arr);
In questo caso non c'è nussun bisogno di passare l'indirizzo di "arr" in 
quanto arr è già un puntatore, giusto?
Ora ne caso abbiamo dichiarato una struttura in maniera dinamica (come 
nel mio esempio):
typedef struct pippo *miopippo;
struct pippo{
	int valore;
	miopippo *next;
}
e poi facciamo la seguente dichiarazioni di variabile:
miopippo newpippo;
ora "newpippo" è a tutti gli effetti un puntatore, nè più ne meno di un 
array...quindi perchè utilizzare i doppi puntatori?
Ora sono sicuro che sono io a sbagliarmi...solo che visto che ci sono 
vorrei chiarirmi questa storia.
Grazie mille!!!

 array...quindi perchè utilizzare i doppi puntatori?
 Se devi modificare il valore di "ptr_miopippo" dentro ad una funzione sei
obbligato a passarne l'indirizzo ed ad usare i doppi puntatori. Non ci sono
altri modi.
Ti suggerisco di disegnarti su un pezzo di carta una rappresentazione
grafica delle varie variabili.
Dei rettangoli per rappresentare le variabili non puntatori (ad es. le
variabili di tipo int o le strutture di tipo pippo) e delle frecce per
rappresentare i puntatori. La punta della freccia punta ad un rettangolo
quando il puntatore non vale NULL. Vedrai che se devi cambiare una freccia
(il valore di un puntatore) dentro ad una funzione, sei obbligato a passare
alla funzione una freccia che punta a questa freccia (ossia un puntatore ad
un puntatore, ossia i doppi puntatori usando la tua terminologia),
altrimenti modifichi solo una copia della freccia che doveva essere
modificata e quando esci dalla funzione la freccia (puntatore) che doveva
essere modificata è rimasta inalterata.

 Ciao, Alberto
Ok sto seguendo la tua soluzione, ma c'è un errore che non risolvo...
l'errore è il seguente:
error: request for member 'next' in something not a structure or union
error: request for member 'codice' in something not a structure or union
Tale errore viene generato dalle seguenti assegnazioni:
*mycoda->next = NULL;
*mycoda->codice = temp;
Sapresti dirmi il perchè?
Grazie!
Ecco come ho cambiato l'implementazione di inserisci:
void inserisci(struct elemen **mycoda){
	int temp = 0;
	//elemento *telem;
	struct elemen *telem;
	if (mycoda == NULL){
 
		printf("\nLa coda è vuota...provvedo a crearne una...\n");
 
		//mycoda = (elemento*) malloc(sizeof(elemento));
		*mycoda = malloc(sizeof(elemento));
 
		if(mycoda != NULL){
 
			printf("Coda creata...\n");
			*mycoda->next = NULL;
		} // end if
		else{
			printf("Mi dispiace ma non mi è possibile creare una coda...\n"); return;
		} // end else
 
		printf("Inserisci il tuo codice...: ");
		scanf("%d", &temp);
 
		*mycoda->codice = temp;
 
		printf("Codice inserito!!!\n");
		printf("\nmycoda->codice : %d\n", *mycoda->codice);
		printf("\nmycoda->next : %s\n", *mycoda->next);
 
		if(mycoda == NULL) {
 
			printf("\n\nATTENZIONE!!! Coda continua ad essere NULL!!!\n\n");
 
		} // end if
 
	} // end if
	else{
		// scorriamo la coda fino alla fine
		telem = mycoda;
 
		while(*telem->next != NULL){
 
			*telem = *telem->next;
		} // end while
 
		*telem->next = (elemento *) malloc(sizeof(elemento));
		telem = *telem->next;
 
		if(telem != NULL){
 
			printf("Nuovo elemento aggiunto...\n");
			printf("Inserisci il tuo codice...: ");
			scanf("%d", &temp);
 
			*telem->codice = temp;
			*telem->next = NULL;


 essere modificata č rimasta inalterata.
Ottimo consiglio! Ringrazio molto te e Andrea Laforgia e Albero EMME per 
tutti i consigli! Oggi mi avete chiarito una cosa *MOLTO* importante!

 Grazie!
Ok ok ho risolto:
(*mycoda)->next = NULL;
(*mycoda)->codice = temp;
Mancavano le parentesi :)))

Ok ora *sembra* che tutto funziona...
Questo è il codice funzionante:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct elemen *elemento;
struct elemen {
 
	int codice;
 
	elemento next;
}; // end struct
void inserisci(struct elemen **mycoda);
void stampa(struct elemen *mycoda);
int main()
{
	int i, scelta = 1;
 
	//elemento coda; // inizio coda!
 
	struct elemen *coda;
 
	coda = NULL; // inzializzazione di coda
 
	while(1){
		printf("\nFai la tua scelta...\n");
		printf("1 per inserire...\n");
		printf("2 per stampare...\n");
		printf("0 per uscire...\n\n");
		scanf("%d", &scelta);
 
		if(scelta == 0){
 
			printf("\n\nHai scelto di uscire...Arrivederci!\n\n"); return 0;
 
		} // end if
 
		switch(scelta){
			case 1: inserisci(&coda); break;
			case 2: stampa(coda); break;
			default: printf("Scelta sbagliata!!!\n"); continue;
 
		} // end scelta
 
 
 
	} // end while
} // end main
void inserisci(struct elemen **mycoda){
	int temp = 0, count = 0;
	//elemento *telem;
	struct elemen *telem;
	if (*mycoda == NULL){
 
		printf("\nLa coda è vuota...provvedo a crearne una...\n");
 
		//mycoda = (elemento*) malloc(sizeof(elemento));
		*mycoda = malloc(sizeof(elemento));
 
		if(mycoda != NULL){
 
			printf("Coda creata...\n");
			(*mycoda)->next = NULL;
		} // end if
		else{
			printf("Mi dispiace ma non mi è possibile creare una coda...\n"); return;
		} // end else
 
		printf("Inserisci il tuo codice...: ");
		scanf("%d", &temp);
 
		(*mycoda)->codice = temp;
 
		printf("Codice inserito!!!\n");
		//printf("\nmycoda->codice : %d\n", (*mycoda)->codice);
		//printf("\nmycoda->next : %s\n", (*mycoda)->next);
 
		if(mycoda == NULL) {
 
			printf("\n\nATTENZIONE!!! Coda continua ad essere NULL!!!\n\n");
 
		} // end if
 
	} // end if
	else{
		// scorriamo la coda fino alla fine
 
		telem = *mycoda;
 
		while(telem->next != NULL){
 
			telem = telem->next;
			count++;
 
		} // end while
 
		//printf("\n\nHo inserito in posizione: %d\n\n", count);
 
		telem->next = malloc(sizeof(elemento));
		telem = telem->next;
 
		if(telem != NULL){
 
			printf("Nuovo elemento aggiunto...\n\n");
			printf("Inserisci il tuo codice...: ");
			scanf("%d", &temp);
 
			telem->codice = temp;
			telem->next = NULL;
 
		} // end if
		else {
			printf("Non è stato possibile inserire un nuovo elemento...\n"); return;
		}
 
	} // end else
 
} // end inserisci
void stampa(struct elemen *mycoda){
	struct elemen *telem;
	if(mycoda!= NULL){
 
		//printf("\n%d\n", mycoda->codice);
 
		printf("\n\n");
 
		telem = mycoda;
 
		while(telem->next != NULL){
 
			printf("%d\n", telem->codice);
 
			telem = telem->next;
 
		} // end while
 
		printf("%d\n", telem->codice);
 
		printf("\nCoda terminata!!!\n\n");
	} // end if


quanto arr è già un puntatore, giusto?
No, perché si dice (lo dice lo standard) che il nome dell'array decade
nel puntatore al suo primo elemento.  Per gli argomenti di funzione
vale sempre, mentre non è sempre vero.  Cioè, scrivere:
void funzione(int a[]) 
significa *SEMPRE* scrivere:
void funzione(int *a) 
E' così per ragioni di performance, l'array non viene passato per
copia sullo stack, ma viene copiato solo l'indirizzo al primo elemento
(a partire dal quale, mediante aritmetica dei puntatori e conoscendo
il tipo dei dati contenuti nell'array, accedi a tutti i seguenti).
Bada che, in generale, un array è una cosa differente da un puntatore
e la differenza si tocca con mano in tre casi specifici:
1) l'uso di sizeof;
Se ho: int a[5], *b;
scrivere 'sizeof a' è diverso dallo scrivere 'sizeof b'.
2) l'uso di & (address-of);
La differenza qui è più sottile e riguarda il tipo del puntatore
restituito dall'applicazione di & alla variabile array o puntatore:
Se ho int a[5], *b;
scrivere '&a' significa ottenere un puntatore ad array di 5 interi,
mentre scrivere '&b' significa ottenere un puntatore a un puntatore a
intero.
3) l'inizializzazione di un array mediante string literal;
Quando scrivi: char a[] = "pippo";
"pippo" è un array di 6 caratteri const e *non* decade nel puntatore
al suo primo elemento, essendo la scrittura del tutto equivalente a:
char a[] = {'p','i','p','p','o','\0'};

 l'hai definita (il tipo è conforme).
Non è propriamente così.  Per come l'hai scritta, la clausola "quindi" che
scrivi è pericolosa perché lascia pensare che "arr" sia *sempre* il
puntatore al primo elemento.  In realtà, arr *può decadere* in puntatore
al primo elemento; nel caso dei parametri di funzioni, questo decadimento
avviene sempre.


 avviene sempre.
Cosa intendi con *può decadere* ?

 Cosa intendi con *può decadere* ?
Lo stesso significato che lo standard ISO assegna al predicato "decays".
Vedi la mia risposta a Will.


 char a[] = {'p','i','p','p','o','\0'};
In che senso non decade a puntatore?
Cioè se passo 'a' (arraty const di char) come paramentro di una funzione 
(tipo ad esempio... void modifica(char *a) e poi chiamo modifica(a) ) 
non posso utilizzare l'aritmetica dei puntatori per scorrere l'array?
Faccio una prova pratica ;)

 non posso utilizzare l'aritmetica dei puntatori per scorrere l'array?
Non sto parlando di 'a', sto parlando di "pippo".
Se passi 'a' a una funzione come quella che citi, il decadimento avviene
sempre, te l'ho già scritto nel precedente messaggio.


 sempre, te l'ho già scritto nel precedente messaggio.
Ah ok, non avevo capito parlassi di "pippo"...