Sscanf

_prime_number
Ciao a todos!
Io dovrei leggere da file una stringa mista di numeri e caratteri. Solo che chiaramente i numeri mi servono non in formato carattere, ma come valori. Che comando devo usare? Sscanf? Non ho ben capito il suo funzionamento. Oppure devo scannerizzare come stringa di caratteri e poi convertire in qualche modo i numeri? Qualcuno magari può farmi un esempio?

Grazie!

Paola

Risposte
eugenio.amitrano
Per darti il miglior consiglio ho bisogno di alcune informazioni:

Il file e' un insieme di record ?
Il file viene gestito interamente dal tuo programma (che vuoi realizzare) ?
E' un file preso a caso da un'altra fonte che conosci la posizione e il formato dei dati da estrarre ?

_prime_number
Non so cosa sia un insieme di record..!
Cmq il file è gestito così: lo crea l'utente secondo certi parametri (è su più righe e ogni riga ha una determinato numero di caratteri. Il programma chiede il nome del file all'utente e poi legge una riga a caso (anche per questo effettivamete avrei bisogno di un consiglio? Come gli dico di leggere la riga n-esima invece di partire dalla 1°?).
Ti servono altre info? :)

Paola

eugenio.amitrano
Vediamo se ho capito.
Il file e' strutturato da un'insieme di righe in cui ogni riga e' formata da un'insieme di valori. Questo insieme di valori a livello testo e' visto come una stringa ovviamente).

Osservazione:
La stringa puo' contenere spazi se un valore e' pari a 32 (codice ascii dello spazio)
In questo caso sconsiglio la lettura a stringhe.

Domande:

1) I valori da leggere da quanti bit sono formati ?
Esempio:
(4 bit = ogni carattere costituisce 2 valori)
(8 bit = ogni carattere costituisce 1 valori)
(16 bit = ogni 2 caratteri costituiscono un 1 valore)

2) Ogni riga contiene sempre lo stesso numeri di valori ?
In questo caso utilizzeremo i record.

_prime_number
Ti faccio un esempio di riga

5--3--7-3-2-----9-4--9-3-1--

Ogni riga deve rappresentare uno schema di Sudoku.
i trattini "-" mi servono, perchè indicano uno spazio vuoto nello schema. Conta poi che tutti i numeri sono formati da una cifra sola essendo Sudoku. Ecco, il mio problema è: come faccio a leggere una riga "mista"?

Ogni riga, contiene 81 elementi. Il file che devo leggere contiene vari schemi e il mio programma poi ne sceglie uno a caso.

Paola

eugenio.amitrano
Ultime due domande e poi all'opera.

1) Vuoi rappresentare la griglia a video ?

2) Tra un sudoku e l'altro c'e' solo un invio ?
Cioe' e' scritto puro come segue:
--1--9--5-----4......
3--7---76----2.....
e non per esempio
Sudoku n.1 Griglia: ---4----7---5

_prime_number
Sì dopo la dovrò rappresentare in una finestra grafica.
Secondo te mi conviene considerarli come caratteri i numeri? Perchè dopo dovrò impostare un metodo risolutivo...

Per quanto riguarda le righe di file, sì sono "pure" TRa ogni schema c'è solo un invio, come nel primo esempio che hai fatto!! ;)

Paola

eugenio.amitrano
Perfetto!
utilizzero' un metodo standard C e tutto quello che scrivero' di seguito e' sempre da verificare.

Abbiamo bisogno di sapere quanti sudoku contiene il file.
(In questo caso ogni sudoku corrisponde ad un record).
Ogni riga contiene un record + un invio, siccome ogni record e' composto da 81 caratteri, ogni riga ha la dimensione di 82 caratteri, ossia 82 bytes.
La dimensione del file in bytes diviso 82 ci restituisce il numero dei record.

Dichiarazione varibili e costanti:
/* costanti */
#define nCol  9 // numero di colonne di un sudoku
#define nRow 9 // numero di righe di un sudoku
#define rowSize 82 // dimensione di una riga

/* struttura del sudoku */
/* matrice 9*9 */
typedef struct {
   char value[nCol][nRow];
} sudokuType;

/* variabili */
sudokuType sudoku; // variabile sudoku;
int sudokuValue[nCol][nRow]; valori numerici del sudoku che dovrai utilizzare successivamente
FILE *fp; // puntatore al file 
long fileSize; // dimensione del file
long numRec; // numero dei record ovvero dei sudoku
long index; // indice del sudoku da leggere


ricaviamo il numero dei record:
fp = fopen.... // esegui sempre il controllo dell'esistenza del file
fseek(fp, 0, SEEK_END); // si punta alla fine del file
fileSize = ftell(fp) + 1; // Un file e' grande quanto la sua posizione finale + 1
numRec = fileSize / rowSize;
fclose (fp);


generiamo il numero casuale del sudoku da leggere:
// ...non dimenticare il randomize nel main ....
index = rand() % numRec // restituisce un valore da 0 a numRec - 1


peschiamo il sudoku dal file:
fp = fopen.... // come prima esegui sempre il controllo dell'esistenza del file
fseek(fp, index * rowSize, SEEK_SET); // puntera' all'inizio del sudoku che vogliamo leggere
fread(fp, sizeof(sudokyType), 1, sudoku);
fclose(fp);


convertiamo i caratteri in numeri:
// scansione valore per valore
for(c = 0; c < nCol; c++)
   for(r = 0; r < nRow; r++)
      if(sudoku.value[c][r] == '-')
         sudokuValue[c][r] = 0;
      else
         sudokuValue[c][r] = sudoku.value[c][r] - 48;


credo che hai tutto per proseguire.
Se ti occorre un ulteriore aiuto anche su come rappresentare un sudoku oppure qualche chiarimento chiedi pure.

A presto,
Eugenio

_prime_number
Ok me lo sono letto attentamente e mi pare chiaro tutto. Una cosa: perchè proprio nell'ultima riga sottrai 48?

Grazie!!

Paola

eugenio.amitrano
Per convertire il carattere in numero.

Se tieni premuto ALT mentre scrivi 48 sul tastierino numerico e poi lo lasci e come se avessi premuto 0.
Perche' il codice ascii di 0 e' 48.

'0' = ascii 48 ossia 48 + 0
'1' = ascii 49 ossia 48 + 1
...
'9' = ascii 57 ossia 48 + 9

per esempio se sudoku.value[c][r] = '3'
e come se sudoku.value[c][r] = 51 quindi sudoku.value[c][r] - 48 = 3.

In sostanza 'x' = 48 + x quindi x = 'x' - 48 dove x va da 0 a 9.

ok ?

_prime_number
Ok tutto chiaro! Non sapevo questa cosa dell'ASCII!!

Se sorgono altri problemi scrivo sul forum, ma spero di doverti disturbare il meno possibile!! ;)

Grazie ancora, sei la mia salvezza!!

Paola

eugenio.amitrano
Disturba pure senza problemi.
E' un piacere per me.

A presto,
Eugenio

P.S.
Come hai potuto notare la conoscenza dei codici ascii aiuta a gestire i caratteri numericamente.
Su internet puoi trovare molto facilemnte una tabella di tutti i codici ascii.

Esempio di comodita':
immaginiamo una variabile (ch) di tipo carattere, che legge un carattere casuale dal file.
Per sapere se questa variabile contiene una lettera minuscola basta fare uno dei seguenti confronti:

codice ascii di 'a' = 97
codice ascii di 'z' = 122

if(ch >= 97 && ch <= 122)
{ ...e' una lettera minuscola...}

oppure piu' semplicemente

if(ch >= 'a' && ch <= 'z')
{ ...e' una lettera minuscola...}

se scrivo 'a' e 'z' al posto 97 e 122 non cambia nulla.

se vuoi verificare invece che si tratti di un numero scrivi:

if(ch >= 48 && ch <= 57)
{ ...e' un numero...}

oppure piu' semplicemente

if(ch >= '0' && ch <= '9')
{ ...e' un numero...}

Studente Anonimo
Studente Anonimo
"eugenio.amitrano":

         sudokuValue[c][r] = sudoku.value[c][r] - 48;



        sudokuValue[c][r] = sudoku.value[c][r] - '0';


Più portabile. ;)

eugenio.amitrano
Bravo!
Funziona anche scrivendo '0' al posto di 48.

Eugenio

groucho1
// scansione valore per valore
for(c = 0; c < nCol; c++)
   for(r = 0; r < nRow; r++)
      if(sudoku.value[c][r] == '-')
         sudokuValue[c][r] = 0;
      else
         sudokuValue[c][r] = sudoku.value[c][r] - 48;


lo farei diventare

// scansione valore per valore
for(c = 0; c < nCol; c++)
   for(r = 0; r < nRow; r++)
      sudokuValue[c][r] = (sudoku.value[c][r] == '-') ? 0 : atoi(sudoku.value[c][r]);


int atoi ( const char * string ), si trova nella stdlib.h e converte una stringa in un intero... perchè non usarla? :-D
per il resto il codice di eugenio.amitrano mi sembra molto buono :wink:

eugenio.amitrano
Ciao groucho, (questo personaggio mi e' molto simpatico)
benvenuto nel forum e complimenti per la preparazione informatica. Sono sicuro che la tua presenza dara' grande valore aggiunto al forum.

Volevo segnarti un'imprecisione:
atoi(sudoku.value[c][r]);
non funziona, perche' come hai scritto tu, vuole come parametro una stringa e non un carattere.
Per farla funzionare si potrebbe effettuare un trasferimento in una stringa di un carattere piu' il NIL.

A presto,
Eugenio

groucho1
vedi la fretta a volte? :oops:
ahah... non ci avevo nemmeno pensato al fatto che fosse un carattere... :D

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.