首先,我将解释我要编程的内容。我想打开一个目录并获取所有文件名及其编号(在目录中)。我想为找到的文件数量分配一定数量的内存,并为它们的名称分配一定数量的内存。我举一个例子。

可以说我们有一个名为dir的目录,该目录中有4个文件。这四个文件的名称如下:lalocamomarasarw

我希望我的程序按以下方式工作

进入dir并在查找文件的同时不断分配内存以存储它们(就像一个字符串表,我不知道确切大小,因为我不知道要找到多少个文件)。我逐个字符地存储文件名,并且每次读取一个字符时,我都会根据需要不断分配内存,我正在重新分配内存并递增1。遵循相同的逻辑,我遵循文件编号,在此文件中我不断增加文件数量并重新分配内存如所须。我想像这样的表(指针)是filenames[numberOfFiles][stringCharacter].

我在第二个循环的函数GetFiles(...)中遇到分段错误:*(*(entries+*number)+size) = dp->d_name[size];

int main()
{
    int number,i;
    char *mainDirectory = NULL,**names = NULL;

    printf("Give the movies directory: ");
    mainDirectory = ReadMainDirectory();



    if(GetFiles(mainDirectory,&names,&number) != 0)
    {


        system("PAUSE");
        return 1;
    }

    system("PAUSE");
    return 0;
}

char* ReadMainDirectory()
{
    char *dir,c;
    int size = 1;

    dir = (char*)malloc(size+1);
    dir[size-1] = '\0';

    while((c = getchar()) != '\n')
    {
        dir[size-1] = c;
        size++;

        dir = (char*)realloc(dir,size+1);
        dir[size-1] = '\0';
    }

    return dir;
}

int GetFiles(char *dir,char ***names,int *number)
{
    struct dirent *dp;
    DIR *fd;
    int size;
    char **entries = NULL;

    if ((fd = opendir(dir)) == NULL)
    {
        printf("Can't open directory %s!\n",dir);
        return 0;
    }

    *number = 0;
    size = 0;

    entries = (char**)malloc((*number+1) * sizeof(char*));
    *entries = (char*)malloc((size+1) * sizeof(char));

    while ((dp = readdir(fd)) != NULL)
    {
        if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
        {
            continue;
        }

        size = 0;

        while(dp->d_name[size] != '\0')
        {
            *(*(entries+*number)+size) = dp->d_name[size];
            size++;
            *(entries+*number) = (char*)realloc(entries[*number],(size+1) * sizeof(char));
        }

        entries[*number][size] = '\0';

        printf("%s\n",entries[*number]);

        (*number)++;

        entries = (char**)realloc(entries,(*number+1) * sizeof(char*));
    }

    *names = entries;

    closedir(fd);

    return 1;
}

int GetStringSize(char *string)
{
    int size = 0;

    while(string[size] != '\0')
    {
        size++;
    }

    return size;
}

int StringEndsWith(char* string,char* extension)
{
    return !strcmp(string + strlen(string) - strlen(extension), extension);
}

最佳答案

getfiles的正确实现(获取动态数组中目录中的所有文件)并提供解除分配器:

#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>

/* returns a NULL terminated array of files in directory */

char **getfilelist(const char *dirname) {
        DIR *dp;
        char **entries = NULL;
        struct dirent *entry;
        off_t index = 0;

        dp = opendir(dirname);
        if (!dp) {
                perror(dirname);
                return NULL;
        }

        while((entry = readdir(dp)) != NULL) {
                /* increase entries array size by one pointer-size */
                entries = realloc(entries, (1+index)*sizeof(char *));

                /* strdup returns a newly allocated duplicate of a string that
                 * you must free yourself
                 */
                entries[index] = strdup(entry->d_name);
                index++;
        }

        /* need one more entry for NULL termination */
        entries = realloc(entries, (1+index)*sizeof(char *));
        entries[index] = NULL;

        return entries;
}

void putfilelist(char **entries) {
        char **p;
        if(!entries)
                return;
        for(p = entries; *p !=NULL ; p++) {
                free(*p); /* free all the strdups */
        }
        free(entries); /* free the array of pointers */
}


有关如何使用它的示例:

int main(int argc, char **argv) {
        char **p, **entries;
        char *dir = (argc == 1 ? "." : argv[1]);
        entries = getfilelist(dir);
        for (p = entries; p && *p; p++) {
                printf("%s\n", *p);
        }
        putfilelist(entries);
}


更新了解决方案,

为了在不使用任何库代码的情况下实现您的解决方案,并将其保留给系统调用,以下是一个示例,该示例实现了上面示例所做的所有操作,而无需依赖更高级别的库调用。

注意

底部功能与以上示例相同。

/*
 * A partially low-level implementation using a direct system calls
 * and internal memory management
 *
 * This is an opinionated (linux only) implementation of OP
 *
 * linux headers are only included for some of the constants and
 * where it would be trivial to re-implement system calls (e.g. open, write etc.)
 * which I am too lazy to do in this example.
 *
 */

#define NDEBUG

#include <stdarg.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/fcntl.h>
#include <linux/unistd.h>

/* replace this macro with your own error handling messages */
#define handle_error(msg) \
    do { my_fdputs(2, msg); my_exit(-127); } while (0)

#if !defined(NDEBUG)
#define assert(x) do { int __rv = (x); if(!__rv) { my_fdprintf(2, "assertion failed %s\n", #x); my_exit(__rv); } } while(0)
#else
#define assert(x) do {} while(0)
#endif



/* returns a NULL terminated array of files in directory */
/* low-level list builder using getdents */

void my_exit(int x)
{
    syscall(SYS_exit_group, x);
}

/* a trivial malloc / realloc / free */

/* simple linked list memory accounting */
struct memblock {
    struct memblock *next;
    size_t size;
    int free; /* flag */
    int magic; /* canary value for debugging */
};

#define METASIZE sizeof(struct memblock)

void *global_base = NULL;

struct memblock *find_free_block(struct memblock **last, size_t size)
{
    struct memblock *current = global_base;
    while(current && !(current->free && current->size >= size)) {
        *last = current;
        current = current->next;
    }
    return current;
}


/*
 * instead of using sbrk, we should really use mmap on newer
 * linux kernels and do better accounting, however this is a
 * simple example to get you started
 */

struct memblock *request_space(struct memblock *last, size_t size)
{
    struct memblock *block;
    void *request;

    block = sbrk(0); /* get current program break */
    request = sbrk(size + METASIZE);
    assert((void *)block == request);
    if(request  == (void *)-1) {
        return NULL;
    }

    if(last) {
        last->next = block;
    }
    block->size = size;
    block->next = NULL;
    block->free = 0;
    block->magic = 0x12345678;

    return block;
}

struct memblock *get_memblock_ptr(void *ptr)
{
    return (struct memblock *)ptr - 1;
}

/* a simple memcpy, can be optimized by taking alignment into account */

void *my_memcpy(void *dst, void *src, size_t len)
{
    size_t i;
    char *d = dst;
    const char *s = src;
    struct memblock *bd, *bs;
    bd = get_memblock_ptr(dst);
    for(i = 0; i < len; i++) {
        d[i] = s[i];
    }
    return dst;
}

/* now to implement malloc */
void *my_malloc(size_t size)
{
    struct memblock *block;

    if(size == 0)
        return NULL;

    if(!global_base) {
        block = request_space(NULL, size);
        if(!block)
            return NULL;
        global_base = block;
    }
    else {
        struct memblock *last = global_base;
        block = find_free_block(&last, size);
        if(!block) {
            block = request_space(last, size);
            if(!block) {
                return NULL;
            }
        }
        else {
            block->free = 0;
            block->magic = 0x77777777;
        }
    }

    return (block+1);
}

void my_free(void *ptr)
{

    struct memblock *block;
    if (!ptr)
        return;

    block = get_memblock_ptr(ptr);
    assert(block->free == 0);
    assert(block->magic == 0x77777777 || block->magic == 0x12345678);
    block->free = 1;
    block->magic = 0x55555555;
}


void *my_realloc(void *ptr, size_t size)
{
    struct memblock *block;
    void *newptr;

    if(!ptr)
        return my_malloc(size);

    block = get_memblock_ptr(ptr);
    if(block->size >= size)
        return ptr;

    newptr = my_malloc(size);
    if(!newptr)  {
        return NULL;
    }

    my_memcpy(newptr, ptr, block->size);
    my_free(ptr);
    return newptr;
}


/* trivial string functions */

size_t my_strlen(const char *src) {
    size_t len = 0;
    while(src[len])
        len++;
    return len;
}

char *my_strdup(const char *src)
{
    char *dst;
    char *p;
    size_t len = 0, i;
    len = my_strlen(src);


    dst = my_malloc(1+len);
    if(!dst)
        return NULL;

    for(i = 0; i < len; i++) {
        dst[i] = src[i];
    }
    dst[i] = 0;
    return dst;
}


/* trivial output functions */

my_fdputs(int fd, const char *str)
{
    return write(fd, str, my_strlen(str));
}

int my_fdputc(int fd, char c)
{
    return write(fd, &c, sizeof(char));
}

/* a very limited implementation of printf */
int my_fdvprintf(int fd, const char *fmt, va_list ap)
{
    const char *p;
    int count = 0;
    for(p = fmt; p && *p; p++ ) {
        if(*p == '%')  {
            p++;
            switch(*p) {
            case 's':
                count += my_fdputs(fd, va_arg(ap, char *));
                break;
            case '%':
                count += my_fdputc(fd, '%');
                break;
            default:
#ifndef NDEBUG
                my_fdputs(2, "warning: unimplemented printf format specifier %");
                my_fdputc(2, *p);
                my_fdputc(2, '\n');
#endif
                break;
            }
        }
        else {
            my_fdputc(fd, *p);
        }
    }
    return count;
}

int my_fdprintf(int fd, const char *fmt, ...)
{
    int rv;
    va_list ap;
    va_start(ap, fmt);
    rv = my_fdvprintf(fd, fmt, ap);
    va_end(ap);
    return rv;
}


/* wrapper to linux getdents directory entry call */
/* linux dirent structure */
struct linux_dirent {
    long           d_ino;
    off_t          d_off;
    unsigned short d_reclen;
    char           d_name[];
};

/* system call wrapper */
int getdents(int fd, void *buf, size_t bufsize)
{
    return syscall(SYS_getdents, fd, buf, bufsize);
}


/* reimplement getfilelist using our getdents */
#define BUF_SIZE 1024
char **getfilelist(const char *dirname) {
    int fd, nread;
        char **entries = NULL;
        off_t index = 0;

    char buf[BUF_SIZE];
    struct linux_dirent *d;
    int bpos;


    /* O_DIRECTORY since kernel 2.1 */
        fd = open(dirname, O_DIRECTORY|O_RDONLY);

        if (fd < 0) {
                handle_error(dirname);
        }

    for(;;) {
        nread = getdents(fd, buf, BUF_SIZE);
        if (nread == -1)
            handle_error("getdents");

        if (nread == 0)
            break;

        for (bpos = 0; bpos < nread;) {
            d = (struct linux_dirent *) (buf + bpos);
            entries = my_realloc(entries, (1+index) * sizeof(char *));
            entries[index++] = my_strdup(d->d_name);
            bpos += d->d_reclen;
                }
    }

       /* need one more entry for NULL termination */
        entries = my_realloc(entries, (1+index)*sizeof(char *));
        entries[index] = NULL;

    close(fd);

    return entries;
}

void putfilelist(char **entries) {
        char **p;
        if(!entries)
                return;
        for(p = entries; *p !=NULL ; p++) {
                my_free(*p); /* free all the strdups */
        }
        my_free(entries); /* free the array of pointers */
}


int main(int argc, char **argv) {
        char **p, **entries;
        char *dir = (argc == 1 ? "." : argv[1]);
        entries = getfilelist(dir);
        for (p = entries; p && *p; p++) {
                my_fdprintf(1, "%s\n", *p);
        }
        putfilelist(entries);
}


希望你喜欢

10-08 12:42