2

I keep passing in and returning the dirs_later_array. When I get to "new_size=..." in the else block, I end up with new_size of 2 the second time around. So far so good. But when I do a realloc

dirs_later_array = realloc(dirs_later_array,
new_size * sizeof(struct dirs_later*));

the sizeof remains at 4, the size of the pointer, for dirs_later_array. I'm able to succesfully store at dirs_later_array[1] but that value keeps getting overwritten the next time I go into the function.

struct dirs_later** add_struct(const char *findme, struct dirent *dptr,
        struct stat *this_lstat, char *relative_path, const char *type_str,
        struct dirs_later **dirs_later_array) {

    struct dirs_later *new_dir = malloc(sizeof(struct dirs_later));
    check_realloc_dirs_error(new_dir);

    if (strcmp(dptr->d_name, ".")) { //Dir and not same directory
        //Copy the relative path to the struct
        char *relative_path2;
        relative_path2 = malloc(strlen(relative_path) + 1);
        check_realloc_error(relative_path2);
        strcpy(relative_path2, relative_path);

        //if (strlen(relative_path) > 0)
        //    relative_path2[strlen(relative_path) - 1] = '\0';

        if (NULL != new_dir) {
            new_dir->findme = findme;
            new_dir->dptr = dptr;
            new_dir->st_mode = this_lstat->st_mode;
            new_dir->relative_path = relative_path2;
            new_dir->type_str = type_str;
        }
        int new_size = 0;
        /*
         //Check if this is the first element in the struct
         if (sizeof(dirs_later_array) / sizeof(struct dirs_later*) == 1) {
         new_size = 1;
         }
         */
        if (dirs_later_array == NULL) {
            dirs_later_array = malloc(sizeof(struct dirs_later*)); //Store the directory structures or process later
            check_realloc_arr_error(*dirs_later_array);
            new_size = 1;
        } else {

            //Add directories to directories array
            new_size = (((sizeof(dirs_later_array) + sizeof(struct dirs_later*)))/sizeof(struct dirs_later*));
            //printf("new size: %d",new_size);
        }
        dirs_later_array = realloc(dirs_later_array,
                new_size * sizeof(struct dirs_later*));
        check_realloc_arr_error(dirs_later_array);
        dirs_later_array[new_size - 1] = new_dir;
    }
    return dirs_later_array;
}



user994165
  • 9,146
  • 30
  • 98
  • 165
  • 1
    `realloc`does not resize anything it justs allocates dynamic memory specified as an parameter and assigns it to your pointer. – Alok Save Feb 28 '12 at 07:37
  • 1
    @Als But it does! It does resize! – Mr Lister Feb 28 '12 at 07:41
  • @Als - Any also ensures that the original contents remain unchanged (in as far as to the new amount of space) – Ed Heal Feb 28 '12 at 07:43
  • It is a fundamental C and C++ rule that something's size does not depend on the values it contains. Were this not the case, how would know what size to pass to `malloc`? You'd need the value to know the size, but if you had some place to put the value, you probably wouldn't need to call `malloc`. – David Schwartz Mar 28 '16 at 17:45
  • BTW, `p = realloc(p, new_size)` is a well-known ___anti-pattern__ that leaks the memory when an error occurs and `realloc()` returns a null pointer. Don't do that! – Toby Speight Mar 11 '23 at 14:59

2 Answers2

14

Operator sizeof is a compile time feature and it only checks the static size of an expression. So for pointer it only returns the size of that pointer which is 4 on your platform. sizeof does not measure the size of a dynamically allocated data. There is no standard feature in C to get the size of dynamically allocated data.

Juraj Blaho
  • 13,301
  • 7
  • 50
  • 96
5

Your sizeof(struct dirs_later*) should be changed to sizeof(struct dirs_later) - as before!

Also the sizeof is a compile time feature. You need a structure like this to hold the size

struct my_dirs
   struct dirs_later *dirs;
   int size;
};

Initialise it like this

struct my_dirs directories;
directories.size = 0;
directories.dirs = NULL;

Then to add (note realloc can take NULL as a parameter

directories.dirs = realloc(directories.dirs,
                           (++directories.size) * sizeof(struct dirs_later));

This would also simplify your code.

Ed Heal
  • 59,252
  • 17
  • 87
  • 127
  • Actually, whether realloc can take a NULL as a parameter is an implementation dependent issue. I do remember that some compilers on some machines that I have dealt with over the years would allow that. It was not something that you could guarantee to work on every machine though, so it was considered poor style to use that "feature". https://en.cppreference.com/w/c/memory/realloc – Grumpy OldMan May 26 '20 at 08:21
  • @GrumpyOldMan Standard C [requires in section 7.22.3.5.3](https://www.open-std.org/JTC1/SC22/WG14/www/docs/n1570.pdf#%5B%7B%22num%22%3A116%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C-27%2C816%2Cnull%5D) that __If `ptr` is a null pointer, the `realloc` function behaves like the `malloc` function for the specified size__. Not implementation-defined. Perhaps you're thinking of the behaviour when a zero size is passed, which was implementation-defined prior to C23? It's now undefined. – Toby Speight Mar 11 '23 at 14:56
  • Toby... The document that you referenced is fairly recent (2011)... Well, for some of us old farts, that is considered very recent... :) One of the things that I've learned during my career is that you should not assume that you will always be working on the latest versions of compilers. Sometimes, you work on legacy machines because there is some package that the company has running on it that is not available on a more recent machine. It takes very little effort to add code to ensure that a NULL pointer is not used vs you will spend a lot of time finding the problem later after a problem. – Grumpy OldMan Mar 13 '23 at 14:42