Passing by reference in C... Help!

Discussion in 'Mac Programming' started by Littleodie914, Sep 19, 2008.

  1. macrumors 68000

    Littleodie914

    Joined:
    Jun 9, 2004
    Location:
    Rochester, NY
    #1
    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."

    Code:
    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:

    Code:
    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$ 
    
     
  2. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    At the very least pointer should be declared as

    Code:
    void pointer (char* a)
    
     
  3. thread starter macrumors 68000

    Littleodie914

    Joined:
    Jun 9, 2004
    Location:
    Rochester, NY
    #3
    Wow yea I couldn't believe I missed that. :eek: 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?
     
  4. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    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
    Code:
    *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.
     
  5. thread starter macrumors 68000

    Littleodie914

    Joined:
    Jun 9, 2004
    Location:
    Rochester, NY
    #5
    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?
     
  6. jsw
    Moderator emeritus

    jsw

    Joined:
    Mar 16, 2004
    Location:
    Andover, MA
    #6
    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:
    Code:
    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. :eek:
     
  7. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #7
    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:

    Code:
    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.
     
  8. thread starter macrumors 68000

    Littleodie914

    Joined:
    Jun 9, 2004
    Location:
    Rochester, NY
    #8
    That 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:

    Code:
    #include <stdio.h>
    
    void pointer(char ** a) {
    	*a = "Woah\n";
    }
    
    main() {
    	char *string = "Howdy\n";
    	
    	pointer(&string);
    	
    	printf("%s", string);
    }
     
  9. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #9
    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.

    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.
     
  10. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #10
    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
     
  11. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #11
    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 :eek:
     
  12. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #12
    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
     
  13. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #13
    Lol, old code sucks!
     
  14. macrumors G5

    gnasher729

    Joined:
    Nov 25, 2005
    #14
    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.
     
  15. macrumors G5

    gnasher729

    Joined:
    Nov 25, 2005
    #15
    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.
     

Share This Page