Thread: Pointers as Arguments in Functions

  1. #1
    Registered User
    Join Date
    Apr 2013
    Posts
    8

    Pointers as Arguments in Functions

    Hi,

    I'm having some problems with a function. The function is supposed to find the two largest values in an array.

    Code:
    void find_two_largest( const int *a, int n, int *largest, int *second_largest){
        largest = a;
        int temp;
        second_largest = a;
        for ( int i = 1; i < n; i++){
            if (*(a + i) > *largest){
                temp = *largest;
                *largest = *(a + i);
                *second_largest = temp;
                }
            else if (*(a+i) > *second_largest)
                *second_largest = *(a+i);
            
        }
    }
    I don't see any mistake with the code of the function, but when I try to call it inside my program it only returns 0 for both largest and second_largest.

    Code:
    int *find_middle( int *a, int n);
    
    void find_two_largest(const int *a, int n, int *largest, int *second_largest);
    
    
    int main()
    {
        int n;
        printf("No. of elements?");
        scanf("%d",&n);
        int a[n];
        printf("Elements of array:");
        for (int i=0; i<n; i++)
            scanf("%d", &a[i]);
        int largest, second_largest;
        find_two_largest(a, n, &largest, &second_largest);
        printf("Largest element is %d, second largest is %d", largest, second_largest);
    }
    Can someone tell me what I'm doing wrong. Do I have to declare the variables largest and second_largest as normal integer variables and then pass their addresses as arguments to find_largest or is that incorrect?

  2. #2
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    Line 2 and 4 obviously don't do what you think they should do.

    Compare them to line 8

    If you have such a problem with pointer notation - use array notation + temporary variable inside your function to store the intermediate results.

    After your search is done - assign the found data to output parameters.

    Another benefit with this approach - you can pass NULL to one of the output parameters and your function could verify it before final assignment and skip on it if the caller is interested to know one of them and not the both.
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  3. #3
    11DE784A SirPrattlepod's Avatar
    Join Date
    Aug 2013
    Posts
    485
    The compiler gives no warnings when compiling this code?

  4. #4
    Registered User
    Join Date
    Apr 2013
    Posts
    8
    Quote Originally Posted by vart View Post
    Line 2 and 4 obviously don't do what you think they should do.

    Compare them to line 8

    If you have such a problem with pointer notation - use array notation + temporary variable inside your function to store the intermediate results.

    After your search is done - assign the found data to output parameters.

    Another benefit with this approach - you can pass NULL to one of the output parameters and your function could verify it before final assignment and skip on it if the caller is interested to know one of them and not the both.
    Thanks for your answers guys.

    I thought that largest=a and second_largest=a would assign the address of the first element of the array to both pointer variables. Is that incorrect? I learned that array names can be used as a pointer to its first element and both largest and second_largest are pointer variables, so that assignment should be legal. *largest and *second_largest should then give the values of the first element. During the loop the elements of the array, *(a+i) that is, are then assigned to *largest depending on whether the conditions hold.

    From what I've read about pointers, they simply contain the address of the variable they are pointing to and after assigning a pointer variable to a variable the two are basically "equivalent", in the sense that if I change the value of one of the two, the other will be altered as well.
    Is that where the problem is in my function? Because the array is taken as a constant argument and if *largest and *second_largest point to the first element of the array, they essentially cannot be changed either?

    As far as writing the function with array notation, I could do that, but I'm just learning about pointers and the book I'm reading required me to write the function with pointer arithmetic and pointer arguments.

    The compiler did give the warning: "Assigning to 'int *' from 'const int *' discards qualifiers. Did not know what that means.


  5. #5
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Quant89 View Post
    I thought that [COLOR=#000000][FONT=Consolas][FONT=arial]largest=a and second_largest=a would assign the address of the first element of the array to both pointer variables. Is that incorrect?
    That is correct.
    Quote Originally Posted by Quant89 View Post
    I learned that array names can be used as a pointer to its first element and both largest and second_largest are pointer variables, so that assignment should be legal.
    Yes, array names are converted by the compiler to a pointer to the first element, and the assignment is legal.

    Problem is, the assignment is suspicious, for reasons I'll come back to.

    Quote Originally Posted by Quant89 View Post
    *largest and *second_largest should then give the values of the first element.
    Well, that is true. *largest and *second_largest, given your pointer assignments, are references to the first elements of a.

    Quote Originally Posted by Quant89 View Post
    During the loop the elements of the array, *(a+i) that is, are then assigned to *largest depending on whether the conditions hold.
    Yes. Except that your understanding is now incorrect.

    largest is a pointer to the first element of a (i.e. a[0]). So "*largest = *(a + i)" has the same effect as "a[0] = a[i]". The assignment *largest = <anything> does not change what largest points at.

    Quote Originally Posted by Quant89 View Post
    From what I've read about pointers, they simply contain the address of the variable they are pointing to and after assigning a pointer variable to a variable the two are basically "equivalent", in the sense that if I change the value of one of the two, the other will be altered as well.
    Yes, but an assignment to *p (where p is a pointer) does not change the value of the pointer p. Your code is misbehaving because you expect "*largest = *(a + i)" to have the same effect as "largest = a + i;". It doesn't.

    Quote Originally Posted by Quant89 View Post
    Is that where the problem is in my function? Because the array is taken as a constant argument and if *largest and *second_largest point to the first element of the array, they essentially cannot be changed either?
    If you took heed of your compiler warning (see below) you would realise that lines 2 and 4 are suspicious (consistent with what vart told you). "largest = a" causes largest to be a non-const pointer with the same value as the const pointer a. That is suspicious, because subsequently doing "*largest = <something>" is legal, but doing "*a = <something else>" is illegal.


    Quote Originally Posted by Quant89 View Post
    The compiler did give the warning: "Assigning to 'int *' from 'const int *' discards qualifiers. Did not know what that means.
    Yes, indeed. Your compiler was warning you about the problem in your code.

    "Assigning to 'int *' from 'const int *' discards qualifiers." is compiler-speak for "you have taken a const pointer (a pointer that points at something that CANNOT be changed) and made a non-const pointer (a pointer to something that CAN be changed) from it".
    Last edited by grumpy; 08-23-2013 at 07:31 AM.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  6. #6
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    Quote Originally Posted by Quant89 View Post
    largest=a and second_largest=a would assign the address of the first element of the array to both pointer variables.
    But you do not want this behavior.

    Originally largest and second_largest point to the variables where caller expect to get the result. So you do not want to change where these pointers are pointing, rather cahnge the value of variables they are pointing at.

    That's why I would do like this:

    Code:
    void find_two_largest( const int *a, int n, int *pLargest, int *pSecond_largest){
        int largest = a[0];
        int second_largest = a[0];
        for ( int i = 1; i < n; i++){
          ...
          largest  = ...
          second_largest = ...
          ...
        }
    
        //here we have found values we are interested in and stored them into local variables.
    
       //now update the outgoing parameters
       if(pLargest)
          *pLargest = largest;
    
       if(pSecond_largest)
          *pSecond_largest= second_largest;
    
    }
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  7. #7
    Registered User
    Join Date
    Apr 2013
    Posts
    8
    Thanks a lot for your extensive answer, greatly appreciated. I have some questions left though.

    "The assignment *largest = <anything> does not change what largest points at."

    Does this only hold because the array was made constant or does *pointer = new value never change what p points to? Basically what I don't understand is whether the address of a variable is changed when its value is changed. If e.g. n is a normal integer variable with the value 10 and p is a pointer variable that points to n, if you then write *p=15, does p point to something else than at the beginning?

    "largest = a" causes largest to be a non-const pointer with the same value as the const pointer a. That is suspicious, because subsequently doing "*largest = <something>" is legal, but doing "*a = <something else>" is illegal.

    What about an assignment of the form largest = a +i if the condition is satisfied, is that legal? In that case, if the first if condition holds, I could merely change:

    Code:
     
    temp = *largest;
    *largest = *(a + i);
    *second_largest = temp;


    to

    Code:
    second largest = largest
    // second largest now points to formerly largest value
    largest = a + i;
    // largest now points to the address of the largest element of a up to this point
    unfortunately this still gives me the same error, what did I do wrong here?

  8. #8
    Registered User
    Join Date
    Apr 2013
    Posts
    8
    Quote Originally Posted by vart View Post
    But you do not want this behavior.

    Originally largest and second_largest point to the variables where caller expect to get the result. So you do not want to change where these pointers are pointing, rather cahnge the value of variables they are pointing at.

    That's why I would do like this:

    Code:
    void find_two_largest( const int *a, int n, int *pLargest, int *pSecond_largest){
        int largest = a[0];
        int second_largest = a[0];
        for ( int i = 1; i < n; i++){
          ...
          largest  = ...
          second_largest = ...
          ...
        }
    
        //here we have found values we are interested in and stored them into local variables.
    
       //now update the outgoing parameters
       if(pLargest)
          *pLargest = largest;
    
       if(pSecond_largest)
          *pSecond_largest= second_largest;
    
    }
    Thanks for your answer, but if I do it that way, what exactly is the point of using pointers?

    Is it not possible to return two values in an int function and using a void function with pointer arguments is the only way to return two or more values?

  9. #9
    11DE784A SirPrattlepod's Avatar
    Join Date
    Aug 2013
    Posts
    485
    Quote Originally Posted by grumpy View Post
    snip
    Apart from all this, the only errors I can see are lines 2 & 4.

  10. #10
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    Quote Originally Posted by Quant89 View Post
    Thanks for your answer, but if I do it that way, what exactly is the point of using pointers?

    Is it not possible to return two values in an int function and using a void function with pointer arguments is the only way to return two or more values?
    I'm not clear what you are asking here.

    In regard of returning values from function using pointers as arguments my way does EXACTLY the same what your way should have being doing, if you have not added the bug due to misuse of pointers.
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  11. #11
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Quant89 View Post
    "The assignment *largest = <anything> does not change what largest points at."

    Does this only hold because the array was made constant or does *pointer = new value never change what p points to? Basically what I don't understand is whether the address of a variable is changed when its value is changed.
    It has nothing to do with constness. It has to do with the fact the value of a pointer is an address. The address is where a value (in your case of an int) is stored.

    Changing the value of a variable never changes its address.


    Quote Originally Posted by Quant89 View Post
    If e.g. n is a normal integer variable with the value 10 and p is a pointer variable that points to n, if you then write *p=15, does p point to something else than at the beginning?
    I'm not sure what you mean by "than at the beginning" (they make your question meaningless) so I'll answer your question as if those words aren't there.

    The assignment "*p = 15" will change the value of the variable n. It will not change the value of p. It does not change the address of n. The value of p (as distinct from the value of *p) was equal to the address of n before the assignment, and remains equal.

    Quote Originally Posted by Quant89 View Post
    "largest = a" causes largest to be a non-const pointer with the same value as the const pointer a. That is suspicious, because subsequently doing "*largest = <something>" is legal, but doing "*a = <something else>" is illegal.

    What about an assignment of the form largest = a +i if the condition is satisfied, is that legal?

    It is legal but suspicious. If a is a const pointer, a+i is also a const pointer. largest is not so, again, "largest = a + i" discards constness.

    And, more significantly, it does not do what you are expecting.

    Quote Originally Posted by Quant89 View Post
    In that case, if the first if condition holds, I could merely change:
    Quote Originally Posted by Quant89 View Post
    Code:
     
    temp = *largest;
    *largest = *(a + i);
    *second_largest = temp;


    to

    Code:
    second largest = largest
    // second largest now points to formerly largest value
    largest = a + i;
    // largest now points to the address of the largest element of a up to this point
    unfortunately this still gives me the same error, what did I do wrong here?
    It's a warning actually, although I suggest treating it as an error.

    The thing is the address of a variable and the value of a variable are different and distinct things (if they weren't, you could only ever have one variable in your program that has a value 42). You're incorrectly treating them as if they are the same ... sort of.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. arguments of functions
    By SCRIPT_KITTEH in forum C Programming
    Replies: 2
    Last Post: 06-05-2013, 07:04 PM
  2. Pointers to structures & functions arguments
    By lautarox in forum C Programming
    Replies: 4
    Last Post: 11-17-2008, 12:27 PM
  3. Functions as arguments
    By jw232 in forum C++ Programming
    Replies: 2
    Last Post: 04-19-2008, 11:11 AM
  4. functions and pointer arguments
    By Unregistered in forum C++ Programming
    Replies: 6
    Last Post: 01-08-2002, 05:04 PM
  5. passing arguments through functions
    By cwd in forum C Programming
    Replies: 2
    Last Post: 09-30-2001, 06:07 PM