I am writing a simple app that outputs all files in some directory to console. To achieve this I dynamically allocate memory in function PathCreator()
and return a pointer to this memory. I don't know how to correctly free this memory segment in GetAllFiles()
. When I use the code below I get a stack overflow exception. How can I fix this? Please don't offer me to use something that doesn't need dynamically allocated memory, I just want to fix my code.
#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");
}
So, you have "." and ".." in your directory search.
The first entry is ".", so:
p = PathCreator(dir, file.cFilename)
yields:
"C:\Users\."
Then the next line:
if (!is_directory(p))
Is ALWAYS false, so it just keeps recursing into:
GetAllFiles(p)
forever ... or until your stack blows up, whichever comes first ;-)
I would recommend explicitly checking for "." and ".." and skipping those entries (also MFC and Qt, etc. have nice directory handling classes, but I think you want to do it this way).
My 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));
Again you try to use C
in place of C++
and you still using wcout
?! no problem you are a programmer and I'm sure you have a reason for this! but memory management in C
is much much harder than C++
and you should have some skills to use it. Here is a fully working code but as you see it is really harder to manage, use and understand than its C++ version using standard containers and string, so if you are allowed to use C++(as you use wcout
) then use its C++ version for ease:
#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;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.