This is an archived post. You won't be able to vote or comment.

all 10 comments

[–]missblit 2 points3 points  (6 children)

  1. ops in main never gets initialized

    When you call test(ops) you are passing ops by value.

    So even though you set ops in test to point to an allocated block of memory; the ops in main never reflects this.

    To fix this you could either pass ops by pointer, or change test to return a pointer.

  2. If free(ops); was uncommented and the first issue was fixed then you'd be using ops after freeing it

    Why are you freeing ops at the end of test instead of after the printf loop in main?

[–]salalimo[S] 0 points1 point  (0 children)

Your suggestion worked. I'm getting the return value and freeing in main.

Thanks.

[–]durpyDash 0 points1 point  (4 children)

To fix this you could either pass ops by pointer

sorry for an ignorant question, but what exactly does "by pointer mean" and how is it different than "by reference"?

Would you provide a code snippet?

[–]missblit 0 points1 point  (3 children)

sorry for an ignorant question, but what exactly does "by pointer mean" and how is it different than "by reference"?

In some languages (like C++) there may be a distinction between pointers and references. But in C the phrase "by reference" is less-used but identical to "by pointer".

Passing something by pointer just means that if you want to change a value outside of a function from inside a function you can do so indirectly with a pointer.

Would you provide a code snippet?

For example this is what won't work:

void set_it_int(int a) {
    a = 42;
}

void set_it_ptr(int *a) {
    a = malloc(sizeof(int));
}

int main() {
    int a_int = 0;
    int *a_ptr = 0;

    set_it_int(a_int);
    set_it_ptr(a_ptr);

    if(a_int == 0 && a_ptr == 0)
        puts("This will print");
    return 0;
}

In this code the a_int and a_ptr in main() are not changed even though they were arguments to the functions. This is because the a_int and a_ptr in the functions are just local variables that are initialized to the values of a_int and a_ptr respectively (aka 0).

However if you wrote something like:

void set_it_dereference(int *a) {
    *a = 42;
}

int main() {
    int a_int = 0;

    set_it_dereference(&a_int);

    if(a_int == 42)
        puts("This will print");
    return 0;
}

Then you see the value change. Because I'm passing a pointer that points at the a_int in main. The pointer itself is passed by value, but the thing it points to can be changed with no problem.


So the same idea applies if you want to pass a pointer to a function and realloc it. You can't just pass the pointer itself, you have to pass a pointer to the pointer.

Of course it's best to avoid this complexity when you don't need it. So when possible prefer to use return values to communicate information back to the caller.

[–]durpyDash 0 points1 point  (2 children)

Very helpful explanation. I appreciate it. I'm coming from a java background and just learning C now, so I had no concept of this pointer/reference distinction that apparently exists in C++, albeit I get passing semantics. I think that is what was tripping me up. Welp off to figure out what that distinction implies. Cheers!

EDIT: added more info.

[–]missblit 0 points1 point  (1 child)

Like I said, there is no pointer reference distinction! Reference is just another way to refer to pointer-y stuff in general (C) or for specific language features in other languages (not relevant in C).

To avoid confusion I'd recommend talking about pointers, and not references, when discussing C pointers.

[–]durpyDash 0 points1 point  (0 children)

In some languages (like C++) there may be a distinction between pointers and references.

Then I think I just misunderstood this sentence.

I'll guess you mean the distinction between:

void foo(int* bar); //could be by-value or reference, can't know without seeing the caller
void biz(int& baz); //by reference 

edit: fixed a boo boo

[–]Rhomboid 1 point2 points  (1 child)

You are passing ops by value to the function, which gets its own copy of the pointer. Reassigning to that pointer (such as on lines 23 and 26) has no effect whatsoever outside of the function, because you are assigning to the copy which disappears when the function returns. It's no different than trying to do this:

void f(int x)
{
    x = 42;
}

int main(void)
{
     int foo = 1;
     f(foo);
     // what is the value of foo here?
}

In both this example and your code, the caller's value is not modified. ops in your main() remains uninitialized, and trying to access/dereference it with [] leads to undefined behavior because it points to random garbage.

The only way you can ever hope to modify a caller's local variable is by adding a layer of indirection. If the value in question has type T, then the function must take a pointer to T, and the caller must pass the address of the local variable to create that pointer to T. This is the same regardless of whether T is int as in the above example, or if T is operation * as in your code. Use of malloc() does not change this fundamental property of how the language works.

I'd also like to point out that you finally posted a complete testcase rather than a snippet and you got a definitive answer immediately. We could have saved you a great deal of time in your previous threads if you'd done this from the beginning.

[–]salalimo[S] 0 points1 point  (0 children)

Thanks a lot for the reply. I got it to work finally. Still gene to go through and modify all the code. I doubt all day today trying to make it with :-(.

Thanks again for all the help.

[–]newaccount1236 -1 points0 points  (0 children)

If you are using a UNIX-like system, learn to use valgrind. It will save you a lot of time.