1

I'm trying to create dynamic array of structs (pics in this case) using realloc. I want to do it in function, but there's a problem: variables in main are not changed by this function. There must be problem with pointers but I cannot find it. PS: Function UploadFile works properly. There's a function:

int AddPicture(struct Picture ***tab, int *PicCounter)
{
    struct Picture *temp;
    struct Picture pic;
    (*PicCounter)++;
    temp = realloc(*tab, (*PicCounter) *sizeof(*temp));
    if (temp != NULL)
    {
        UploadFile(&pic);
        **tab = temp;
        (*tab)[*PicCounter-1]->name = pic.name;
        (*tab)[*PicCounter-1]->type[0] = pic.type[0];
        (*tab)[*PicCounter-1]->type[1] = pic.type[1];
        (*tab)[*PicCounter-1]->width = pic.width;
        (*tab)[*PicCounter-1]->height = pic.height;
        (*tab)[*PicCounter-1]->scale = pic.scale;
        (*tab)[*PicCounter-1]->table = pic.table;
    }
    else {
        printf("Memory reallocation error");
        free(temp);
        return 1;
    }
return 0;
}

There's how I call it in main:

struct Picture *tabofpics;
int piccounter = 0;
tabofpics = malloc(1 * sizeof(*tabofpics));
AddPicture(&tabofpics,&piccounter);

Thanks for help.

EDIT: I've tried **tab instead of ***tab and values in main are correct, but it acts like memory doesn't reallocate properly, even if realloc doesn't return NULL.

  int AddPicture(struct Picture **tab, int *PicCounter)
{
    struct Picture *temp;
    struct Picture pic;
    (*PicCounter)++;
    temp = realloc(*tab, (*PicCounter) * sizeof(*temp));
    if (temp != NULL)
    {
    UploadFile(&pic);
    *tab = temp;    
    tab[*PicCounter - 1]->name = pic.name;
    tab[*PicCounter - 1]->type[0] = pic.type[0];
    tab[*PicCounter - 1]->type[1] = pic.type[1];
    tab[*PicCounter - 1]->width = pic.width;
    tab[*PicCounter - 1]->height = pic.height;
    tab[*PicCounter - 1]->scale = pic.scale;
    tab[*PicCounter - 1]->table = pic.table;
}
else {
    printf("Memory reallocation error");
    free(*tab);
    return 1;
}
return 0;
}                                                                                                                             

The idea is to put as many pics in the program as one want to, do some operations on its and leave. There must be function to add and delete pics whenever user want to, however when I call function with **tab in argument second time I get Access violation location, so as I mentioned earlier, realloc must not work properly.

15
  • 2
    Why is tab a triple pointer? It seems like a double pointer should be sufficient. Especially since you're allocating memory based on the size of a Picture, not a Picture *. Commented Dec 23, 2018 at 14:05
  • 2
    I think compiler warning should give answers. And it seems that you don't know how many pictures you want to add, in this case, maybe linked list would be better? every node would be info about your picture Commented Dec 23, 2018 at 14:05
  • 1
    struct Picture ***tab --> struct Picture **tab Commented Dec 23, 2018 at 14:06
  • 1
    @IgorZ Don't just try things as solutions. Think of one, try to understand the underlying concepts first. Check my answer. Commented Dec 23, 2018 at 14:29
  • 1
    @IharobAlAsimi, it is a worthy consideration to look at while profiling, but really it isn't exponential, it is max twice what you are using... so if you are working on a 1gb dataset you might have a 1gb buffer unused, but that is generally ok in modern VM environments, far better than copying a .9gb buffer 10 times Commented Dec 23, 2018 at 15:05

3 Answers 3

2

The central problem can perhaps be best summarized by these two excerpts from your code:

    temp = realloc(*tab, (*PicCounter) *sizeof(*temp));

[...]

        **tab = temp;

You are reallocating the space pointed to by the value of *tab, but on success, you're storing the pointer to the new space in **tab, which is a different location. Regardless of which of those is the right location for the pointer, the combination is certainly wrong.

In fact, however, given the way you are calling your function ...

struct Picture *tabofpics;

[...]

AddPicture(&tabofpics,&piccounter);

... the type of the actual argument is struct Picture **. And that's appropriate for your purpose, so you should adjust the function definition to match:

int AddPicture(struct Picture **tab, int *PicCounter)

. Moreover, you should ensure that a matching function declaration is present in a header file that is #included into the source file containing the definition of AddPicture and into every source file containing a call to that function. That, plus ensuring that compiler warnings are turned up, should empower the compiler to help you diagnose mismatches between the definition and the uses of this function.

Having done that, the expression *tab in function AddPicture() will refer to the same object that the expression tabofpics (no *) refers to in main(). That appears to be consistent with how you're actually using it, with the exception of the mismatch I described at the beginning.

There are other reasonable criticisms of your code that could be made, but @Iharob has already done a good job of addressing those in his answer.

Sign up to request clarification or add additional context in comments.

Comments

1

As I see it, you need to improve the logic of your code, for instance

  1. Don't increment PicCounter yet
  2. You have a mismatch in your pointers indirection level, in the caller function you have struct Picture * and you are passing it as struct Picture ** to a function taking struct Picture ***. You should reason about it and what is it that you really want. It seems that you want an array of struct Picture *.

Style,

  1. Don't use PicCounter for a variable, use number_of_pictures or something more appropriate.
  2. Don't write 1 * sizeof(...) it's too explicit and you don't need to be as much.

Tooling,

  1. Enable compiler warnings to spot simple mistakes that you make without noticing, or those that are a conceptual flaw like the mismatched indirection of pointers in your code.

That said, I think you probably wanted to write this

int
AddPicture(struct Picture ***tab, int *counter)
{
    struct Picture **array;   
    array = realloc(*tab, (*counter + 1) * sizeof(*array));
    if (array != NULL)
    {
        struct Picture *current;
        // We will avoid using the `tab' variable because it's
        // confusing, the only reason why it's a *** pointer is
        // to do this here, and below where we set it to `NULL'
        *tab = array;
        // We also need to allocate space for a new image to store
        // the results in.
        current = malloc(sizeof(*current));
        if (current == NULL)
            goto error;    
        // This is a guess, but isn't the code just initializing
        // the `pic' that you allocated on the stack?
        //
        // Well, the following is the same.
        //
        // Oh, and should we check for errors here?
        UploadFile(current);            
        // Now we can increase counterand update our array
        array[(*counter)++] = current;
        // We have succeded, so return 0
        return 0;
    }
error:
    printf("Memory reallocation error");
    // Release memory allocated so far
    free(*tab);
    // Prevent dangling pointer
    *counter = 0;
    *tab = NULL;
    // A non zero value means, an error
    return 1;
}

And the caller function should be something like

struct Picture **tabofpics;
int counter = 0;
// `realloc' will take car of the allocation
tabofpics = NULL;
if (AddPicture(&tabofpics, &picounter) == 0)
    // Everything ok, picture added
else
    // Error

Please be careful with *** pointers, they can cause a lot of confusion. I have to think 4 or 5 times about

(*tab)[*counter] = current;

before I can see that it's correct. So I chose to change it as you can see in the code.

Your code should be as descriptive as possible, and using *** pointers goes in the wrong direction of that.

4 Comments

Are you a three star programmer?
@P__J__ No I am not, please check my comments in the question. But blindly saying that three stars are wrong, is just wrong. Everything has their use. Three stars in this case is not bad provided that you're careful. Please read the code before giving your opinion immediately when you see that I retained the 3 stars. I think that was intended here, the OP just didn't use it right.
@P__J__ I will re-check, it could be. That's why they're so frowned upon of course. Thanks for your feedback.
@P__J__ I found a couple of issues. Please check again and if it's still bad don't hesitate to tell me. The health of answers at this site is really important to me. Thanks. I don't know if you're familiar, but for some tags there are really bad answers, unlike the c tag which has great answers in general.
-1

According to answers of @Iharob and @John I was able to write a working function:

 int AddPicture(struct Picture **tab, int *PicCounter)
{
struct Picture *temp;
(*PicCounter)++;
temp = realloc(*tab, (*PicCounter) * sizeof(*temp));
if (temp != NULL)
{
    struct Picture *pic;
    pic = malloc(sizeof(*pic));
    UploadFile(pic);
    *tab = temp;
    (*tab)[(*PicCounter)-1] = *pic;
    free(pic);
}
else {
    printf("Memory reallocation error");
    free(*tab);
    (*PicCounter)--;
    return 1;
}
return 0;
}

It's not perfect, but it works properly. Thanks for help!

1 Comment

Please do not answer your own question if based on other answers. Accept the one you consider most helpful instead. Only answer your own question if it's substantially different from the ones already provided. Also your code is faulty. If you call free(*tab) then *PicCounter = 0 is a must, because now you don't have access to the contents of tab anymore. And the level of indirection in your code is still wrong. If it "works" it's just an accident, so please use a memory debugger or similar tool and check that your code is wrong.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.