Newsgroup: it.comp.lang.c++
Titolo: *** Un programmino che funziona a meta' ***

Arieccomi. Vi sottopongo un programmino di esercizio.
Il prog. deve stampare tutte le directory dell'unità c:
Il programma però non visualizza tutte le directory, ma solo
una parte (ad esempio, su 175 ne stampa 30).
Dove sto sbagliando ?
(per comodità di lettura ho tralasciato le parti del programma
che non interessano).
Grazie in anticipo
                                  Milla
......................................
char chBufDir[300][30]    // le dir. in c: sono meno di 300
int WINAPI WinMain(...)
{
...
}
LONG WINAPI WndProc(...)
{
...
	switch(messg)
	{
...
        nvoci = i = 0;
        trova_e_inserisce_voce("c:\\");
		hdc=BeginPaint(hWnd,&ps);
		for(i=0; i<=nvoci; i++)
		{
           sLenght=sprintf(szMessage,"-> %s",chBufDir[i]);
     	   TextOut(hdc,0,charht*(i-NewVPos),szMessage,sLenght);
		}
		ValidateRect(hWnd,NULL);
		EndPaint(hWnd,&ps);
		break;
...
}
int se_dir(DWORD qt)
{
		switch (qt)
		{
		case FILE_ATTRIBUTE_ARCHIVE: 
				return(0);
				break;
		case FILE_ATTRIBUTE_DIRECTORY:  
                return(1);
				break;
		default:
			return(0);
			break;
		}
		return(0);
}
void trova_e_inserisce_voce(char *Dir_Corrente)
{
BOOL fRC;
WIN32_FIND_DATA ffd;
HANDLE hFindFile;
		SetCurrentDirectory(Dir_Corrente);
		hFindFile=FindFirstFile("*.*",&ffd);     
		if (se_dir(ffd.dwFileAttributes) == 1)   
		    if(strcmp(ffd.cFileName,"."))
			{
			   strcpy(chBufDir[nvoci],ffd.cFileName);
			   nvoci++;
			}
		for(;;)
		{
			fRC=FindNextFile(hFindFile,&ffd);
			if(fRC==FALSE)
			{
				FindClose(hFindFile);
				break;
			}
			else
			{
        		if (se_dir(ffd.dwFileAttributes) == 1)      
                   if(strcmp(ffd.cFileName,".."))
				   {
                   strcpy(chBufDir[nvoci],ffd.cFileName);
				   nvoci++;
		           trova_e_inserisce_voce(ffd.cFileName);
				   }
			}
		}
}

Probabilmente il problema sta nel fatto che sposti continuamente la
directory corrente. Come si comporta FindNextFile se nel frattempo la
directory e' cambiata? Non lo so. Teoricamente dovrebbe andare ma non si
puo' mai dire.
Ciao
Antonio Donatiello

 Dove sto sbagliando ?
Se vedo bene, la funzione trova_e_inserisce_voce() utilizza nvoci che
non è stato dichiarato (ma non ti dà nessun errore?). Forse volevi che
utilizzasse quello della funzione WndProc() ma allora devi passarglielo
come parametro.
EMG

Il problema ha due cause:
1 - La funzione 'trova_e_inserisce_voce' ha un bug.
2 - Anche la funzione 'se_dir' ha un bug.
Il primo bug
FindClose(hFindFile);          // tuo codice
SetCurrentDirectory("..");    // linea aggiunta
break;                               // tuo codice
La linea che ho aggiunto è importante, perché riporta la directory corrente
nello stato in cui era prima che la ricorsione attuale della funzione fosse
invocata, permettendo così alle funzioni Find* della ricorsione di livello
immediatamente superiore di lavorare sulla directory corretta.
L'altro bug
'dwFileAttributes' è un campo in cui ogni flag è rappresentato da un
singolo bit; quindi non puoi fare un controllo per valore, ma devi testare
solo quel bit che rappresenta il flag che ti interessa. Infatti quelle
cartelle che hanno altri flag impostati oltre a 'FILE_ATTRIBUTE_DIRECTORY'
(come le cartelle nascoste e quelle a sola lettura) non passano questo
controllo. Tutta la funzione si riduce a:
int se_dir(DWORD qt)
{
 if(qt & FILE_ATTRIBUTE_DIRECTORY) return 1;
 return(0);
}
In questo modo se il flag 'FILE_ATTRIBUTE_DIRECTORY' è impostato, il file
viene riconosciuto come cartella indipendentemente dal fatto che possa
avere anche altri attributi.
Riguardo al buffer
Il nome di un file (quindi anche quello di una cartella) potrebbe essere
composto da più di 30 caratteri. Il numero massimo di caratteri da cui può
essere composto un nome di file è rappresentato dalla costante _MAX_FNAME
definita in 'stdlib.h'; quindi:
char chBufDir[300][_MAX_FNAME];
Stefano.

 char chBufDir[300][_MAX_FNAME];
...
Ok anche questo l'ho inserito. 
Una domanda: considerando che questa è una
maniera _assai_ barbara di cercare informazioni sul disco sulle directory,
e che questo è solo un esercizio, come posso dimensionare la
prima dimensione del buffer, se non so a priori quante possono essere
le directory ?
............
Ed ora un'altra considerazione, forse la più intelligente che mi 
è venuta:
Se (sempre nel caso della ricerca delle directory), sempre
rimanendo (per ora) nell'ottica del C (non C++) gestissi questo
problema dinamicamente con la creazione e la ricerca di un albero B ?
Non sarebbe un pochino più elegante (ed efficente ?)
Intanto, caro Stefano, Grazie dei preziosi consigli.
 
 Milla

 perchè le directory della mia unità c: sono 426)
...
Non è vero niente. Le directory del mio disco sono _molte_
di più, come ho potuto facilmente constatare con la
funziona *Trova* di Windows.
Dimensionando il buffer in maniera esatta funziona
tutto alla perfezione, e con il tuo suggerimanto
il numero delle directory
trovate dal mio programmino e dalla funzione Trova
di Win coincidono.
Avevi in ogni caso ragione tu. L'errore era dovuto
allo *sforamento* del buffer.
...sono ancora molte le cose che devo imparare...
Ancora grazie
                                                     Milla

...sono ancora molte le cose che devo imparare...
Quest'ultima affermazione vale, penso, per noi tutti (il
giorno in cui smettero` di avere cose da imparare sara`
certo quello che mi sotterrano...), comunque, in particolare,
una cosa che _ho_ imparato e` di non rendermi la vita
piu` difficile di quanto gia` non sia: la libreria standard
del C++, specialmente std::vector e std::string, risolve
tantissime situazioni in cui "sforamenti di buffer",
problemi di allocazone e liberazione memoria, ecc,
sono, altrimenti, rischi molto frequenti.
Alex

Non sarebbe un pochino piů elegante (ed efficente ?)
Ti consiglio di scrivere su it.comp.lang.c se vuoi discutere
di soluzioni C (non C++); su questo gruppo si dovrebbe
invece parlare di C++.
Alex

le directory ?
Potresti utilizzare una struttura capace di ridimensionarsi dinamicamente tipo
una queue o uno stack. Per inciso la scelta della struttura non e` irrilevante, con una
coda realizzi una ricerca breadth-first, con uno stack invece una depth-first.
STL fornisce gia` queste (ed altre) strutture, se non vuoi utilizzare STL puoi
sempre considerale la realizzazione di di questa struttura come un esercizio dentro
un altro.
Paolo
----------------------------------------------------------
  Paolo Marotta
  Computer Science, University of Pisa
  home:   
http://www.cli.di.unipi.it/~marotta
  e-mail: 
mar...@cli.di.unipi.it
 
----------------------------------------------------------

 Non sarebbe un pochino più elegante (ed efficente ?)
Sicuramente; in effetti un semplice elenco di directory non ti serve a
niente; non è una struttura visitabile gerarchicamente. Chiaramente hai
bisogno di una struttura intelligente se vuoi fare qualche cosa di utile
con l'immagine di una directory. Mi pare che anche qui, la libreria
standard del C++ ti venga incontro; se non sbaglio, infatti, fornisce anche
un'implementazione di albero B, ma non ti so dire di più. Comunque, è
comprensibile che, per esercizio, tu voglia provare a implementare tutto da
te.
Stefano.

un'implementazione di albero B, ma non ti so dire di più. Comunque, è
No; la libreria standard del C++ tipicamente *usa* una struttura
ad albero bilanciato (specificamente, un red-black tree) per la
implementazione di map<>, set<>, ecc, ma non la rende in modo
diretto disponibile.  Qua, comunque, non servirebbe (non c'e` il
bilanciamento, ecc).
Un albero N-ario di nodi di tipo X si implementa d'altronde
banalmente:
template<class X>
class TreeLevel {
    std::vector<TreeLevel> children;
    // anche uno std:: set puo` aver senso
    TreeLevel* parent;    // per comodita`
public:
    // ctor, accessori, ecc
};
Alex