简体   繁体   English

递归函数中的堆栈溢出

[英]Stack overflow in recursive function

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. 为此,我在PathCreator()函数中动态分配内存,并返回指向该内存的指针。 I don't know how to correctly free this memory segment in GetAllFiles() . 我不知道如何在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). 和“ ..”并跳过这些条目(MFC和Qt等也具有不错的目录处理类,但我认为您想这样做)。

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 ?! 再次,您尝试使用C代替C++并且仍在使用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. 但是C内存管理比C++难得多,因此您应该掌握一些使用它的技能。 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: 这是一个可以正常工作的代码,但是正如您所见,它比使用标准容器和字符串的C ++版本更难管理,使用和理解,因此,如果允许使用C ++(如使用wcout ),则可以使用其C ++版本缓解:

#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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM