Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Переполнение стека при рекурсии

67K
11 марта 2011 года
commeta
3 / / 11.03.2011
Здравствуйте!,

первая программа на си, пишу рекурсивный обход каталога с подкаталогами.
В случае большой глубины рекурсии программа вызывает переполнение стека.
Подскажите как правильно делать рекурсию в данном случае? (чтобы stack overflow не происходило).
Код:
#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;
}


Windows console app, borland c++ builder
9.0K
11 марта 2011 года
grag63
71 / / 23.01.2006
Возможны 3-а варианта:
1-ый - вместо фиксированных массивов (char mask[32768];) использовать динамические (char *mask). Данный вариант частично решает (увеличивает рекурсию) проблему.
2-ой - убрать фиксированные массивы и работать только с path (char *fnm = path + strlen(path); strcpy(fnm, name); dirIter(path); *fnm = 0;)
3-й - отказаться от рекурсии и обходить в одном цикле, управляя уровнями. Данный вариант посложнее, но не имеет подобных ограничений.
67K
11 марта 2011 года
commeta
3 / / 11.03.2011
grag63
Переписал в соответствии вашим рекомендациям, работает! :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;
}
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог