2012-10-16 8 views
0

J'écris une application simple qui affiche tous les fichiers dans un répertoire à la console. Pour ce faire, j'alloue dynamiquement de la mémoire dans la fonction PathCreator() et renvoie un pointeur vers cette mémoire. Je ne sais pas comment libérer correctement ce segment de mémoire dans GetAllFiles(). Lorsque j'utilise le code ci-dessous, j'obtiens une exception de dépassement de pile. Comment puis-je réparer cela? S'il vous plaît ne me propose pas d'utiliser quelque chose qui n'a pas besoin de mémoire allouée dynamiquement, je veux juste réparer mon code.Dépassement de pile dans la fonction récursive

#include "stdafx.h" 
#include <windows.h> 
#include <iostream> 
wchar_t *PathCreator(wchar_t *dir, wchar_t *fileName); 
int is_directory(wchar_t *p) 
{ 
    wchar_t *t = PathCreator(p,L"\\"); 
    WIN32_FIND_DATA file; 
    HANDLE search_hendle = FindFirstFile(t, &file); 
    long error = GetLastError(); 
    if(error == 267) 
    { 
     return 0; 
    } 
    else 
    { 
     return 1; 
    } 
} 

wchar_t *PathCreator(wchar_t *dir, wchar_t *fileName) 
{ 
    wchar_t* path = 0; 
    int size = 0; 
    wchar_t *d = dir; 
    wchar_t *f = fileName; 
    while(*d != '\0') 
    { 
     d++; 
     size++; 
    } 
    while(*f != '\0') 
    { 
     f++; 
     size++; 
    } 
    path = new wchar_t[(size+=3) * sizeof(wchar_t)]; 
    int j = 0; 
    while(j < size) 
    { 
     path[j] = '\0'; 
     j++; 
    } 
    int i; 
    i = 0; 
    while(*dir != '\0') 
    { 
     path[i] = *dir; 
     i++; 
     dir++; 
    } 
    path[i++] = '\\'; 
    wchar_t *t = fileName; 
    while(*t != '\0') 
    { 
     path[i] = *t; 
     i++; 
     t++; 
    } 
    path[i] = '\0'; 
    return path; 
} 

void GetAllFiles(wchar_t* dir) 
{ 
    wchar_t *p = 0; 

    int i = 0; 
    WIN32_FIND_DATA file; 
    wchar_t *t = PathCreator(dir, L"*"); 
    HANDLE search_hendle = FindFirstFile(t, &file); 
    if(search_hendle) 
    { 

     do 
     { 
      p = PathCreator(dir,file.cFileName); 
      if(!is_directory(p)) 
      { 
       std::wcout << p << std::endl; 
      } 
      else 
      { 
       GetAllFiles(p); 
      } 
      delete [] p; 
     } 
     while(FindNextFile(search_hendle, &file)); 

    } 
    delete [] t; 
    FindClose(search_hendle); 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    GetAllFiles(L"C:\\Users"); 
} 
+0

Le rendre itératif? –

+0

@John Dibling Pouvez-vous décrire cela plus en détail? – abilash

+3

Légèrement hors-sujet: C et C++ ne sont pas le même langage. Comme il est clair que vous utilisez C++, il peut être judicieux de travailler sur vos concepts C++. Par exemple, pourquoi 'new' et' delete' sont déconseillés (en faveur des pointeurs intelligents), et pourquoi utiliser 'std :: string' (ou' std :: wstring') est préférable à l'utilisation de pointeurs de type C. – tenfour

Répondre

1

Encore une fois, vous essayez d'utiliser C en place de C++ et vous utilisez toujours wcout?! Pas de problème, vous êtes un programmeur et je suis sûr que vous avez une raison pour cela! mais la gestion de la mémoire dans C est beaucoup plus difficile que C++ et vous devriez avoir quelques compétences pour l'utiliser. Voici un code fonctionnant pleinement mais comme vous le voyez, il est vraiment plus difficile à gérer, utiliser et comprendre que sa version C++ en utilisant des conteneurs et des chaînes standard, donc si vous êtes autorisé à utiliser C++ (alors que vous utilisez wcout) aisance:

#include <Windows.h> 
/*! \brief Merge \a folder and \a filename into a newly allocate memory and 
* return it to the caller. Use free to free returned memory! 
*/ 
wchar_t* PathCreator(wchar_t const* folder, wchar_t const* filename) 
{ 
    wchar_t* res; 
    size_t i, len, folderLen = wcslen(folder), filenameLen = wcslen(filename); 
    len = folderLen + filenameLen; 
    if(folder[folderLen - 1] != '\\') ++len; 
    ++len; // for \0 

    res = (wchar_t*) malloc(sizeof(wchar_t) * len); 
    if(!res) return NULL; 

    wcscpy_s(res, len, folder); 
    /* Remove possible wide card at end of folder */ 
    for(i = folderLen; i--;) { 
     if(res[i] == '*' || res[i] == '?') { 
      res[i] = 0; 
      --folderLen; 
     } else { 
      break; 
     } 
    } 
    if(res[folderLen - 1] != '\\') wcscat_s(res, len, L"\\"); 
    wcscat_s(res, len, filename); 

    return res; 
} 
/*! \brief Free memory that returned by \ref GetAllFiles 
*/ 
void FreeAllFilesMemory(wchar_t** p) 
{ 
    wchar_t** tmp = p; 
    if(!p) return ; 
    while(*tmp) free(*tmp++); 
    free(p); 
} 
wchar_t** AddToArray(wchar_t** p, size_t* pAllocated, size_t* pUsed, wchar_t* s) 
{ 
    if(*pUsed >= *pAllocated) { 
     size_t newAlloc = *pAllocated * 3/2; // Grow by 1.5 
     if(newAlloc < 16) newAlloc = 16; 
     p = (wchar_t**) realloc(p, newAlloc * sizeof(wchar_t*)); 
     if(!p) return NULL; 
     *pAllocated = newAlloc; 
    } 

    p[*pUsed] = s; 
    ++*pUsed; 
    return p; 
} 
wchar_t** GetAllFilesImpl(wchar_t const* folder, wchar_t** res, size_t* pAllocated, size_t* pUsed) 
{ 
    HANDLE hSearch; 
    WIN32_FIND_DATAW fileinfo; 
    size_t allocatedMemory = 0; 

    hSearch = FindFirstFileW(folder, &fileinfo); 
    if(hSearch != INVALID_HANDLE_VALUE) { 
     do { 
      wchar_t* sFileName, ** tmp, sTmp[ 1024 ]; 
      /* ignore ., .. */ 
      if(!wcscmp(fileinfo.cFileName, L".") || 
       !wcscmp(fileinfo.cFileName, L"..")) 
       continue; 
      sFileName = PathCreator(folder, fileinfo.cFileName); 
      wprintf(L"%s\n", sFileName); /* Print result */ 
      tmp = AddToArray(res, pAllocated, pUsed, sFileName); 
      if(!tmp) return FreeAllFilesMemory(res), NULL; 
      res = tmp; 
      if(fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 
       wcscpy_s(sTmp, sFileName); 
       wcscat_s(sTmp, L"\\*"); 
       tmp = GetAllFilesImpl(sTmp, res, pAllocated, pUsed); 
       if(!tmp) return NULL; 
       res = tmp; 
      } 
     } while(FindNextFileW(hSearch, &fileinfo)); 
     FindClose(hSearch); 
    } 
    return res; 
} 
/*! \brief List all files that match a pattern and return it as an array of 
* wide strings, free result using \ref FreeAllFilesMemory 
*/ 
wchar_t** GetAllFiles(wchar_t const* folder) 
{ 
    size_t nAllocated = 0, nUsed = 0; 
    wchar_t** res = GetAllFilesImpl(folder, NULL, &nAllocated, &nUsed); 
    if(res) { 
     /* to indicate end of result add a NULL string */ 
     wchar_t** tmp = AddToArray(res, &nAllocated, &nUsed, NULL); 
     if(!tmp) return FreeAllFilesMemory(res), NULL; 
     res = tmp; 
    } 
    return res; 
} 
+0

Juste un moment je l'essaie – abilash

+0

O man, c'est magique. C'est ce que j'ai cherché. Comment écrivez-vous ce code si rapidement? Savez-vous que je vais poser cette question?)) – abilash

+0

Non, je suis en programmation C/C++ pendant 12 ans jour et nuit, mais cela prend 10 minutes pour que je l'écrive, mais pour sa version C++ je l'écris dans un minute ou deux. Donc, c'est ce que je dis, c'est vraiment, vraiment plus difficile de coder en C, donc pour l'usage que vous utilisez C++ :) – BigBoss

8

Donc, vous avez "." et ".." dans votre recherche d'annuaire.

La première entrée est donc "":

p = PathCreator(dir, file.cFilename) 

rendements:

"C:\Users\." 

Puis la ligne suivante:

if (!is_directory(p)) 

est toujours faux, il ne cesse récursif en:

GetAllFiles(p) 

pour toujours ... ou jusqu'à ce que votre pile explose, selon la première éventualité ;-)

Je recommande de vérifier explicitement « » et ".." et en sautant ces entrées (aussi MFC et Qt, etc. ont de belles classes de gestion d'annuaire, mais je pense que vous voulez le faire de cette façon).

Ma modification:

do 
    { 

     // I added this - guess I can't embolden code text 
     if (wcscmp(file.cFileName,L".") == 0 || wcscmp(file.cFileName,L"..")==0) 
      continue; 

     p = PathCreator(dir,file.cFileName); 
     if(!is_directory(p)) 
     { 
      std::wcout << p << std::endl; 
     } 
     else 
     { 
      GetAllFiles(p); 
     } 
     delete [] p; 
    } 
    while(FindNextFile(search_hendle, &file)); 
+0

Si je change de code pour ignorer les répertoires "." et ".." ce serait du travail? D'autres choses sont correctes? – abilash

+1

@Vsevywniy: Surtout, j'ai ajouté le test (voir mod ci-dessus) et il récursif mon répertoire C: \ Users correctement. Il y a une erreur plus tard dans PathCreator() où il obtient une chaîne sans un terminateur nul, mais c'est une autre question ;-) –

+0

Quand j'utilise ta boucle cela fonctionne sans crash mais il n'affiche rien. Je pense que si le problème - chaîne terminée par zéro, il y a des déchets ont apparence ou accident? Mais il ne montre rien. – abilash

Questions connexes