zancudo
zancudo

Reputation: 355

issue with pointer of chars

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

struct data {
    char *path;
};

void listFiles(void *p)
{
    struct data *d = (struct data *)p;

    struct dirent *dp;
    DIR *dir = opendir(d->path);

    // Unable to open directory stream
    if (!dir)
        return;

    while ((dp = readdir(dir)) != NULL)
    {
        if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
        {
            struct data *nd= malloc(sizeof(struct data));
            char *c = malloc(sizeof(char *));

            // Construct new path from our base path
            strcpy(c, d->path);
            strcat(c, "/");
            strcat(c, dp->d_name);
            strcpy(nd->path,c);
            printf("%s\n", nd->path);

            listFiles(nd);
        }
    }

    closedir(dir);
}

int main(int argc, char* argv[])
{
    struct data *d= malloc(sizeof(struct data));
    char *c = malloc(sizeof(char *));
    strcpy(c,argv[1]);
    d->path = c;

    printf("%s\n", d->path);

    listFiles(d);   //need to send a struct

    return 0;
}

I am new with handling pointer of chars. I want to print the list of directories and files. If I use a char path[1000], it works but I would like to use char *path. I keep getting "Segmentation fault (core dumped)". Any suggestion?

Upvotes: 0

Views: 140

Answers (4)

John Bode
John Bode

Reputation: 123468

A char * is just an address - it doesn’t store the actual string data. Remember that a string in C is just a sequence of characters including a zero-valued terminator. Strings are stored in arrays of character type (char for ASCII, EBCDIC, UTF-8, wchar_t for ”wide" encodings), and the array must be at least one element wider than the string length in order to account for the string terminator.

Now, under most circumstances, when we’re dealing with array expressions the type of the expression "decays" from type "array of T" to "pointer to T" and the value of the expression is the address of the first element, so most of the time we’re dealing with expressions of type char * when working with strings, but a char * is not a string.

To store the path name you need to allocate an array of char like so:

char *c = malloc( sizeof *c * (N + 1) );

where N is the max number of characters you need to store. You need to set aside N+1 elements to account for the terminator. The type of the expression *c is char, so the expression sizeof *c yields the same value as sizeof (char)1.


  1. sizeof is an operator, not a function, so parentheses are only necessary if the operand is a type name.

Upvotes: 1

Florent
Florent

Reputation: 446

1- You must understand that a string in C is null termnated sequence of caracters. If those caracters are all in an allocated memory, it is ok. The allocated space must be bigger than the string lenght + 1 (the null ending caracter). If the string is bigger than allocated space a "Segmentation fault" appear.

2- pointer (ie address of an object) and pointed object are not the same and have not the same size.

sizeof(char *) gives the size of the pointer on a char. the size of a variable to store adresse not the size of a string.

sizeof(char) gives 1 (byte)

strlen(myString) return the size of the string ie the number of caracters before the ending Zero regardless the allocated memory.

char toto[1000]; sizeof toto; // ---> gives 1000 the allocated space by array of char. strlen(toto) // depend on the data in memory starting at toto (address of the first caracter ie pointer)

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


int main(int argc, char* argv[])
{

    char t[]="ABCDEFGH";  // initalisation only 
    // t="12345678";   //illegal
    // t[]="12345678"; //illegal    
    
    //
    printf("\nstring in t: %s", t);
    printf("\nsizeof in t: %d", sizeof t);   // size of the array 
    
    printf("\nstrlen in t: %d", strlen(t));  // size of the string 
    //in strlen t is used as pointer char *

    char * p;
    p = malloc(sizeof (char) * 50);// sizeof is not a function but an operator
    strcpy(p, t);   
    p++; // go to the next element of type char in memory.
    printf("\nstring in p %s", p);  
    printf("\nsizeof in p: %d", sizeof p);  
    printf("\nstrlen in p: %d", strlen(p)); 
    return 0;
}

Output is:

string in t: ABCDEFGH
sizeof in t: 9
strlen in t: 8
string in p ABCDEFGH
string in p BCDEFGH
sizeof in p: 4
strlen in p: 7

Upvotes: 0

Jonathan Leffler
Jonathan Leffler

Reputation: 753785

Given that you subsequently use:

// Construct new path from our base path
strcpy(c, d->path);
strcat(c, "/");
strcat(c, dp->d_name);

You need to allocate enough space for that much data, which means:

char *c = malloc(strlen(d->path) + strlen(dp->d_name) + sizeof("/"));

The sizeof("/") evaluates to 2; the null byte is part of the size of the array containing the string.

You allocate 4 or 8 bytes via sizeof(char *) (depending on whether you are working with a 32-bit or 64-bit memory model); this is usually not enough.

You should also check that both allocations work before using the space allocated, taking appropriate action if one fails.

There is also have a major memory leak in the if statement within the loop. The code allocates space but doesn't free it before the variables holding the pointers go out of scope — thus leaking the memory.

We can also debate the wisdom of allocating a structure that simply contains a pointer. You have to make two allocations where one would suffice if you simply used a char * variable. If you kept a length in the structure too (so that one of the strlen() calls could be replaced by accessing the known length, then the structure would be justifiable.

Some systems provide a 'length' member in the struct dirent type. POSIX does not mandate this: it only mandates d_ino and d_name. On macOS (Darwin, BSD), the length member is d_namlen. On Linux, it appears to be d_reclen. It's not guaranteed to exist — and that's probably because different existing implementations have different names for the member.

Upvotes: 0

Icemanind
Icemanind

Reputation: 48686

A char * is only 4 bytes, therefore, sizeof(char *) will only return 4, which is not enough to hold a full path name. Instead, try using a line like this:

char *c = malloc(sizeof(char) * 256);

This will allocate 256 bytes of however big a char is (usually 1).

Upvotes: 1

Related Questions