#1
  1. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12

    pointer values that hang around in functions?


    a very usual thing done with pointers is to pass one that points to an array to a function, and use it within the function to modify the array it points to. obviously wherever the pointer ends up, the actual pointer variable itself gets thrown away at the end of the function. how can you make this pointer variable hang around in the function, so when you call the function again with the same call, it picks up from where it left off? like when you define a static variable in a function, that variable's value stays with the function on successive calls to that function.
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,086
    Rep Power
    2222
    Kind of like strtok() does, right?

    Here's an idea:
    1. Define a static variable to store the pointer in between function calls.
    2. Pass the pointer to the function, which stores it in that static variable and uses that variable for all the pointer operations in the function. That way, any subsequent changes to the pointer (eg, p++ to step through the array) will be stored in that static variable between calls.
    NOTE: If you need to keep track of both the beginning of the array and where you last left off, then you would need two static variables.
    3. In subsequent calls to the function, pass an invalid value for the pointer, such as NULL. This will tell the function to use the value(s) stored in the static variable(s).
    4. If you want to start working on a different array, then call the function with a valid (eg, non-NULL) value. This will tell the function to load the static variable(s).

    E.g.:
    Code:
    void foo(char* s)
    {
        static char *p;
    
        if (s != NULL)
            p = s;
    
        // process the char array using p
    
    }
    
    int main(void)
    {
        char str1[81];
        char str2[81];
    
        foo(str1);    // call foo for the first time & have it work on str1
        foo(NULL);  // subsequent call to work on str1
        foo(NULL);  // yet another call to work on str1
    
        foo(str2);    // now have foo start working on str2
        foo(NULL);  // subsequent call to work on str2
        foo(NULL);  // yet another call to work on str2
    
        return 0;
    }
    Another idea you might want to use, depending on the application, is to make a copy of the array for the function to work on, rather than have it work on the original data. For one thing, it leaves the original data intact and, for another, it protects you from having the function work on data that no longer exists.

    strtok() illustrates that idea. It scans the string being tokenized and then, when it finds a delimiter character, it replaces it with a NULL and returns a (char*) to that string. In the meantime, the original string is getting changed. So if you had a need to keep the original string intact, you would have to have made a copy first. Also, you cannot delete that string (eg, free(str) ) nor exit from the function that defines it before you have finished tokenizing it -- I haven't ever tested that, but I'm pretty sure you'd end up trying to tokenize garbage as well as clobbering something in the stack, like a return address.

    Hope that helps.
    Last edited by dwise1_aol; March 21st, 2003 at 06:27 PM.
  4. #3
  5. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12
    oh right, i didn't know of strtok()

    yeah, that's what i meant. thanks. apart from didn't you mean :
    Code:
    if (p == NULL)
            p = s;
    or maybe you didn't? not sure. well that's how i used it in anycase.

    i thought/hoped there might be a way without using another variable. i really thought this was going to work until i tried it. the function like this:

    Code:
    void foo(static char* s)
    {
        // process s
    }
    but the compiler wasn't having any of that. i really thought it would have worked because function parameters and function variables are very similar, but obviously not in this case.

    not sure about your 2nd solution. first solution seems much better i think - simpler.

    yup, thanks
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Beginner (1000 - 1499 posts)

    Join Date
    Feb 2001
    Posts
    1,472
    Rep Power
    15
    balance,

    A pointer is an address, so when you pass it to a function, there is no starting up again where you left off. The next time you call the function, the address you send to the function is the same, so you wouldn't need to make the pointer a static variable. If you were stepping through an array that was pointed to by the pointer, and you wanted to start up at the index position where you left off, then you could declare a static integer variable in your function to retain the index value:
    Code:
    void a_function(int* pnumbers)
    {
    	static int index_pos = 0;
    	for(int i=0; i<3; i++)
    	{
    		cout<<*(pnumbers + index_pos + i);
    	index_pos += 3;	
    }
    Last edited by 7stud; March 22nd, 2003 at 01:00 AM.
  8. #5
  9. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,086
    Rep Power
    2222
    Originally posted by balance
    oh right, i didn't know of strtok()

    yeah, that's what i meant. thanks. apart from didn't you mean :
    Code:
    if (p == NULL)
            p = s;
    or maybe you didn't? not sure. well that's how i used it in anycase.
    No, I did mean "if (s != NULL)". Look at the logic. If s is a valid address, ie non-NULL, then we do want to use it to start working on a new array. If s is equal to NULL, then we do not want to change the value of p, but rather keep on using it picking up where we left off.

    HOWEVER, you did catch a bug there. If we call foo() for the very first time with a pointer value of NULL, then p had never been initialized and we'll undoubtedly get a segmentation error. We have to trap against that, most likely with something like:
    Code:
        if (p == NULL)
            return;
    
        if (s != NULL)
            p = s;
    Depending on what return value you have foo return, it should indicate that an error was encountered: eg, -1 for int or NULL for a pointer type. Also, even though a static pointer variable should automatically initialize to NULL, I prefer to make those things explicit:
    Code:
    static char *p = NULL;
    Good eye there.
    Last edited by dwise1_aol; March 22nd, 2003 at 12:54 AM.
  10. #6
  11. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12
    A pointer is an address, so when you pass it to a function, there is no starting up again where you left off.
    i know a pointer is an address. if you're stepping that pointer along the array in the funciton then there is starting up from where you left off. all i was after is that the function should retain the pointer value rather discard it, like what static allows with function variables. - which is what i got
    The next time you call the function, the address you send to the function is the same, so you wouldn't need to make the pointer a static variable.
    i'm changing it, so i will
    If you were stepping through an array that was pointed to by the pointer, and you wanted to start up at the index position where you left off, then you could declare a static integer variable in your function to retain the index value
    oh yeah, that's probably better than making a static version of the pointer - it takes less space to store an int than a pointer. that's probably the best way to do it i guess.




    No, I did mean "if (s != NULL)". Look at the logic. If s is a valid address, ..
    oh right. the logic i was using is, if the static internal pointer isn't set yet, make the internal static pointer equal the pointer that's been passed to the function. otherwise don't touch the static internal pointer. i see what you mean - you're checking that the passed pointer is actually a pointer value. well, when i changed it to how i suggested it worked, but then i wasn't testing for valid pointer. but it worked.




    static char *p = NULL;

    is that ok? because what it looks like to me that you're setting what *p points to, if it points to anything, to NULL, not the pointer p to NULL.


    but in anycase, i think the best way to do it is as 7stud mentioned - don't step the actual pointer, use a seperate static int and add it to the pointer that was passed to the function.
  12. #7
  13. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,086
    Rep Power
    2222
    Originally posted by balance
    static char *p = NULL;

    is that ok? because what it looks like to me that you're setting what *p points to, if it points to anything, to NULL, not the pointer p to NULL.
    Yes, it is, because it is a declaration, not an assignment statement. The static char * part declares the variable p's type while the = NULL part defines the value that it is to be initialized to.

    Actually, my own trepidation at such declarations in a function is that the variable would be initialized every time the function is called, but that is only the case with auto variables, not static ones; e.g.:
    Code:
    void foo(void)
    {
        char *auto_p = NULL;  // auto_p gets initialized to NULL every time foo is called
        static char *p = NULL;  // p only gets initialized when the program starts up
                                //    and retains its most-recently-assigned value thereafter.
                                
    }
    but in anycase, i think the best way to do it is as 7stud mentioned - don't step the actual pointer, use a seperate static int and add it to the pointer that was passed to the function.
    Yes, that would also work. My approach included the ability to use the function to process several arrays in sequence (ie, when you're done with array1, reinitialize foo's static variable to process array2, then array3, etc.).

    So, you could pass the function the index you want it to start at. If the index is valid ( >= 0 ), then reinitialize your processing at that index. If the index is invalid (e.g., == -1), then continue with the index value in the static variable.
  14. #8
  15. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12
    Yes, it is, because it is a declaration, not an assignment statement. The static char * part declares the variable p's type while the = NULL part defines the value that it is to be initialized to.
    hmm, yup you're right that does seem to be fine, but how come this line in the same place in the code doesn't work then ? :
    Code:
    static char *p = s;
    s being the array pointer passed to the function as in your original code:
    initializer element is not constant
    seems a bit strange that it should work with NULL but not with another address (which is obviously what s is in the case). why does it matter what form the value is in? (just being curious - doesn't matter that much)
  16. #9
  17. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2002
    Posts
    272
    Rep Power
    18
    I'm not completely sure of this answer but here goes anyway. It would seem that static variables that are initialized in their declaration would have to be done at compile time so they can't use the value of a parameter since that parameter has no value at that time.
  18. #10
  19. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,086
    Rep Power
    2222
    Originally posted by balance
    hmm, yup you're right that does seem to be fine, but how come this line in the same place in the code doesn't work then ? :
    Code:
    static char *p = s;
    s being the array pointer passed to the function as in your original code:
    initializer element is not constant
    seems a bit strange that it should work with NULL but not with another address (which is obviously what s is in the case). why does it matter what form the value is in? (just being curious - doesn't matter that much)
    Initialization is handled in the start-up code, which ends with a function call to main() -- id est, it's all handled before your code even begins to run.

    Therefore, initialization values must be known at compile time. In your example, the variable s will not have a value until [relatively] long after the start-up code has finished running.

    The value of NULL is known at compile time, at least after the preprocessor has run. In MinGW, it is defined in stddef.h thus:
    #define NULL ((void *)0)

    You can also initialize a pointer to point to a variable or function, because that address would be known at compile time. Be advised that "compile time" includes the link step, since the address in question could be in another module and so would have to be fixed up first. But I trust you understood what I meant.
    Last edited by dwise1_aol; March 23rd, 2003 at 12:36 AM.
  20. #11
  21. No Profile Picture
    .
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2002
    Posts
    296
    Rep Power
    12
    It would seem that static variables that are initialized in their declaration would have to be done at compile time so they can't use the value of a parameter since that parameter has no value at that time.
    yup, that makes total sense - i never take the compiler errors in properly, but the compiler error and your explanation there makes it clear. it also explains the problem i had with attempting to attach 'static' to the pointer within the function definition line
    Code:
    void foo(static char* s)
    {
        // process s
    }
    which resulted in the same error, if i remember correctly.
    You can also initialize a pointer to point to a variable or function
    right i was about to say NULL is the only value possible there then, but there's that as you say. i'm just at function pointers in my book - haven't covered them yet.
    "compile time" includes the link step, since the address in question could be in another module and so would have to be fixed up first.
    yup, got ya.

    thanks v. much :)

IMN logo majestic logo threadwatch logo seochat tools logo