Conversione modulo e segno
La funzione di cui riporto il codice legge dei numeri da file e li converte in modulo e segno su 10 bit:
In pratica ho un problema con la stampa. Nel codice sopra riportato ce ne sono 2, una all'interno del ciclo while (messa come commento), che ad ogni iterazione mi stampa i numeri correttamente. L'altra stampa invece, (al di fuori del ciclo) mi stampa i numeri tutti insieme ed p quella che mi crea problemi. In pratica se i numeri sono 3 la stampa la effettua in questo modo :
1° num : 3inbinario2inbinario1inbinario
2° num : 2inbinario1inbinario
3° num : 1inbinario
qualcuno può aiutarmi a trovare l'errore ?
Grazie in anticipo!
void conversione(int vetnum[], char nbin[][MBIT], int *n) { int i,j,num; for(i=0;i<*n;i++) { num=fabs(vetnum[i]); j=10; if (vetnum[i]>0) nbin[i][0]='0'; else nbin[i][0]='1'; nbin[i][11]='\0'; while(num>=1) { if(num%2==0) nbin[i][j]='0'; if(num%2==1) nbin[i][j]='1'; num=num/2; j--; /*printf("%s\n", nbin[i]);*/ } for(j=j;j>0;j--) nbin[i][j]='0'; } for(i=0;i<*n;i++) printf("Numero modulo e segno : %s\n", nbin[i]); }
In pratica ho un problema con la stampa. Nel codice sopra riportato ce ne sono 2, una all'interno del ciclo while (messa come commento), che ad ogni iterazione mi stampa i numeri correttamente. L'altra stampa invece, (al di fuori del ciclo) mi stampa i numeri tutti insieme ed p quella che mi crea problemi. In pratica se i numeri sono 3 la stampa la effettua in questo modo :
1° num : 3inbinario2inbinario1inbinario
2° num : 2inbinario1inbinario
3° num : 1inbinario
qualcuno può aiutarmi a trovare l'errore ?
Grazie in anticipo!
Risposte
MBIT quanto vale?
11, dal momento che la conversione è a 10 bit l'undicesimo è ' \0 '
Non ho guardato con attenzione il programma, ma ci sono alcune cose strane nel tuo codice:
1. Perché n è passato come puntatore? Non sembra essere necessario in quanto il numero di valori non dovrebbe cambiare all'interno della funzione;
2. Perché utilizzi fabs (definito per valori double) per calcolare il valore assoluto di un numero intero? Stai facendo un inutile conversione tra valori interi e double e viceversa. Esiste la funzione abs definita in stdlib.h (cstdlib se usi il C++) per calcolare il valore assoluto di un intero.
3. Se devi comunque scrivere tutti i valori dell'array non ha senso usare come terminazione di ciclo num>=1. C'è infatti il rischio che il numero richieda più di 10bit e che sovrascriva il bit di segno (e altro oltre l'inizio dell'array) e richiede la scrittura di due cicli. E' molto meglio fare un ciclo su tutti i bit da settare in cui continui a dividere il numero e a calcolarne il modulo.
Alcune note meno importanti:
1. num>0 è normalmente meglio di num>=1.
2. Non è necessario usare due if, uno per num%2==0 e l'altro per num%2==1, per considerare tutti i valori binari. E' sufficiente testare per uno dei due e poi usare il ramo else per l'altro.
Ma nessuna di queste osservazioni sembra spiegare il comportamento strano che hai descritto (anche se non sono certo di averlo compreso del tutto).
1. Perché n è passato come puntatore? Non sembra essere necessario in quanto il numero di valori non dovrebbe cambiare all'interno della funzione;
2. Perché utilizzi fabs (definito per valori double) per calcolare il valore assoluto di un numero intero? Stai facendo un inutile conversione tra valori interi e double e viceversa. Esiste la funzione abs definita in stdlib.h (cstdlib se usi il C++) per calcolare il valore assoluto di un intero.
3. Se devi comunque scrivere tutti i valori dell'array non ha senso usare come terminazione di ciclo num>=1. C'è infatti il rischio che il numero richieda più di 10bit e che sovrascriva il bit di segno (e altro oltre l'inizio dell'array) e richiede la scrittura di due cicli. E' molto meglio fare un ciclo su tutti i bit da settare in cui continui a dividere il numero e a calcolarne il modulo.
Alcune note meno importanti:
1. num>0 è normalmente meglio di num>=1.
2. Non è necessario usare due if, uno per num%2==0 e l'altro per num%2==1, per considerare tutti i valori binari. E' sufficiente testare per uno dei due e poi usare il ramo else per l'altro.
Ma nessuna di queste osservazioni sembra spiegare il comportamento strano che hai descritto (anche se non sono certo di averlo compreso del tutto).
"Ryuzaky*":
11, dal momento che la conversione è a 10 bit l'undicesimo è ' \0 '
E allora il problema è questo.
Se MBIT=11, ogni riga di nbit è composta da 11 char con indici da 0 a 10; quindi il terminatore zerochar '\0' va in posizione 10, e l'ultimo "bit" è in posizione 9.
Ma nel tuo codice hai
// some stuff before... j=10; // ... nbin[i][11]='\0'; //...
Chiaro?

PS. I consigli di apatriarca sono precisi; un'altra cosa:
// before for(j=j;j>0;j--) // after for(;j>0;j--)
Ovvero, è inutile assegnare j a sè stesso (anche se il compilatore normalmente queste cose le toglie da solo).
E' molto meglio fare un ciclo su tutti i bit da settare in cui continui a dividere il numero e a calcolarne il modulo.
Ho corretto gli accorgimenti suggeriti


Magari potrei in precedenza imporre il rango di valori ammissibili.
Se MBIT=11, ogni riga di nbit è composta da 11 char con indici da 0 a 10; quindi il terminatore zerochar '\0' va in posizione 10, e l'ultimo "bit" è in posizione 9.
Ho corretto anche questo ma purtroppo ho ancora lo stesso problema

Riporto l'intero codice, magari cosi risulta più chiaro :
#include<stdio.h> #include<stdlib.h> #define N 50 #define MBIT 11 int lettura(int vetnum[]); void conversione(int vetnum[], char nbin[][MBIT], int n); main(){ int vettorenumeri[N]; int dim; char numerobinario[N][MBIT]; dim=lettura(vettorenumeri); conversione(vettorenumeri,numerobinario,dim); system("pause"); } int lettura(int vetnum[]) { int i=0; FILE *fp; char nomefile[N]; printf("Inserisci il nome del file da aprire:\n\n"); scanf("%s", nomefile); fp=fopen(nomefile,"r"); while(feof(fp)==0) { fscanf(fp,"%d",&vetnum[i]); i++; } return i; } void conversione(int vetnum[], char nbin[][MBIT], int n) { int i,j,num; for(i=0;i<n;i++) { num=abs(vetnum[i]); j=10; if (vetnum[i]>0) nbin[i][0]='0'; else nbin[i][0]='1'; nbin[i][10]='\0'; while(num>0) { if(num%2==0) nbin[i][j]='0'; else nbin[i][j]='1'; num=num/2; j--; } for(;j>0;j--) nbin[i][j]='0'; } for(i=0;i<n;i++) printf("Numero modulo e segno : %s\n", nbin[i]); }
Ma nessuna di queste osservazioni sembra spiegare il comportamento strano che hai descritto (anche se non sono certo di averlo compreso del tutto).
Mi spiego meglio : Se i numeri in binario sono "0000001111","1000100101","0000000010" la stampa avviene in questo modo :
000000111110001001010000000010
10001001010000000010
10000000010
Quello che intendevo con quella frase è che tu prima fai un ciclo fino a che num sia maggiore di zero, considerando quindi tutte le cifre e poi azzeri le cifre mancanti. Il problema è che num potrebbe avere troppe cifre e quindi il tuo codice potrebbe sovrascriverti locazioni di memoria al di fuori dell'array (oltre che al bit di segno e al terminatore di ciclo). Siccome dividendo zero per due si continua ad ottenere zero e continueresti quindi ad ottenere il risultato corretto anche se il numero di cifre fosse inferiore al massimo, tanto vale fare il ciclo su tutte le cifre e ignorare il reale numero di cifre del numero. Cioè:
invece che i tuoi due cicli.
for (int j = 9; j > 0; --j) { if (num % 2 == 1) nbin[i][j] = '1'; else nbin[i][j] = '0'; num/=2; }
invece che i tuoi due cicli.
"Ryuzaky*":
Ho corretto anche questo ma purtroppo ho ancora lo stesso problema![]()
Certo: nel codice corretto, è rimasta l'assegnazione j=10 nella funzione di conversione.
Ma come ho detto prima:
- ogni riga è di 11 caratteri
- gli indici di colonna, per ogni riga, vanno da 0 a 10
- il terminatore zerochar va in posizione 10 (e l'hai corretto)
- la tua conversione comincia impostando il carattere di indice 10 (j=10) invece che dal carattere di indice 9
Chiaro adesso?
Fatte salve le osservazioni di apatriarca, va senza dire.
Chiaro ! Grazie mille ad entrambe
