Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12

    [c] passing a pointer to pointer to a function (i think)


    getting in a muddle with passing pointers to pointers, at least i think that's what i'm getting in a muddle with.

    basing my code on this code from the book i'm following:
    Code:
    ...
    main (int argc, char *argv[])
    {
    	...
    	...
    	while (--argc > 0 && (*++argv)[0] == '-')
    		while (c = *++argv[0])
    			...
    			...
    i want to do much the same (roughly/basically) as that but a main difference is, instead of dealing with argc and argv in main, i'm trying to pass them to another function and then use them from that function.

    this is a stripped down version of one of my many efforts:

    Code:
    #include <stdio.h>
    
    void test(int *argc, char **argv)
    {
    	int c;
    	
    	printf("function call   ");
    	
    	(*argc)--;	/* knock the value of argc down 1 (to know when end in main) */
    	argv++;		/* intended to step to the next string */
    	while(c = *argv++[0])	/* intended to step through chars of string */
    		putchar(c);
    	
    	putchar('\n');
    }
    
    main (int argc, char **argv)
    {
    	while(argc > 0)		/* not call function if no more strings in argv */
    		test(&argc, **argv);
    }

    example of intened result:

    enter this on command line:

    ./a.out 123 45 6789

    and the hoped for output from that is:

    a function call 123
    a function call 45
    a function call 6789

    i'm sure there's some other flaws (i've tried this many different ways and am going round in circles with it) that's stopping that happening, but the important thing right now i'd like to get sorted is to be able to get into the situation where i can deal with argv in my test function in the same way as the book code deals with argv in it's main code. in other words pass argv to the test function so that in that function it's in the same form as the form as it's in, in the book's main.

    at the moment the above code's error is:
    passing arg 2 of `test' makes pointer from integer without a cast

    another version didn't result in that error but then it didn't seem as if i'd passed argv as i hoped so i'm not sure.

    further small question: *argv[] is the same as **argv right? pretty sure it is, just want to check.

    any help much 'preciated :)

    [xtra] i've just realised that this test version of the code that i've posted above doesn't allow the argv pointer to increment/remember where it got to in the test function - so it'll always start from the start instead of from where it left off last. but forget that - doesn't matter - it's the **argv passing that's the problem [/xtra]
    Last edited by balance; March 26th, 2003 at 10:00 AM.
  2. #2
  3. jasondoucette.com
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    Canada
    Posts
    378
    Rep Power
    12

    Re: [c] passing a pointer to pointer to a function (i think)


    After scanning over this really quick:

    1. Q: further small question: *argv[] is the same as **argv right?

    Yes. Test this out yourself with a program that uses argv properly, and change it, and it'll still work.

    2. Your function is defined as:
    void test(int *argc, char **argv)
    and you call it like so:
    test(&argc, **argv);

    It wants 1. a pointer to an int and 2. an array of pointers, but you are passing it 1. a pointer to an int and 2. a pointer to a pointer to a type, which is of type array of pointers. Just call the function like:
    test(&argc,argv);

    I hope I got this right, since I only skimmed over it very quickly.
    Last edited by Jason Doucette; March 26th, 2003 at 10:36 AM.
  4. #3
  5. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12
    yup, you're absolutely right. good grief. why didn't i just ask this question earlier? got in a big mess with this.

    it's now working nearly completely ok, and that [xtra] bit i added isn't actually the case - it does carry on.

    but yes, call the function without any *s with argv. that's the answer i was after. :) thanks very much
    Last edited by balance; March 26th, 2003 at 12:54 PM.
  6. #4
  7. jasondoucette.com
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    Canada
    Posts
    378
    Rep Power
    12

    Re: Re: [c] passing a pointer to pointer to a function (i think)


    Originally posted by Jason Doucette
    ...you are passing it 1. a pointer to an int and 2. a pointer to a pointer to a type, which is of type array of pointers.
    Actually, I am wrong. You are dereferencing the pointer twice, and this value is what you are passing in. I should avoid answering questions right after I just wake up! :) The compiler didn't catch this, and explain what was wrong?
  8. #5
  9. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12
    but it works!? in fact that's what i'm going to ask now: how come it works?!...

    further confusion on the same thing, but different question.
    Code:
    #include <stdio.h>
    
    void test(int *argc, char **argv)
    {
    	char c;
    	
    	(*argc)--;	/* knock argc down 1 to know when to stop in main */
    	argv++;		/* step to the next string */
    	
    	printf("%d: ", *argc);
    	
    	while(c = *argv[0]++)	/* step through chars in the string */
    		putchar(c);
    		
    	putchar('\n');
    }
    
    main (int argc, char **argv)
    {
    	while(argc > 1)		/* not call function if no more strings in argv */
    		test(&argc, argv);
    }
    how come this is working? :) the part i'm talking about is that each time the function test is called the pointer manages to pick up from where it last left off, and i haven't made any concessions for that at all, and yet it is doing that. it's great that it is, but i can't see how or why?

    so when it's called with say:

    ./a.out abc de fghi

    the output is:

    3: abc
    2: de
    1: fghi

    i thought it would be like this, in an eternal loop:

    3: abc
    3: abc
    3: abc
    3: abc
    ...
    ...

    but it isn't. why does the pointer not need remembering in the function? or how is it getting remembered?
    Last edited by balance; March 26th, 2003 at 03:12 PM.
  10. #6
  11. jasondoucette.com
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    Canada
    Posts
    378
    Rep Power
    12
    Sorry, I should have made it clear. I was correct in my answer to what was wrong in your program. But my explanation of what you were passing in was incorrect... the fix for this incorrect parameter which I stated you should try was correct.
  12. #7
  13. jasondoucette.com
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    Canada
    Posts
    378
    Rep Power
    12
    To answer your question:

    Originally posted by balance
    how come it works?!...
    The reason it works, is because you are passing in a pointer to argc. So, when you dereference this pointer, you are accessing the original argc (thus, if you change it, the real one changes - there is no other copy of it in the function).
  14. #8
  15. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12
    But my explanation of what you were passing in was incorrect...
    i see. phew - that was going to throw me into even further confusion :)

    The reason it works, is because you are passing in a pointer to argc. So, when you dereference this pointer, you are accessing the original argc (thus, if you change it, the real one changes - there is no other copy of it in the function).
    ah but there's a bit more to it than that. yes, i stupidly missed that it won't be an eternal loop because of argc stopping it, but argv manages to step successfully. it doesn't repeat the same line. argc only determines if that function gets called or not. the value in argc is not used to effect the argv pointer at all. not directly in either function. so how does argv manage to pick up from where it got to each time? i think i've worked it out:

    the only thing that effects which string argv points to is the argv++; line, hense my confusion on why it's working. argv++; is an accumalative thing so there must be something global/external going on. it must be because argv is viewed to have been defined externally? therefore global. i think that must be it. argv, because it comes from outside main must be an external variable.

    but also i've used this code in the thing i want it for, and it *does not remember where it's got to*. when the function's called repeatedly, argv always starts from the start - never moves off the first line. it's the same basic structure of code - the only difference is that the called function (the equivelent of the function 'test' above) is in another file, so argv must be an static external variable. locally global to the file that main is in.

    wow, this problem, which is only an exercise from a book, has really had me going in circles :) thanks for the help

    [actualy i'm having doubts about that now - why does argc and argv need to be mentioned in main's arguments. but there must be something global going on. i don't know :) whatever]
    Last edited by balance; March 26th, 2003 at 09:56 PM.
  16. #9
  17. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2002
    Posts
    272
    Rep Power
    19
    It doesn't have anything to do with global variables.

    What really happens in most environments is this. The entire command line is given to the program as a single string. Before it is passed to main, the string is chopped up like this.

    ./a.out\0abc\0de\0fghi

    In case that isn't clear each part of the command line has the space after it replaced by a '\0'. argv[0] gets the address of "./a.out", argv[1] gets the address of "abc", and so on.

    In test() you are using argv[1], also known as *argv after the argv++. You also happen to always be incrementing the value of argv[1] to step through the string. This continues until you hit the '\0' and you fall out of the loop, but not before incrementing argv[1] again which puts it pointing at the next character in the original string. When you come back into test() you once again use argv[1] but it now points to the next string.

    I apologize for not being able to make this more clear. It would be a lot easier to see if you step through it in a debugger.
  18. #10
  19. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12
    i understand that the single string entered on the command line gets split by it's spaces and put into seperate strings, argv being an array of pointers to these strings.

    the part i do not understand is that the pointer that's being used to step though the different argv strings, it's value is being retained between seperate function calls and i can't see how or why that's happening. (maybe it's something very simple and obvious but i can't see it right now :))

    obviously, pointers point to things. if you change what a pointer points to within a function, that change will stay with what you've changed, even when the function ends. but..
    argv++; /* step to the next string */
    ..in 'test' doesn't seem to me to increment anything external to 'test', and yet argv's position is mirraculously (to me) retained function call after function call.

    as i say, i could easily be missing something obvious and silly - that's usually the case :) maybe argv++; is changing something external? that would explain it rather than argv being global.


    When you come back into test() you once again use argv[1] but it now points to the next string.
    so it is an external to 'test' variable, therefore an external change? :/
    Last edited by balance; March 27th, 2003 at 06:56 AM.
  20. #11
  21. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2002
    Posts
    272
    Rep Power
    19
    Incrementing argv in test() isn't what is doing it. Incrementing *argv is where it is happening. Your function doesn't step through the strings. It steps through a single string that just happens to contain all of the strings you are interested in. If the program loader actually created new strings in which to place the command line parameters your code would not work. As long as the new strings weren't adjacent to each other in memory.
  22. #12
  23. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2002
    Posts
    272
    Rep Power
    19
    Code:
    command line - ./a.out abc de fghi
    
                     argv
                      /
                     /
              ______/__________________________________
              | argv[0] | argv[1] | argv[2] | argv[3] |
              -----------------------------------------
              /            /          |          |
      _______/___    _____/___     ___|__    ____|____
      | ./a.out |    |  abc  |     | de |    | fghi  |
      -----------    ---------     ------    ---------
    
    In test() you are incrementing test's copy of argv so that argv now
    points to argv[1].  You then go through your loop that increments the
    value in argv[1] to point to each character successively until you
    reach the '\0'.  When your loop is finished argv[1] points to the character
    just past the '\0'.  The value in argv[1] that you have been changing is
    the value in the original argv[1] since that is the copy that argv points
    to.  You then call test() again and once again you use the value in argv[1]
    to traverse the string.  argv[1] points to the character just past the '\0'
    from the last call to test().  This just happens to be the next parameter.
    If you look at the values of argv[1] and argv[2] after the first call to
    test() you will see that they are the same.  You continue with this process
    until you have processed all of the parameters.  I think the part that you
    are missing is that you never actually traverse the list of parameters.  If
    the program loader actually placed the parameters in non-adjacent memory
    locations you would see that your code would only correctly print out the
    first one.
  24. #13
  25. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12
    Incrementing *argv is where it is happening.
    which is external to test rather than internal hense it's continued existence. right.
    Your function doesn't step through the strings. It steps through a single string that just happens to contain all of the strings you are interested in.
    right. i see. that is a very important point that i'd missed.

    ok, thanks for your explenation. - this has caused me the most trouble so far, in c, for some reason. thanks.


    oh, you've posted further explenation - great. haven't digested it yet. this was in response to the previous one
    Last edited by balance; March 27th, 2003 at 08:32 AM.
  26. #14
  27. jasondoucette.com
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    Canada
    Posts
    378
    Rep Power
    12
    Just as you were changing the variable argc outside of the function test() from within the function test(), you are doing the same thing with the strings pointed to by argv (the array of pointers to char). (It may make more sense to you to use this notation:
    int main (int argc, char *argv[])
    so you can easily see that it is an array of pointers to char.)

    3dfxMM mentioned this here:

    Originally posted by 3dfxMM
    ... The value in argv[1] that you have been changing is
    the value in the original argv[1] since that is the copy that argv points to....
    Remember that arrays are passed into function as pointers (which you are doing explicitly, since you use the notation char **argv), but all that is passed in is a single pointer. As soon as you dereference this pointer, you are accessing the same data as the original pointer.

    I just wanted to make sure you understood this, because this can cause tons of problems and headaches if you don't understand.
  28. #15
  29. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12
    yup, the fact that the strings in this are actually best looked at as *a* string. multidimensional array is a pretty misleading phrase/concept in this situation - not helpful at all.

    (this is *the* key one: )
    also the fact that argv++, which amounts to argv[1], all the time, repeatedly, in test(), is being used to store the pointer throughout the whole thing.
    (the stepping always starting off from the same place that kept confusing me, is here - but it's actually good that it's always the same place! quite amazing luck that.)

    those 2 main points i failed to get, especially the second one, even though they'd been pointed out to me several times! :)

    it is amazing the code worked seeing as i didn't have a clue what was actually happening.

    so at last i think i can finally say i understand it :) thanks v. much to both of you for your various replies.

    phew.
    Last edited by balance; March 27th, 2003 at 12:28 PM.
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo