Oppure

Loading
12/12/10 14:50
WinstonS
Ciao a tutti, starei facendo questo esercizio:
A Elettrolandia si va a votare per eleggere il nuovo Governatore. Si presentano quattro candidati: 1,2,3,4.
Le schede votate sono raccolte in una lista, in cui ogni elemento memorizza il numero del candidato votato e un'informazione
sulla validità della scheda (valida o nulla). Si deve procedere allo spoglio.
     (i) Definire gli opportuni tipi di dato per rappresentare la lista delle schede votate
     (ii) Progettare una funzione ricorsiva che, presa in input la lista delle schede votate, e un numero corrispondente
         ad uno dei candidati, proceda al conteggio dei voti validi relativi a quel candidato
     (iii) Progettare una funzione che, presa in input la lista delle schede votate, e il numero corrispondente ad uno dei candidati,
         elimini dalla lista iniziale le schede votate non valide di quel
         candidato e restituisca il numero di cancellazioni effettuate


Ora credo di aver risolto tutto, ma se nella funzione del punto iii (EliminaSchedeNulle()) uso f (parametro) al posto di first (puntatore dichiarato globalmente per comodità;) nel momento in cui vado a stampare la lista ho elementi in più che non dovrebbero esserci (se ho capito bene perchè first viene passato alla funzione per valore);
Quindi sostanzialmente la domanda è questa: cosa devo modificare nel codice per fare in modo che quando cambio il valore di f (cioè l'indirizzo dell'inizio della lista) nella funzione, venga cambiato anche il valore di first? Come posso, cioè, passare per riferimento first a EliminaSchedeNulle()?

Ecco il link al codice: pastebin.com/…

#include <stdio.h>
#include <stdlib.h>
typedef enum {false, true} boolean; 

	struct nodo {
		int candidato;
		boolean valida;
		struct nodo *next;
	};

typedef struct nodo scheda;
scheda *first; //puntatore al primo elemento della lista
/* prototipi delle funzioni */
void InizializzaLista();
void AggiungiScheda(int candidato, boolean validita);
void ScriviSchede();
int ConteggioVotiValidi(int candidato, scheda* f);
int EliminaSchedeNulle(int candidato, scheda *f);
/* ## */

int main()
{

		//Variabili varie:
		int scelta; //Per la scelta del menu
		int candidato; //tiene un intero 1<=n<=4 riferito al candidato n
		int validita;//validità della scheda
		int jolly;
		int termina=0;
	InizializzaLista();
	while(termina==0){
	//Presento un menu di scelta
		printf("\n\n\nElezioni del nuovo Governatore di Elettolandia\n I candidati sono: '1', '2', '3', '4'\n");
		printf("Scegli fra le seguenti opzioni:\n\
			1) Aggiungi scheda\n\
			2) Vedi schede\n\
			3) Svuota Lista Schede\n\
			4) Conteggia Voti validi per un candidato\n\
			5) Elimina schede nulle per un candidato\n\
			6) Termina\n");

		//Faccio in modo che l'utente scelga un n 1<=n<=6 prima di continuare l'esecuzione
		do {
		printf("\nDigita la tua scelta: ");scanf("%d",&scelta);
		} while (scelta < 1 || scelta >6);

		switch (scelta) {
			case 1: //scelta==1
				printf("\nVoto per il candidato numero: ");scanf("%d",&candidato); 
				printf("\nScrivi 0 se la scheda è nulla, 1 se valida: ");scanf("%d",&validita); 
				AggiungiScheda(candidato, validita); 
				printf("Aggiunto un nuovo voto %s per il candidato %d\n\
Premere invio per continuare...", \
				first->valida?("valido"):("NON valido"), first->candidato);
				getchar();
				getchar();
				break;
			case 2:
				printf("** Inizio della lista **\n\
Indirizzo - Candidato - Validità - Successiva\n");
				ScriviSchede();
				printf("** Fine della lista **\n\
Premere invio per continuare...");getchar();getchar();
				break;
			case 3:
				InizializzaLista();
				printf("Lista svuotata!\nPremere un tasto per continuare");getchar();getchar();
				break;
			case 4:
				printf("\nInserire il numero del candidato di cui conteggiare i voti validi:");scanf("%d",&candidato);
				jolly=ConteggioVotiValidi(candidato,first); 
				printf("\nI voti validi per il candidato %d sono: %d",candidato,jolly);
				printf("\nPremi invio per continuare...");getchar();getchar();
				break;
			case 5:
				printf("\nInserire il numero del candidato di cui eliminare i voti nulli:");scanf("%d",&candidato);
				jolly=EliminaSchedeNulle(candidato,first);
				printf("\nEliminate %d schede",jolly);
				printf("\nPremi invio per continuare...");getchar();getchar();
				break;	
			case 6:
				termina=1;
		}
	}
	return (0);
}
//Inizializzazione della lista: si libera la memoria sfruttata precedentemente per la lista 
void InizializzaLista()
{
	scheda *temp;
	while (first!=NULL)
	{
		temp = first;
		first = first->next;
		free(temp);
	}
	//first=(scheda*) malloc(sizeof(scheda));
	return;
}

//Funzione per l'aggiunta di schede alla lista
void AggiungiScheda(int candidato, boolean validita) 
{
	scheda *nuova;
	nuova = (scheda*) malloc(sizeof(scheda));
	nuova->candidato=candidato;
	nuova->valida=validita;
	nuova->next=first;
	first=nuova;
	return;
}
//Stampa la lista
void ScriviSchede() {
	scheda *temp=first;
	while (temp!=NULL)
	{
		printf("%p           %d    -    %d   %p \n",temp,temp->candidato,temp->valida,temp->next);
		temp=temp->next;
	}
}

//Punto (ii)
int ConteggioVotiValidi (int candidato, scheda* f) //sto passando come parametro la lista solo perchè è richiesto esplicitamente nell'esercizio, ne farei a meno sfruttando il puntatore first che è dichiarato globalmente
{
	if (f==NULL) return 0; //controlla che la lista non sia vuota
	if (f->candidato==candidato && f->valida==true)
			return 1+ConteggioVotiValidi(candidato, f->next);		
	else
			return 0+ConteggioVotiValidi(candidato,f->next);
}
//Fine Punto (ii)

// punto (iii) 
int EliminaSchedeNulle(int candidato, scheda *f) //vedi commento a riga 132
{

	if (first == NULL) return 0; //Se la lista è vuota esce dalla funzione tornando 0
	if (first->next==NULL && first->candidato==candidato && first->valida==false) {InizializzaLista(); return 1;} //Nel caso in cui ci sia un solo elemento nella lista e questo elemento va eliminato, è necessario chiamare inizializzalista(); torna 1 perchè è coem fare una cancellazione
	int cancellazioni=0;
	scheda *temp, *prec;
	//Il primo ciclo fa in modo che f non sia un voto nullo al candidato passato come parametro
	while (first->candidato==candidato && first->valida==false) { //fin quando la prima scheda è un voto nullo a candidato
		temp=first->next;  //il primo elemento diviene quello successivo
		free(first); //libero la memoria del vecchio primo elemento
		first=temp;
		cancellazioni++; //incremento il numero di cancellazioni
	} 
	prec=first; //ho gia verificato che f non è una scheda nulla a candidato
	temp=prec->next; //controllo della scheda successiva alla prima "rimasta"
	while(temp!=NULL) {
		if (temp->candidato==candidato && temp->valida==false) {
			prec->next=temp->next; //Se la scheda puntata da temp non è valida allora la scheda precedente a temp (con prec->next=temp) dovrà puntare alla scheda successiva a temp (temp->next)
			free(temp); //Libero la memoria
			cancellazioni++; //incremento il numero di cancellazioni
			temp=prec->next;
		} else
		{
			prec=temp; //incremento prec
			temp=temp->next; //incremento temp
		}
	};
	return cancellazioni; //torna in output il numero delle cancellazioni effettuate 
}
// punto (iii)
Ultima modifica effettuata da WinstonS 12/12/10 21:49
aaa
12/12/10 17:17
Alex
per passare un valore per riferimento invece che per valore usa un puntatore a un puntatore...così puoi modificare il puntatore facendolo puntare da qualche altra parte...
aaa
12/12/10 20:12
WinstonS
Mai usati puntatori a puntatori; vediamo
il prototipo della funzione di questo tipo?
int EliminaSchedeNulle(int candidato, scheda **f)

e la chiamata alla funzione così? EliminaSchedeNulle(candidato,&first)[\code], dove candidato è un int e first è dichiarato come scheda *first[\code]...


E fin qui il programma va ma poi come opero all'interno di EliminaSchedeNulle?? *f->, *f., **f->, **f., (per fare un esempio di cose che non funzionano)?

aaa
12/12/10 21:46
WinstonS
Ecco così sembra andare (mi suggeriva lumo_e che si potrebbe semplificare la funzione EliminaSchedeNulle(...) ad un solo while, ma non sono arrivato a come fare).
Lo metto qui così che il post possa servire a qualcun altro.

/*
#include <stdio.h>
#include <stdlib.h>
typedef enum {false, true} boolean; 
struct nodo {
	int candidato;
	boolean valida;
	struct nodo *next;
}; typedef struct nodo scheda;

/* prototipi delle funzioni */
void InizializzaLista(scheda** f);
void AggiungiScheda(int candidato, boolean validita, scheda** f);
void ScriviSchede(scheda *f);
int ConteggioVotiValidi(int candidato, scheda* f);
int EliminaSchedeNulle(int candidato, scheda** f);

int main()
{
	//Variabili varie:
	int scelta; //Per la scelta del menu
	int candidato; //tiene un intero 1<=n<=4 riferito al candidato n
	int validita;//validità della scheda
	int jolly;
	int termina=0;
	scheda *first; //puntatore al primo elemento della lista
	InizializzaLista(&first);
	while(termina==0){
	//Presento un menu di scelta
		printf("\n\n\nElezioni del nuovo Governatore di Elettolandia\n I candidati sono: '1', '2', '3', '4'\n");
		printf("Scegli fra le seguenti opzioni:\n\
			1) Aggiungi scheda\n\
			2) Vedi schede\n\
			3) Svuota Lista Schede\n\
			4) Conteggia Voti validi per un candidato\n\
			5) Elimina schede nulle per un candidato\n\
			6) Termina\n");

		//Faccio in modo che l'utente scelga un n 1<=n<=6 prima di continuare l'esecuzione
		do {
		printf("\nDigita la tua scelta: ");scanf("%d",&scelta);
		} while (scelta < 1 || scelta >6);

		switch (scelta) {
			case 1:
				printf("\nVoto per il candidato numero: ");scanf("%d",&candidato); 
				printf("\nScrivi 0 se la scheda è nulla, 1 se valida: ");scanf("%d",&validita); 
				AggiungiScheda(candidato, validita, &first); 
				printf("Aggiunto un nuovo voto %s per il candidato %d\n\
Premere invio per continuare...", \
				first->valida?("valido"):("NON valido"), first->candidato);
				getchar();
				getchar();
				break;
			case 2:
				printf("** Inizio della lista **\n\
Indirizzo - Candidato - Validità - Successiva\n");
				ScriviSchede(first);
				printf("** Fine della lista **\n\
Premere invio per continuare...");getchar();getchar();
				break;
			case 3:
				InizializzaLista(&first);
				printf("Lista svuotata!\nPremere un tasto per continuare");getchar();getchar();
				break;
			case 4:
				printf("\nInserire il numero del candidato di cui conteggiare i voti validi:");scanf("%d",&candidato);
				jolly=ConteggioVotiValidi(candidato,first); 
				printf("\nI voti validi per il candidato %d sono: %d",candidato,jolly);
				printf("\nPremi invio per continuare...");getchar();getchar();
				break;
			case 5:
				printf("\nInserire il numero del candidato di cui eliminare i voti nulli:");scanf("%d",&candidato);
				jolly=EliminaSchedeNulle(candidato,&first);
				printf("\nEliminate %d schede",jolly);
				printf("\nPremi invio per continuare...");getchar();getchar();
				break;	
			case 6:
				termina=1;
		}
	}
	return (0);
}
//Inizializzazione della lista: si libera la memoria sfruttata precedentemente per la lista 
void InizializzaLista(scheda **f)
{
	scheda *temp;
	while ((*f)!=NULL)
	{
		temp = (*f);
		(*f) = (*f)->next;
		free(temp);
	}
	return;
}

//Funzione per l'aggiunta di schede alla lista
void AggiungiScheda(int candidato, boolean validita,scheda **f) 
{
	scheda *nuova = (scheda*) malloc(sizeof(scheda));
	nuova->candidato=candidato;
	nuova->valida=validita;
	nuova->next=(*f);
	(*f)=nuova;
	return;
}
//Stampa la lista
void ScriviSchede(scheda *f) {
	while (f!=NULL)
	{
		printf("%p           %d    -    %d   %p \n",f,f->candidato,f->valida,f->next);
		f=f->next;
	}
}

//Punto (ii)
int ConteggioVotiValidi (int candidato, scheda* f)
{
	if (f==NULL) return 0; //controlla che la lista non sia vuota
	if (f->candidato==candidato && f->valida==true)
			return 1+ConteggioVotiValidi(candidato, f->next);		
	else
			return 0+ConteggioVotiValidi(candidato,f->next);
}
//Fine Punto (ii)


int EliminaSchedeNulle(int candidato, scheda** f) 
{

	if ((*f) == NULL) return 0; //Se la lista è vuota esce dalla funzione tornando 0
	if ((*f)->next==NULL && (*f)->candidato==candidato && (*f)->valida==false) {InizializzaLista(f); return 1;} //Nel caso in cui ci sia un solo elemento nella lista e questo elemento va eliminato, è necessario chiamare inizializzalista(); torna 1 perchè è coem fare una cancellazione
	int cancellazioni=0;
	scheda *temp, *prec;
	//Il primo ciclo fa in modo che f non sia un voto nullo al candidato passato come parametro
	while ((*f)->candidato==candidato && (*f)->valida==false) { //fin quando la prima scheda è un voto nullo a candidato
		temp=(*f)->next;  //il primo elemento diviene quello successivo
		free((*f)); //libero la memoria del vecchio primo elemento
		(*f)=temp;
		cancellazioni++; //incremento il numero di cancellazioni
	}
	prec=(*f); //ho gia verificato che f non sia una scheda nulla a candidato
	temp=prec->next; //controllo della scheda successiva alla prima "rimasta"
	while(temp!=NULL) {
		if (temp->candidato==candidato && temp->valida==false) {
			prec->next=temp->next; //Se la scheda puntata da temp non è valida allora la scheda precedente a temp (con prec->next=temp) dovrà puntare alla scheda successiva a temp (temp->next)
			free(temp); //Libero la memoria
			cancellazioni++; //incremento il numero di cancellazioni
			temp=prec->next;
		} else
		{
			prec=temp; //incremento prec
			temp=temp->next; //incremento temp
		}
	};
	return cancellazioni; //torna in output il numero delle cancellazioni effettuate 
}
// punto (iii)

Ultima modifica effettuata da WinstonS 12/12/10 21:50
aaa
13/12/10 18:40
Alex
Postato originariamente da WinstonS:

Mai usati puntatori a puntatori; vediamo
il prototipo della funzione di questo tipo?
int EliminaSchedeNulle(int candidato, scheda **f)

e la chiamata alla funzione così? EliminaSchedeNulle(candidato,&first)[\code], dove candidato è un int e first è dichiarato come scheda *first[\code]...


E fin qui il programma va ma poi come opero all'interno di EliminaSchedeNulle?? *f->, *f., **f->, **f., (per fare un esempio di cose che non funzionano)?


mi pare che devi usare (*f)->
in quanto l'operatore -> ha la precedenza su *...
aaa
13/12/10 20:57
WinstonS
Si infatti ho fatto così :) Grazie mille
aaa
06/01/11 22:09
ramy
Un altro modo sarebbe di tenere un puntatore numerico che conitene il numero di strutture allocate e un bool che dice se la struttura va salvata o no.
Una volta creata la funzione di input sembre di programmare in python,basta solo liberare l' area di memoria (io non lo faccio perchè è un programma breve).

#include <stdio.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <malloc.h>
#include <time.h>


typedef struct
{
    bool save;
    char *nome;
    char *cognome;
}persona;



char *input(FILE *fp);
void add(persona *ptr,int *num);

int main(int argc,char **argv)
{
    persona *lista;
    int *num,i;
    num=(int*)malloc(sizeof(int));
    lista=(persona*)malloc(sizeof(persona));
    *num=0;
    for(i=0;i<3;i++)
      add(lista,num);
    printf("Output:\n");
    for(i=0;i<*num;i++)
      puts(lista[i].cognome);
    return 0;
}

char *input (FILE *fp)
{
    char *string;
    char check;
    string=(char*)malloc(sizeof(char));
    int i=1;
    while((check=fgetc(fp))!=10)
    {
        string[i-1]=check;
        i++;
        string=(char*)realloc(string,i*sizeof(char));
    }
    string[i-1]='Un altro modo sarebbe di tenere un puntatore numerico che conitene il numero di strutture allocate e un bool che dice se la struttura va salvata o no.

Una volta creata la funzione di input sembre di programmare in python,basta solo liberare l' area di memoria (io non lo faccio perchè è un programma breve).

#include <stdio.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <malloc.h>
#include <time.h>


typedef struct
{
    bool save;
    char *nome;
    char *cognome;
}persona;



char *input(FILE *fp);
void add(persona *ptr,int *num);

int main(int argc,char **argv)
{
    persona *lista;
    int *num,i;
    num=(int*)malloc(sizeof(int));
    lista=(persona*)malloc(sizeof(persona));
    *num=0;
    for(i=0;i<3;i++)
      add(lista,num);
    printf("Output:\n");
    for(i=0;i<*num;i++)
      puts(lista[i].cognome);
    return 0;
}

char *input (FILE *fp)
{
    char *string;
    char check;
    string=(char*)malloc(sizeof(char));
    int i=1;
    while((check=fgetc(fp))!=10)
    {
        string[i-1]=check;
        i++;
        string=(char*)realloc(string,i*sizeof(char));
    }
    string[i-1]='{parsed_message}';
    fflush(stdin);
    return string;
}

void add(persona *ptr,int *num)
{
    if(*num>1)
      ptr=(persona*)realloc(ptr,sizeof(persona));
    printf("Inserire nome:-->");
    ptr[*num].nome=input(stdin);
    printf("Inserire cognome:-->");
    ptr[*num].cognome=input(stdin);
    ptr[*num].save=true;
    (*num)++;
}


Ovviamente se non hai tempo di cambiarlo ti conviene lasciarlo così,molti usando il puntatore alla prossima struttura.
Ma in questo modo per aggiungerne una basta digitare (add,num),per cancellarne una basta mettere a falso il bool che dice di salvarla o no.
Alla fine del programma solo quelle col bool true vengono salvate sul file.



'; fflush(stdin); return string; } void add(persona *ptr,int *num) { if(*num>1) ptr=(persona*)realloc(ptr,sizeof(persona)); printf("Inserire nome:-->"); ptr[*num].nome=input(stdin); printf("Inserire cognome:-->"); ptr[*num].cognome=input(stdin); ptr[*num].save=true; (*num)++; }


Ovviamente se non hai tempo di cambiarlo ti conviene lasciarlo così,molti usando il puntatore alla prossima struttura.
Ma in questo modo per aggiungerne una basta digitare (add,num),per cancellarne una basta mettere a falso il bool che dice di salvarla o no.
Alla fine del programma solo quelle col bool true vengono salvate sul file.



aaa