[Solved] Need help i get segmentation fault in program in C


A proper implementation of getfiles (gets all the files in a directory in a dynamic array) and provides a deallocator:

#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 */
}

An example of how you could use it:

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);
}

Updated solution,

In order to implement your solution without using any of the library code, and keep it to system calls, here is an example that implements everything that the above example does, without relying on higher-level library calls.

Note

The bottom functions are the same as the above example.

/*
 * 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);
}

Hope you enjoy

5

solved Need help i get segmentation fault in program in C