Pointer modified when passing it as an argument?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Candamir

Pointer modified when passing it as an argument?

Post by Candamir »

I have a pointer: struct regs *r and pass this pointer as an argument to a function. In this function, the value of r is modified, but when the function returns, the original value of r is still the same. Is this a property of the compiler or a bug in my code?

Candamir
Kemp

Re:Pointer modified when passing it as an argument?

Post by Kemp »

Any changes to arguments are done on a copy of that variable that is made on the stack (optimisations nonewithstanding). Changes done to the thing pointed to are done on the actual thing pointed to as the value of the pointer is not changed.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Pointer modified when passing it as an argument?

Post by Pype.Clicker »

in other words, what you pass to a function through an argument in C is _always a value_. even when you have pointers around, you always give the _value_ of the pointer, never the variable itself.

e.g. you have

Code: Select all

void print_one_char(char* str) {
    putc(*str); // print first char
    str++;  // advance pointer to next char
}
and you do

Code: Select all

    char* msg="hello world";
    print_one_char(msg); print_one_char(msg); print_one_char(msg);

    print_one_char(msg+6); print_one_char("world");
all are correct invocation, and the resulting text will be "hhhww". note the construct "(msg+6)" and "("world")" where the value is compiled right before you call the function. How could print_one_char know it now no longer operate from a variable but rather on a computed expression ?

the answer is it doesn't need to care. print_one_char operates on its argument which is placed in a memory location that isn't used for anything else.

If that still seems weird to you, just grab the K&R and a book explaining the stack in assembly, then get a look at how a simple example is compiled into assembly by GCC...
Candamir

Re:Pointer modified when passing it as an argument?

Post by Candamir »

Hmm, it seems pretty the same as Java: Primitives in method arguments are modified without changing the original and objects are modified...

(Well, it's more like the other way round: Java is like C ;))

Thanks,

Candamir
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Pointer modified when passing it as an argument?

Post by Pype.Clicker »

"passing arguments by value" and "passing arguments by variable" are there since the first high-level languages, afaik.
distantvoices
Member
Member
Posts: 1600
Joined: Wed Oct 18, 2006 11:59 am
Location: Vienna/Austria
Contact:

Re:Pointer modified when passing it as an argument?

Post by distantvoices »

That's "passing arguments by reference", ain't it?
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
Habbit

Re:Pointer modified when passing it as an argument?

Post by Habbit »

Well, if you need to modify the pointer itself (i.e. make it point to another variable) instead of the pointee (the struct), you need to pass a double pointer:

Code: Select all

void alterPointer(char** ptr)
{
    *ptr = "Another one";
}

int main(void)
{
    char* myString = "A string";
    cout << myString << endl;  // Prints 'A string'
    alterPointer(&myString);   // Notice the double indirection: &(char*) = char**
    cout << myString << endl;  // Prints 'Another one'
    return 0;
}
This could be used to implement, for example, PHP-like iteration functions (na?vely and w/o bound checks in this snippet):

Code: Select all

int next(int** ptrToIntArray)
{
    *ptrToIntArray++; // Move the array pointer to the next int
    return **ptrToIntArray; // Return the now-current element
}

void otherFunc(void)
{
    int* arr = new int[5]
    // Fill the array
    int item = next(&arr); // 1st item
    item = next(&arr); // 2ns item
    return;
}
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:Pointer modified when passing it as an argument?

Post by Candy »

If you use a c++ compiler you can also pass a reference to the pointer:

Code: Select all

void modify(char *&x) {
   x = "hello world";
}

int main(...) {
   char *t = NULL;
   modify(t);
   printf("%s", t);
}
proxy

Re:Pointer modified when passing it as an argument?

Post by proxy »

Code: Select all

int next(int** ptrToIntArray)
{
    *ptrToIntArray++; // Move the array pointer to the next int
    return **ptrToIntArray; // Return the now-current element
}

this example is BROKEN, *p++ does not increment what p points to. ++ has a higher precidence than (yes both versions do) just postfix ++ returns the original value, not the new one.

thus p++ is functionally the same as "int t = p; ++p; return t;", just any current compiler will know to optimize this by reorderoing such that the temp is unneccessary in most cases.

what you want is:

Code: Select all

int next(int** ptrToIntArray)
{
    (*ptrToIntArray)++; // Move the array pointer to the next int
    return **ptrToIntArray; // Return the now-current element
}
or better yet:

Code: Select all

int next(int** ptrToIntArray)
{
    ++(*ptrToIntArray); // Move the array pointer to the next int
    return **ptrToIntArray; // Return the now-current element
}
Finally of course this is avoided entirely by using c++ and references!

Code: Select all

int next(int* &ptrToIntArray)
{
    ++ptrToIntArray; // Move the array pointer to the next int
    return *ptrToIntArray; // Return the now-current element
}
which can be improved to make it even shorter..

Code: Select all

int next(int*&ptrToIntArray)
{

    return *++ptrToIntArray; // Move the array pointer to the next int and Return the now-current element
}
proxy
Candamir

Re:Pointer modified when passing it as an argument?

Post by Candamir »

Well, thanks for your extensive answers. This was indeed one of the problems in my scheduler. However, I think I also have the same problem with my ASM code, but due to the nature of the stack in ASM I think maybe there the situation might be different...

This is my code:

Code: Select all

irq_common_stub:
    pushad
    push ds
    push es
    push fs
    push gs

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov eax, esp

    push eax
    mov eax, irq_handler
    call eax
    pop eax

    pop gs
    pop fs
    pop es
    pop ds
    popad
    add esp, 8
    iret

Code: Select all

void irq_handler(struct regs *r)
{
   r = (struct regs *)something;
   ...
I already tried it out, but didn't quite understand the codes behaviour... IIUC, pop eax should then restore esp to 'something', shouldn't it?

Candamir

PS: Maybe I'm wrong in the first place and all that misses is a mov esp, eax after pop eax...
Habbit

Re:Pointer modified when passing it as an argument?

Post by Habbit »

proxy wrote:
this example is BROKEN, *p++ does not increment what p points to. ++ has a higher precidence than (yes both versions do) just postfix ++ returns the original value, not the new one.
you are indeed right, as the msdn doc states, but then my c++ compiler is quite broken (m$vc++ 5), since it allows that kind of construct with the behaviour i described... maybe i should update to vs.net 2005 and vc++ 8.0 (or even get g++ ^_^)
Midas
Member
Member
Posts: 140
Joined: Sat Jun 24, 2006 4:40 pm
Location: Falkirk, Scotland
Contact:

Re:Pointer modified when passing it as an argument?

Post by Midas »

Habbit wrote:you are indeed right, as the msdn doc states, but then my c++ compiler is quite broken (m$vc++ 5), since it allows that kind of construct with the behaviour i described... maybe i should update to vs.net 2005 and vc++ 8.0 (or even get g++ ^_^)
Quite apart from anything else, MSVC++ 5 might compile something but it isn't C++. C++ wasn't standardised until after MSVC++6, IIRC. (Although I'm open to correction if I'm as wildly wrong as I may be).
Regards,
Angus [Óengus] 'Midas' Lepper
Kemp

Re:Pointer modified when passing it as an argument?

Post by Kemp »

AFAIK none of the current compilers can be said to compile standard C++ code, as there's lots of things in there that are hard to build into the compiler or that simply aren't used enough to be a priority.

Blatently going against standard operator precedence like that is definately something that needs fixing though.
Post Reply