Programmino stupido, neofita in difficoltà

di il
9 risposte

Programmino stupido, neofita in difficoltà

Buongiorno a tutti,
sono nuovo del forum e nuovissimo in ambito programmazione (infima esperienza di un mesetto); e ovviamente già con l'ABC ho grossi problemi: è più di un'ora che non riesco a spiegarmi il perché il programma che segue non funziona.

Quello che vorrei fare è: utilizzando C, leggere da file .txt una serie di nomi e stampare su un altro file .txt i nomi in ordine di lettura, assegnando ad ogni nome un numero, che corrisponde a tutte le volte che il nome in questione è comparso. Chiaramente il programma non deve stampare lo stesso nome più di una volta.
Insomma: stampare su un file diverso quanti omonimi di ogni nome ci sono in elenco.

Per nome intendo un'intera riga di testo: il nome che deve considerare non termina con un blank, ma con un enter a capo.

Tanto per fare un esempio di quello che vorrei:

in:
Mario Rossi
Antonio Verdi
Pinco Pallino
Antonio Verdi

out:
Mario Rossi 1
Antonio Verdi 2
Pinco Pallino 1

ecco il programma:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define A 5000

typedef struct{
char Nome[40];
int cont;
}Omonimo;

void main()
{
FILE *f1,*f2;
int i,j;
int nNomiDiv=1;
Omonimo C[A];

for(i=0;i<A;i++)
C.cont=1;
//inizializzo i contatori


f 1=fopen("Arch_in.txt","r");
for(i=0;feof(f1);i++)
{
fscanf(f1,"%-s",C.Nome);
}
//leggo i nomi


for(i=0;feof(f1);i++)
{
for(j=0;j<i;j++)
{
if(C.Nome!=C[j].Nome) nNomiDiv++;

else if(C.Nome==C[j].Nome) C[j].cont++;
}
}
//conto gli omonimi e quanti nomi diversi ci sono


f2=fopen("Arch_out.txt","w");

for(i=0;i<=nNomiDiv;i++)
{
fprintf(f2,"%s ",C.Nome);
fprintf(f2,"%d\n",C.cont);
}
//teoricamente volevo fargli stampare con quest'ultimo ciclo tutti i nomi diversi ma mi rendo conto da solo che così dovrebbe stampare solo i primi "nNomiDiv" nomi.

fclose(f1);
fclose(f2);

system("PAUSE");
return 0;
}

Comunque il programma non fa quello desiderato, ma sul file di out stampa solo
1
1
I file sono nella cartella giusta e non riesco a trovare gli errori nella stesura del programma. Immagino ce ne siano miliardi ! Tra l'altro sono anche in difficoltà per quanto riguarda lo stampare tutti i primi nomi diversi che compaiono (perché il programma che ho scritto dovrebbe incrementare i contatori solo del primo degli omonimi, ma a questo punto non sono più sicuro nemmeno di quello ).

Grazie in anticipo per l'aiuto
Catullo

9 Risposte

  • Re: Programmino stupido, neofita in difficoltà

    Da quello che vedo il tuo problema è un problema di logica. Poi questa parte quì non ha senso e non capisco come il compilatore non ti dia errore.
    
    for(i=0;feof(f1);i++)
    {
    for(j=0;j<i;j++)
    {
    if(C[i].Nome!=C[j].Nome) nNomiDiv++;  //non puoi confrontare le stringhe così
    
    else if(C[i].Nome==C[j].Nome) C[j].cont++; // e anche quì stai confrontandoi puntatori.
    }
    } 
    
    
    la scelta giusta sarebbe quella di confrontare un nome con tutti quelli inseriti prima di metterlo nel vettore e di metterlo solo se questo non si trova nel vettore. Il confronto tra strignhe si fa con strcmp e non col segno di == o !=. Visto che sei in C non posso consigliarti neanche la classe std::string dove questa comparazione è possibile. Quindi ricapitolando: Lascia tutti i contatori a 0 e non metterli a 1. leggi da file. tieni traccia di quanti elementi diversi hai inserito fino a quel momento. Per ogni nome inserito confronta con strcmp se il nome appena letto da file è uguale o diverso. Inserisci il nome solo se diverso in una cella nuova e incrementi il contatore di nomi diversi, altrimenti incrementa il contatore del nome trovato. Alla fine stamperai solo le celle con il contatore diverso da 0. Questa è la logica del programma. Sta a te implementarlo nel modo giusto.
  • Re: Programmino stupido, neofita in difficoltà

    Grazie mille dell'aiuto !
    Ora riesco a fare eseguire il programma nel modo corretto, con un'unica riserva: non riesco a fare in modo che venga letta un'intera riga di testo come singola stringa. Il programma legge le singole parole e memorizza ognuna di esse nell'array della stringa.
    Con lo stesso esempio di prima:

    in:
    Mario Rossi
    Antonio Verdi
    Pinco Pallino
    Antonio Verdi

    out:
    Mario 1
    Rossi 1
    Antonio 2
    Verdi 2
    Pinco 1
    Pallino 1

    ho riscontrato un altro problema utlizzando elenchi più lunghi:

    in:
    Mario Rossi
    Antonio Verdi
    Pinco Pallino
    Antonio Verdi
    Antonio Verdi

    out
    Mario 1
    Rossi 1
    Antonio 3
    Verdi 3
    Pino 1
    Pallino 1
    Antonio 2
    Verdi 2

    il programma assegna al primo degli n omonimi il numero n, al secondo n-1, al terzo n-2 e così via, fino ad arrivare al penultimo a cui assegna 2 e all'ultimo a cui assegna 1.
  • Re: Programmino stupido, neofita in difficoltà

    Prova fgets invece di fscanf. fgets legge fino alla prima \n.
  • Re: Programmino stupido, neofita in difficoltà

    Posta il codice fin dove sei arrivato adesso. racchiudilo tra il tag code così si vede meglio. Può darsi ceh sbagli qualche passaggio durante il conteggio.
  • Re: Programmino stupido, neofita in difficoltà

    Come ti sembra questa soluzione?
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define A 5000
    
    typedef struct
    {
    	char Nome[40];
    	int cont;
    }Omonimo;
    
    int main()
    {
    	FILE *f1,*f2;
    	int i;
    	int nNomiDiv=0;
    	Omonimo C[A];
    
    	for(i=0;i<A;i++)
    		C[i].cont=0;
    //inizializzo i contatori
    
    
    	f1=fopen("Arch_in.txt","r");
    	char temp[40];
    	while(fgets(temp,40,f1) != NULL)
    	{
    		for(i = 0; i < nNomiDiv; i++)
    		{
    			if(!strcmp(temp,C[i].Nome))
    			{
    				C[i].cont++;
    				break;
    			}
    		}
    		if(i >= nNomiDiv)
    		{
    			strcpy(C[nNomiDiv].Nome,temp);
    			C[nNomiDiv].cont = 1;
    			nNomiDiv++;
    		}
    	}
    	//leggo i nomi
    
    	f2=fopen("Arch_out.txt","w");
    
    	for(i=0;i<nNomiDiv;i++)
    	{
    		fprintf(f2,"%s ",C[i].Nome);
    		fprintf(f2,"%d\n",C[i].cont);
    	}
    
    	fclose(f1);
    	fclose(f2);
    
    	system("PAUSE");
    	return 0;
    }
    
  • Re: Programmino stupido, neofita in difficoltà

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define A 5000

    typedef struct{
    char Nome[40];
    int cont;
    }Omonimo;

    void main()
    {
    FILE *f1,*f2;
    int i,j;
    Omonimo C[A];
    int nNomi=0;
    =fopen("arch_in.txt","r");
    f2=fopen("arch.out.txt","w");

    for(i=0;i<A;i++)
    {
    fgets(C.Nome,40,f1);
    nNomi++;
    puts(C.Nome);

    if(feof(f1)) break;}

    for(i=0;i<nNomi;i++)
    {
    for(j=0;j<i;j++)
    {
    if(strcmp(C.Nome,C[j].Nome)!=0) continue;

    else if(strcmp(C.Nome,C[j].Nome)==0) C[j].cont=C[j].cont+1;
    }
    }

    for(i=0;i<nNomi;i++)
    {if(C.cont>0)
    fputs(C.Nome,f2);
    fprintf(f2,"_%d",C.cont);
    }

    fclose(f1);
    fclose(f2);

    system("PAUSE");
    return 0;
    }


    Ecco cos'ho fatto fin'ora. Ma adesso mi stampa follie: stampando con fputs() tiene conto anche del cambio riga forse?

    Leggo adesso l'ultima risposta
  • Re: Programmino stupido, neofita in difficoltà

    Con le sistemazioni che hai fatto tu funziona tutto che è un piacere !
    Ora non mi resta che capire e applicarmi UN BEL PO', che ho ancora tutto da imparare. A partire dalla logica !

    questo comando
    !strcmp(temp,C.Nome)

    sta a significare
    C.Nome != temp

    giusto?

    Sul libro a cui sto facendo riferimento dice che strcmp() contronta due stringhe e se sono uguali restituisce 0, altrimenti valori positivi o negativi a seconda dei casi.
    Come funziona la negazione di strcmp ?

    Non mi spiego neanche un'altra cosa: hai messo l'unico fgets() all'interno della condizione di while. Mi sarei aspettato di rivederlo all'interno del ciclo e invece no. Perché non c'è?

    Ultimissima cosa: quando ho provato a compilare il programma mi diceva che per richiamare da gets() occorreva la funzione puts(). Sostituito fscanf con fputs ha per lo meno eseguito il programma.
    Con la tua soluzione invece non serve nessun puts(). Come mai?

    Sono profondamente grato per il tuo aiuto e la tua pazienza.
  • Re: Programmino stupido, neofita in difficoltà

    Non il contrario. Ti spiego come funziona.
    strcmp(temp,C.Nome) dovrebbe tornare 0 se sono uguali oppure !=0 se sono diversi. Ebbene tenendo in conto che a me servono uguali l'if si può scrivere come:
    
    if(strcmp(temp,C[i].Nome) == 0)
    
    ma siccome il 0 = false nulla mi vieta di scrivere:
    
    if(!strcmp(temp,C[i].Nome) == 1)  //significa se !false == true 
    
    ma siccome l'espressione dell'if è sempre valutata a 1 basta toglierlo e mettere:
    
    if(!strcmp(temp,C[i].Nome))
    
  • Re: Programmino stupido, neofita in difficoltà

    
     while(fgets(temp,40,f1) != NULL)
    
    vedi cosa ti dice la guida su fgets. ritorna NULL se c'è un errore oppure raggiunto la fine file. Quindi leggo il file finché non c'è un errore oppure non è stato raggiunto la fine. Non ho mai letto da nessuna parte che se usi fgets devi usare fputs x forza. Ognuno è libero di fare come vuole.
    COme ti ho detto in precedenza leggi il contenuto di una riga, confrontalo con tutte le righe inserite fino a quel momento è solo se la riga è diversa a tutte le righe inserite, inserisci anche quella. Quindi io non dupplico in nessun modo le righe all'interno dell'array.
Devi accedere o registrarti per scrivere nel forum
9 risposte