#pragma argsused
#include <stdio.h>
#include <string.h>
#include <dir.h>
#include <windows.h>
void dirIter(char * path)
{
struct ffblk file_info;
int done;
char mask[32768];
char opath[32768];
char npath[32768];
char name[255];
char oname[255];
CharToOem(path, opath);
printf( "%s\n", opath );
strcpy(mask, path);
strcat(mask, "\\*");
done= findfirst(mask, &file_info, FA_DIREC);
while(!done)
{
strcpy(name, file_info.ff_name);
CharToOem(name, oname);
if( file_info.ff_attrib == FA_DIREC )
{
if( strlen(name) < 3 )
{
if( strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
{
strcpy(npath,path);
strcat(npath, "\\");
strcat(npath, name);
dirIter(npath);
printf("\n\n\n");
}
}
else
{
strcpy(npath,path);
strcat(npath, "\\");
strcat(npath, name);
dirIter(npath);
printf("\n\n\n");
}
}
else
{
printf(" %s\n", oname);
}
done = findnext(&file_info);
}
}
int main(void)
{
char path[32768];
strcpy(path, "d:\\Kino");
dirIter(path);
getchar();
return 0;
}
Переполнение стека при рекурсии
первая программа на си, пишу рекурсивный обход каталога с подкаталогами.
В случае большой глубины рекурсии программа вызывает переполнение стека.
Подскажите как правильно делать рекурсию в данном случае? (чтобы stack overflow не происходило).
Код:
Windows console app, borland c++ builder
1-ый - вместо фиксированных массивов (char mask[32768];) использовать динамические (char *mask). Данный вариант частично решает (увеличивает рекурсию) проблему.
2-ой - убрать фиксированные массивы и работать только с path (char *fnm = path + strlen(path); strcpy(fnm, name); dirIter(path); *fnm = 0;)
3-й - отказаться от рекурсии и обходить в одном цикле, управляя уровнями. Данный вариант посложнее, но не имеет подобных ограничений.
Переписал в соответствии вашим рекомендациям, работает! :D
подскажите еще: проверку для malloc надо делать? (выделилась память или нет).
Код:
#include <stdio.h>
#include <string.h>
#include <dir.h>
#include <windows.h>
#include <alloc.h>
char start[]= "d:\\Kino"; // Начало просмотра
char astr[32768]; // Переменная для ansyprint, чтобы каждый раз память не выделять, делаем это вначале
bool isValidDir(char *name) // Проверка каталога
{
if(strlen(name) < 3)
{
if(strcmp(name, ".") == 0) return false;
if(strcmp(name, "..") == 0) return false;
}
return true;
}
void ansyprint(char *str) // Для вывода cp1251 в консоль
{
CharToOem(str, astr);
printf("%s", astr);
}
void dirIter(char *dir) // Итерация по каталогу, рекурсия
{
int done;
struct ffblk file_info;
int n= strlen(dir) + strlen(start); // Считаем сколько нежно памяти
char *mask=(char*)malloc(n+2); // Выделяем память
char *nmask=(char*)malloc(n+1);
// Подготавливаем переменные
strcpy(mask, start);
strcat(mask, dir);
strcpy(nmask, mask);
strcat(mask, "*");
done= findfirst(mask, &file_info, FA_DIREC); // Первый проход
while(!done) // Цикл следующих проходов
{
if( file_info.ff_attrib == FA_DIREC ) // Если это каталог
{
if( isValidDir(file_info.ff_name) )
{
char *ndir=(char*)malloc(n + 1 + strlen(file_info.ff_name));
strcpy(ndir, dir);
strcat(ndir, file_info.ff_name);
strcat(ndir, "\\");
dirIter(ndir);
free(ndir);
}
}
else // Если это файл
{
ansyprint(nmask);
ansyprint(file_info.ff_name);
printf("\n");
}
done = findnext(&file_info);
}
free(mask); // Освобождаем память
free(nmask);
}
int main(void)
{
char dir[]= "\\";
dirIter(dir);
getchar();
return 0;
}
#include <string.h>
#include <dir.h>
#include <windows.h>
#include <alloc.h>
char start[]= "d:\\Kino"; // Начало просмотра
char astr[32768]; // Переменная для ansyprint, чтобы каждый раз память не выделять, делаем это вначале
bool isValidDir(char *name) // Проверка каталога
{
if(strlen(name) < 3)
{
if(strcmp(name, ".") == 0) return false;
if(strcmp(name, "..") == 0) return false;
}
return true;
}
void ansyprint(char *str) // Для вывода cp1251 в консоль
{
CharToOem(str, astr);
printf("%s", astr);
}
void dirIter(char *dir) // Итерация по каталогу, рекурсия
{
int done;
struct ffblk file_info;
int n= strlen(dir) + strlen(start); // Считаем сколько нежно памяти
char *mask=(char*)malloc(n+2); // Выделяем память
char *nmask=(char*)malloc(n+1);
// Подготавливаем переменные
strcpy(mask, start);
strcat(mask, dir);
strcpy(nmask, mask);
strcat(mask, "*");
done= findfirst(mask, &file_info, FA_DIREC); // Первый проход
while(!done) // Цикл следующих проходов
{
if( file_info.ff_attrib == FA_DIREC ) // Если это каталог
{
if( isValidDir(file_info.ff_name) )
{
char *ndir=(char*)malloc(n + 1 + strlen(file_info.ff_name));
strcpy(ndir, dir);
strcat(ndir, file_info.ff_name);
strcat(ndir, "\\");
dirIter(ndir);
free(ndir);
}
}
else // Если это файл
{
ansyprint(nmask);
ansyprint(file_info.ff_name);
printf("\n");
}
done = findnext(&file_info);
}
free(mask); // Освобождаем память
free(nmask);
}
int main(void)
{
char dir[]= "\\";
dirIter(dir);
getchar();
return 0;
}