PDA

View Full Version : Passing by reference in C... Help!




Littleodie914
Sep 19, 2008, 04:06 PM
Hey guys, I'm in the process of learning C (again, kind of) and I'm confused as to why the following method prints "Howdy" to the console rather than "Woah."

void pointer(int * a) {
a = "Woah\n";
}

main() {
char *string = "Howdy\n";

pointer(string);

printf("%s", string);
}

Also, I receive the following warnings. What am I doing wrong? :confused:

Craigs-iMac:Homework 1 Craig$ gcc test.c
test.c: In function ‘pointer’:
test.c:4: warning: assignment from incompatible pointer type
test.c: In function ‘main’:
test.c:10: warning: passing argument 1 of ‘pointer’ from incompatible pointer type
Craigs-iMac:Homework 1 Craig$



robbieduncan
Sep 19, 2008, 04:08 PM
At the very least pointer should be declared as


void pointer (char* a)

Littleodie914
Sep 19, 2008, 04:12 PM
At the very least pointer should be declared as


void pointer (char* a)
Wow yea I couldn't believe I missed that. :o Realized that a couple seconds after I posted. Changed back to a character pointer, and it's good to go. (The warnings are gone, anyway.)

Any ideas on the actual behavior?

robbieduncan
Sep 19, 2008, 04:17 PM
Well you are passing a pointer to the function. You then set the pointer to point at a new memory location (the start of the string), rather than dereferencing the pointer to update the contents of the memory it points at. That'll be your problem.

It's ages since I did pure C (I left Uni 8 years ago :eek:)

But iirc you want

*c = "Woah\n";


I would note this is exceptionally unsafe: you have no idea in the pointer function if there is enough memory allocated or not. If you change the length of the initial string this could crash hard.

Littleodie914
Sep 19, 2008, 04:21 PM
Well you are passing a pointer to the function. You then set the pointer to point at a new memory location (the start of the string), rather than dereferencing the pointer to update the contents of the memory it points at. That'll be your problem.

It's ages since I did pure C (I left Uni 8 years ago :eek:)

But iirc you want

*c = "Woah\n";


I would note this is exceptionally unsafe: you have no idea in the pointer function if there is enough memory allocated or not. If you change the length of the initial string this could crash hard.Yea, that causes a bus error. Strange, shouldn't there be enough space, since the memory the pointer points to is at least big enough to hold 6 characters? (Counting the newline as 1.)

And secondly, even if you are changing the memory address that the pointer points to, shouldn't the printf be grabbing its value from that new memory location? Aren't they the same pointer still?

jsw
Sep 19, 2008, 04:22 PM
It's been even longer since I've done C/C++ (10 years, give or take), but I'm thinking you'd want to pass in a handle (pointer to a pointer), then change it.

Something like:

void pointer(char** a) {
*a = "Woah\n";
}

main() {
char *string = "Howdy\n";

pointer(&string);

printf("%s", string);
}
Of course, it's been a decade, so the specifics escape me. :o

lee1210
Sep 19, 2008, 04:25 PM
This seems like a pretty dangerous game to be playing, but i'll try to explain the behavior.

You are passing the pointer to "Howdy\n" to pointer by value. So while you would be able to modify the contents in pointer (though you shouldn't as "Howdy\n" is a string literal, and you changing that memory would be a bad idea), you can't change the pointer itself. Or rather, you could, but it wouldn't do you much good. This is the same as:


void myIntTest(int x) {
x++;
}


In the calling function, the value of x will not be changed, because you passed x by value. Well, you passed string by value, and it's value is the address to a character. So to do what you want to do, you need to pass the address of string instead, then dereference it in pointer (whose signature will change to char **a), then assign the pointer to the literal "Woah\n". Then back in main, since you changed the value of the pointer, string will be pointing to the string literal "Woah\n".

Having int * in the pointer signature was not the best, but since the size of the pointers would be the same, it wasn't hurting anything too badly. As you saw, it still didn't print properly because of the reasons stated above.

To reiterate, as it seems like the next thing you might try while playing with this sort of thing, do not change the memory you get a pointer to using string literals, bad things will happen.

-Lee

Bah, jsw beat me to it, with the exact code that i came up with.

Littleodie914
Sep 19, 2008, 04:25 PM
It's been even longer since I've done C/C++ (10 years, give or take), but I'm thinking you'd want to pass in a handle (pointer to a pointer), then change it.

Something like:

void pointer(char** a) {
*a = "Woah\n";
}

main() {
char *string = "Howdy\n";

pointer(&string);

printf("%s", string);
}
Of course, it's been a decade, so the specifics escape me. :oThat was it. :) For a class I'm taking we're working with this specific situation, and I was just trying to get a better handle on how to pass references.

For anyone curious, here's the final code that worked:

#include <stdio.h>

void pointer(char ** a) {
*a = "Woah\n";
}

main() {
char *string = "Howdy\n";

pointer(&string);

printf("%s", string);
}

robbieduncan
Sep 19, 2008, 04:25 PM
Yea, that causes a bus error. Strange, shouldn't there be enough space, since the memory the pointer points to is at least big enough to hold 6 characters? (Counting the newline as 1.)
You mean changing it to *c causes that. I've probably told you to do the wrong thing then. There should be enough space. Told you it's been a while.

And secondly, even if you are changing the memory address that the pointer points to, shouldn't the printf be grabbing its value from that new memory location? Aren't they the same pointer still?

No. If you pass the address of the pointer into the function then you can change the target of the pointer and have that respected outside the call. Basically you are passing an int (the pointer) on the stack. This is basically a local variable in the function. Changing the value of a local variable has no effect outside the call.

lee1210
Sep 19, 2008, 04:29 PM
Basically you are passing an int (the pointer) on the stack.

Don't tell him that! It's not just theoretical that sizeof(int) != sizeof(void *) anymore. What you were saying was accurate otherwise, but we don't need people thinking pointers are the same size as ints. On most new systems they aren't.

-Lee

robbieduncan
Sep 19, 2008, 04:31 PM
Don't tell him that! It's not just theoretical that sizeof(int) != sizeof(void *) anymore. What you were saying was accurate otherwise, but we don't need people thinking pointers are the same size as ints. On most new systems they aren't.

-Lee

I was trying to simplify it! I agree an int is not necessarily the size of a pointer. Back when I learnt C you could almost guarantee it was though :o

lee1210
Sep 19, 2008, 04:33 PM
I was trying to simplify it! I agree an int is not necessarily the size of a pointer. Back when I learnt C you could almost guarantee it was though :o

Just giving you a hard time. I'm just bitter because our C compiler defaults return types to int, as many do. Because of this people wrote a lot of code that i'm going to have to fix to make it run on 64-bit OSs, because they decided "Why do we need prototypes for these functions that return char *? They work fine without it, and that's such a burden!".

-Lee

robbieduncan
Sep 19, 2008, 04:34 PM
Just giving you a hard time. I'm just bitter because our C compiler defaults return types to int, as many do. Because of this people wrote a lot of code that i'm going to have to fix to make it run on 64-bit OSs, because they decided "Why do we need prototypes for these functions that return char *? They work fine without it, and that's such a burden!".

-Lee

Lol, old code sucks!

gnasher729
Sep 19, 2008, 05:00 PM
Just giving you a hard time. I'm just bitter because our C compiler defaults return types to int, as many do. Because of this people wrote a lot of code that i'm going to have to fix to make it run on 64-bit OSs, because they decided "Why do we need prototypes for these functions that return char *? They work fine without it, and that's such a burden!".

A bit of history: In the old 68000 days, Metrowerks changed their famous C compiler to return ints in data registers, and pointers in address registers (which would create slightly faster code). Exactly the kind of code that you mention would stop working: The function returning the char* would return it in an address register, the caller who was too lazy to write a function prototype would expect it in a data register, and would interpret whatever garbage happened to be in the data register as the result pointer.

Result 1: Tons of applications crashed. Result 2: Tons of people who didn't deserve to be called programmers complained to Metrowerks. Result 3: Metrowerks changed their compiler back to the slower method.

gnasher729
Sep 19, 2008, 05:02 PM
I was trying to simplify it! I agree an int is not necessarily the size of a pointer. Back when I learnt C you could almost guarantee it was though :o

When I learned C, ints where typically 16 bits and pointers typically 32 bits. This changed a few years later to 32 + 32 bits, but in five years time it will usually be 32 and 64 bits.