【问题标题】:pointer problems when trying to build a directory tree in memory尝试在内存中构建目录树时出现指针问题
【发布时间】:2014-04-28 02:59:08
【问题描述】:

问题1:保存目录结构最好的数据结构是什么?

问题2:我试过用通用树来解决,但是问题很多:

  • 目录下的文件数不确定。所以一个树节点下的子节点数量也是不确定的。我尝试为每个节点添加一个关键字nchild,显示nchild 子节点。所以有指向子节点的nchild 指针(用**child 保存)。一旦那样,**child*child 应该被动态分配空间,没有特定的子节点。所以你知道,释放这些空间真的很难(而且下面的程序不叫free())。有没有更好的办法解决?
  • 有时下面的程序在我输出directory tree时会得到乱码,这让我很困惑。调试的时候发现是函数ent=readdir(pDir);读取了垃圾字符。但是当我编写另一个简单的程序来读取同一个目录时,一切顺利。我认为问题出在递归函数上,但我不知道。如果有人能给我一个想法,我将不胜感激。谢谢!

```

#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>

typedef struct tree_file_s
{
  char path[512];
  time_t date;
  char type;
  long size;
  int nchild;

  struct tree_file_s **child;
} tree_file_t;

int dir_child_len(const char *dir)
{
  int nchild = 0;
  DIR *pDir;
  struct dirent *ent;

  pDir = opendir(dir);
  while((ent=readdir(pDir)) != NULL)
  {
    if (strcmp(ent->d_name, ".")==0 || strcmp(ent->d_name, "..")==0) 
    {
      continue; 
    }
    nchild++;
  }

  return nchild;
}

void tree_create(tree_file_t *tft, const char *dir)
{
  int nchild; // the tft has n child
  DIR *pDir;
  struct dirent *ent; // the directory dir dirent info
  struct stat file_stat; // the new file's stat info

  stat(dir, &file_stat);
  nchild = dir_child_len(dir);
  pDir = opendir(dir);

  // Initialize the parent
  //tft->path = calloc(1, strlen(dir)+1);
  strcpy(tft->path, dir);
  tft->date = file_stat.st_mtime;
  tft->type = 'D';
  tft->size = file_stat.st_size;
  tft->nchild = nchild;
  tft->child = calloc(1, nchild);

  nchild = 0;
   while ((ent=readdir(pDir)) != NULL) 
   {
      if (ent->d_type & DT_DIR) 
      {
         if (strcmp(ent->d_name, ".")==0 || strcmp(ent->d_name, "..")==0) 
         {
           continue; 
         }
         tree_file_t *new_dir = calloc(1, sizeof(tree_file_t));
         tft->child[nchild] = new_dir;

         char *new_path = calloc(1, strlen(dir)+strlen(ent->d_name)+1);
         sprintf(new_path, "%s/%s", dir, ent->d_name);
         tree_create(new_dir, new_path);
         free(new_path);
      } else {
        tree_file_t *new_file = calloc(1, sizeof(tree_file_t));
        char *new_path = calloc(1, strlen(dir)+strlen(ent->d_name)+1);
        // new_file->path = calloc(1, strlen(dir)+strlen(ent->d_name)+1);
        sprintf(new_path, "%s/%s", dir, ent->d_name);
        stat(new_path, &file_stat);
        strcpy(new_file->path, new_path);
        free(new_path);
        new_file->date = file_stat.st_mtime;
        new_file->type = 'F';
        new_file->size = file_stat.st_size;
        new_file->nchild = 0;
        new_file->child = 0;

        tft->child[nchild] = new_file;
      }
      //free(new_path);
      //new_path = 0;
      nchild++;
   }
}

void display_tree(tree_file_t *tft)
{
  int nchild, i;

  nchild = tft->nchild;

  printf("%c: %s\n", tft->type, tft->path);

  for(i = 0; i < nchild; i++)
  {
    if(tft->child[i]->type == 'F')
    {
      printf("%c: %s\n",  tft->child[i]->type, tft->child[i]->path);
    } else {
      display_tree(tft->child[i]);
    }
  }
}

int main(int argc, const char *argv[])
{
  if(argc != 2)
  {
    printf("Usage: a.out dir\n");
    exit(0);
  }

  char dir[512];
  strcpy(dir, argv[1]);
  tree_file_t *tft = calloc(1, sizeof(tree_file_t));
  tree_create(tft, dir);
  display_tree(tft);

  return 0;
}

```

【问题讨论】:

    标签: c linux unix tree


    【解决方案1】:

    当您为new_path 分配空间时,您需要添加 2(一个用于斜杠,一个用于空终止符)。而且你永远不会关闭你打开的目录(使用 closedir())。

    更严重的错误是这一行:

    tft->child = calloc(1, nchild);
    

    只分配 nchild 字节,不足以容纳 nchild 指针!试试:

    tft->child = calloc(nchild, sizeof(*tft->child));
    

    【讨论】:

    • 是的,谢谢您的回答。但是当我尝试修改这两个地方时。 corrupted double-linked list: 发生在 closedir(pDir);
    • @xuefu 这表示堆损坏。我注意到另一个错误(可能是这个原因)。请参阅上面的编辑。
    • 不应该是calloc(nchild, sizeof(struct tree_file_s *))(一颗星)。也许更好calloc(nchild, sizeof(* tft-&gt;child))
    • @chux 是的。固定的。谢谢。
    • @xuefu:是的——你追踪你所做的每个分配并释放任何依赖分配,然后释放分配的空间。它需要一些照顾。对于您进行的每个分配,找出相应的free() 出现的位置。
    猜你喜欢
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 2015-05-14
    • 2016-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多