【问题标题】:Opening multiple directories in C在 C 中打开多个目录
【发布时间】:2021-12-01 09:50:31
【问题描述】:

我正在尝试制作一个程序来创建一个目录,在该目录中创建多个目录,然后在每个目录中创建一个文件。我似乎无法打开那些“多个目录”,以便我可以将我的文件放在那里。我尝试使用name3 作为参数,还尝试使用name3 的值创建一个const char*,但没有任何效果。

error: malloc.c:2379: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed. Aborted (core dumped)

这是我的代码

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

int make_directory(char * name) {
    int checker=mkdir(name, S_IRWXU | S_IRWXG | S_IRWXO);
    return checker;
}



char** getNames() {
    char** names=malloc(10*sizeof(char*));
    for(int i=0;i<10;i++) {
        
        
        if(i==9) {
            names[i]=malloc(3*sizeof(char));
            names[i][0]='1';
            names[i][1]='0';
            names[i][2]='\0';
        } else {
            names[i]=malloc(2*sizeof(char));
            names[i][0]=49+i;
            names[i][1]='\0';
        }
    }
    return names;
}

int makeTenDirs() {
    char **names=getNames();
    char *name2;
    for(int i=0;i<10;i++) {

        name2=NULL;
        name2=getcwd(NULL,0);
        strncat(name2,"/input/dir",11);
        strncat(name2,names[i],1);
        int s=make_directory(name2);

    }
    name2=NULL;
    name2=getcwd(NULL,0);
    strncat(name2,"/input/dir",11);
    strncat(name2,names[0],1);
    strncat(name2,"0",2);
    int s=make_directory(name2);

}

int main() {
    char **names=getNames();
    FILE *file;
    DIR *dir;
    DIR *dir2;
    struct dirent *dent;
    char * name1="./input";
    char *name3;
    int proceed=make_directory("./input");
    if(proceed==-1) {
        printf("Error making the directory\n");
    }
    makeTenDirs();
    dir=opendir("./input");
    if(dir!=NULL) {
        name3=getcwd(NULL,0);
        while((dent=readdir(dir))!=NULL){
            if(strcmp(dent->d_name,"..")!=0 && strcmp(dent->d_name,".")!=0) {
                name3=getcwd(NULL,0);
                strncat(name3,"/input/",8);
                
                strncat(name3,dent->d_name,10);
                printf("%s\n",name3);

                dir2=opendir(name3);
                if(dir2!=NULL) {
                    printf("alo");
                }
            }
        }
    }

    closedir(dir);
    free(names);
    return 0;
}

关于如何打开目录(或者将文件放入其中)的任何提示?

【问题讨论】:

  • 来自getcwd man page:“如果bufNULL...size 是0...buf 分配得尽可能大”。 name2 可能没有足够的空间容纳后续的 strncats,并且您正在溢出该缓冲区。
  • 我应该如何绕过它?有什么办法可以打开我的目录?
  • 你可以给name2一个足够大的初始尺寸,比如char name2[512]; getcwd(name2, sizeof name2);,或者在getcwd返回时保持原样和reallocname2为更大的尺寸。手册页显示“路径名作为函数结果返回,并通过参数 buf,如果存在。” IMO 有点奇怪,但这给了你一些选择。您应该始终检查NULL 的返回值,指示错误。
  • 这是我看到的第一个潜在问题,可能还有其他问题。
  • 不要做类似49+i的事情。请改写'1'+i。请注意,您可能会在此处引入一个错误。

标签: c file pointers directory


【解决方案1】:

下面是一个有效的实现。我清理了所有警告(您有一些未使用的变量,makeTenDirs 没有返回值)。 总是查看并修复警告,使用-Wall -Wextra 标志来启用它们。正如我之前所想的那样,您正在通过overwriting the buffersname2name3 调用undefined behavior。您使用getcwd 的方式为name2name3 分配了足够的空间。只要你strcat 到那个,你覆盖缓冲区,调用UB。那时,程序可能会以完全不可预测的方式运行,包括看起来可以工作。您希望当存在 UB 时您的程序会崩溃,因此您会收到有关问题的警报。下面,我使用了getcwd 的第二种操作模式,它不在内部malloc 内存中,而是将所有内容保存在自动内存中(在堆栈上)。这使您不必手动管理内存。我已经包含了希望解释一切的 cmets,如果您有任何问题,请告诉我。

#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <linux/limits.h>  // for PATH_MAX

int make_directory(char * name) {
    int checker=mkdir(name, S_IRWXU | S_IRWXG | S_IRWXO);
    return checker;
}

char** getNames() {
    char** names=malloc(10*sizeof(char*));
    for(int i=0;i<10;i++) {
        if(i==9) {
            names[i]=malloc(3*sizeof(char));
            names[i][0]='1';
            names[i][1]='0';
            names[i][2]='\0';
        } else {
            names[i]=malloc(2*sizeof(char));
            names[i][0]='1'+i;
            names[i][1]='\0';
        }
    }
    return names;
}

int makeTenDirs(char** names) {
    // This is where your problems began.  As I suggested before and confirmed
    // when I actually ran the code, `getcwd(NULL, 0)` returns a pointer to
    // dynamically allocated memory that's just big enough to hold the path.
    // As soon as you strcat to that, you overflow the buffer causing
    // undefined behavior.  It crashed for me 2nd time through the loop, not
    // immediately when the UB occurred.  Your results could be entirely different,
    // that is the essence of UB.  To fix it, I will declare an automatic array
    // of PATH_MAX large (4096 I believe).  That should make this fixed size array
    // able to handle any path on your _linux_ box (this code will not be portable
    // to windows).  Alternatively, you could do what you did before, just be sure
    // to realloc the name2 memory _before_ strcat'ing so there's enough room for
    // "/input/dir"
    char name2[PATH_MAX];
    // only acceptable place for one character variable names are loop index
    // variables, and you'll even get some argument on that.  Give your variables
    // descriptive names (although, I'd probably just make this function void, not
    // much utility in the return value here, which you didn't even return!)
    int directoryMade = 0;

    for(int i=0;i<10;i++) {
        // This returns NULL if the `sizeof name` (==PATH_MAX == 4096) is too
        // small to hold the path.  That shouldn't be the case since no paths
        // on the system should exceed PATH_MAX, but it's always a good idea
        // to check for errors, that's what a lot of your C code should be
        // doing, so get in the habit. Also, realize your old way created
        // a memory leak each time since each call to getcwd would malloc more
        // memory, and you overwrite the pointer to the previous block with the
        // pointer to the new block. Now nothing is pointing at the previous
        // block so you can't free it --> memory leak.
        if (getcwd(name2, sizeof name2) == NULL)
        {
            perror("Path exceeded buffer length");
            exit(-1);
        }
        // should be plenty of space to strcat now
        strncat(name2,"/input/dir",11);
        strncat(name2,names[i],1);
        // not much utility b/c it keeps getting overwritten. You could check it each time
        // and return if there's an error
        directoryMade=make_directory(name2);
    }

    if (getcwd(name2, sizeof name2) == NULL)
    {
        perror("Path exceeded buffer length");
        exit(-1);
    }
    strncat(name2,"/input/dir",11);
    strncat(name2,names[0],1);
    strncat(name2,"0",2);
    directoryMade=make_directory(name2);

    return directoryMade;
}

int main() {
    char **names=getNames();
    DIR *dir;
    DIR *dir2;
    struct dirent *dent;
    int proceed=make_directory("./input");
    if(proceed==-1) {
        // you print an error here, but continue on anyway
        // as if there was no error
        printf("Error making the directory\n");
    }
    makeTenDirs(names);  // you already fetched names, use them!
    dir=opendir("./input");
    if(dir!=NULL) {
        // same problem here. name3 holds _exactly_ how much space it
        // needs when you allow getcwd to malloc memory for it. As before,
        // you can make name3 an array in automatic storage, or realloc it
        // before strcat'ing
        char name3[PATH_MAX];
        // check for NULL return here too. Not showing it because I'm getting lazy
        getcwd(name3, sizeof name3);
        while((dent=readdir(dir))!=NULL){
            if(strcmp(dent->d_name,"..")!=0 && strcmp(dent->d_name,".")!=0) {
                // check for NULL return
                getcwd(name3, sizeof name3);
                strncat(name3,"/input/",8);

                strncat(name3,dent->d_name,10);
                printf("%s\n",name3);

                dir2=opendir(name3);
                if(dir2!=NULL) {
                    // printf is line-buffered, so this won't print right away unless
                    // you put a newline on it (or fflush(stdout);)
                    printf("alo\n");
                    // close this dir too?
                    closedir(dir2);
                }
            }
        }
    }

    closedir(dir);
    // this is NOT a complete free. You have a double pointer. You need to loop and
    // free each of names[0], names[1], .. names[9], _then_ free(names). I'll leave
    // that as an exercise. In general, you should have a matching number of malloc's
    // and free's.
    free(names);
    return 0;
}

【讨论】:

  • 谢谢!不久前我设法让它工作,并决定回来告诉你我修复了它。我的实现发生了一些变化,但仍然不如你的那么好,所以我将努力重写代码。
  • @RaresAmza 很高兴听到它!找出问题的痛苦通常是最好的学习方式。
猜你喜欢
  • 1970-01-01
  • 2017-07-25
  • 1970-01-01
  • 2010-09-22
  • 1970-01-01
  • 2011-04-03
  • 2015-07-06
  • 1970-01-01
  • 2016-01-04
相关资源
最近更新 更多