Brosef
Brosef

Reputation: 3095

Pointer syntax in a function

I thought I understood pointer syntax but there are small occurrences that throw me off, for instance:

int *ptr;
int array[4] = {1,2,3,4};
int *arrayEnd = array + n;

for (ptr = array; ptr < arrayEnd; ++ptr)
    sum += *ptr;

return sum;

How come we do ptr = array instead of *ptr = array when defining the for loop?

I also don't understand why when an argument to a function is a pointer, we don't use the asterisk.

I see this function(ptr); in books, but why not this: function(*ptr);.

Upvotes: 0

Views: 196

Answers (6)

Ran.CohenTawil
Ran.CohenTawil

Reputation: 61

Notice the asterisk meaning is different in definiton. when you write:

int *arrayEnd = array + n;

it is actualy the same as:

int *arrayEnd;
arrayEnd = array + n;

In both cases you initialize the address of the pointer and not the value referenced by the pointer

Also note that when you define an array the array name can be considered as the first memory location of the array while the number in brackets is its offset i.e. the next two lines are the same:

ptr = array;
ptr = &array[0];

and also the next two lines:

array[2] = 5;
*(array+2) = 5;

Funny fact about the last example is that it can explain you can sometimes write: 2[array] instead of array[2] as *(2+array) is the same as *(array+2)

So when you write:

int *ptr;
int array[4] = {1,2,3,4};
int *arrayEnd = array + n;

for (ptr = array; ptr < arrayEnd; ++ptr)
    sum += *ptr;

return sum;

the third line placed the memory address of the last array element in a variable called arrayEnd

the for loop is running from the first array location to the last array location

the sum adds the array elements

Upvotes: 0

Amarnath Krishnan
Amarnath Krishnan

Reputation: 1263

Assuming that you have code like below.

int x=10;

Here x is a variable that holds a value 10. The variable x is nothing but a label to some memory address.

        x
    +-------+
    |  10   |    4050 which is x
    +-------+

So value 10 is stored in 4050. Its always hard to remember memory address. So you make it easy by naming it and using that name.Here x is nothing but a label to memory address 4050.

int *x_ptr;

Here x_ptr is a pointer variable that can store memory address of any integer variable.

   +-------+
   |  GBV  |   5000 which is x_ptr
   +-------+

Here x_ptr is a label for address 5000. Initially the variable will contain Garbage Value(GBV).

x_ptr = &x;  

The above statement stores address of x in x_ptr.

   +-------+
   |  4050 |   5000
   +-------+
 x_ptr = &x = 4050
 printf("%u",x_ptr); // 4050
 printf("%d", *x_ptr); // 10

 *x_ptr = *(4050) = valueAt(4050) =  10  

Let us now discuss about your code.

int *ptr;

+-------+
|  GBV  |   6000 which is ptr
+-------+

int array[4] = {1,2,3,4};

+-----------+
|     1     |    7824 which is array+0 or array[0]
+-----------+
|     2     |    7828 which is array+1 or array[1]
+-----------+
|     3     |    7832 which is array+2 or array[2]
+-----------+
|     4     |    7836 which is array+3 or array[3]
+-----------+

Here array = 7824

int *arrayEnd = array + n; 

Incrementation with memory location will increase no of bytes based on the data type.

array+0 = 7824 + 0 = 7824
array+1 = 7824 + 1(4 bytes in case of integer) = 7824 + 4 = 7828
when n=4
    arrayEnd = 7824 + 16 =  7840
+-------+
|  7840 |   6010 which is arrayEnd
+-------+

for (ptr = array; ptr < arrayEnd; ++ptr)
   sum += *ptr;

Here ptr is initialized with array's base address(7824). So 7824 will be stored in memory 6000.

  6000             6000    
+-------+        +-------+
|  GBV  |   =>   | 7824  |   6000 which is ptr
+-------+        +-------+

so now ptr = 7824

For Loop
+-------+--------------+-------------+    
|  ptr  |   *ptr       | sum + =*ptr |  // 7824 < 7840
+-------+--------------+-------------+
|  7824 | *(7824) = 1  |  sum += 1   |  // 7828 < 7840
+-------+--------------+-------------+
|  7828 | *(7828) = 2  |  sum += 2   |  // 7832 < 7840
+-------+--------------+-------------+
|  7832 | *(7832) = 3  |  sum += 3   |  // 7836 < 7840
+-------+--------------+-------------+
|  7836 | *(7836) = 4  |  sum += 4   |  // 7840 !< 7840 so loop terminates
+-------+--------------+-------------+ 

Why ptr = array instead of *ptr = array?

valueAt(*) has to be used when you have to store some value in the memory address.

ptr= array; //initializing base address of array to ptr.

  6000             6000    
+-------+        +-------+
|  GBV  |   =>   | 7824  |   6000 which is ptr
+-------+        +-------+

*ptr = array; // ptr already has a address pointed to, and you store array's base address inside that memory location.

  6000     
+-------+  
|  GBV  |    *ptr= *(GBV) = Unknown = array  // No guarantee that GBV is a proper memory address
+-------+  

if ptr already has some proper memory address say 1000, then it is like

  6000     
+-------+  
| 1000  |    *ptr= *(1000) = valueAt(1000) = array 
+-------+  

which makes

  1000     
+-------+  
| 7824  |    
+-------+ 

Simple example with multi pointers.

#include<stdio.h>
int main()
{
    int x=10;
    int *y=&x;
    int **z=&y;
    printf("%d --> %d --> %d",x,*y,**z); 
    return 0;
}

OUTPUT:
   10 --> 10 --> 10

Upvotes: 1

verbose
verbose

Reputation: 7917

Let's begin with the first line of your code:

int *ptr;

If you had declared

int a;

What would it mean? It would mean a is an int. Similarly, since you have declared int *ptr;, it means that *ptr is an int.

If *ptr is an int, what is ptr? ptr (without the star) is a pointer to an int. A pointer is a variable that holds the address of a value. In this case, the pointer is a pointer to an int, which means the value at the address held by ptr is an int.

Then you have int array[4] = {1,2,3,4};. When you declare and define an array, the array identifier (the name of the array) tells you where the array lives in memory. When used in any expression, the name of the array decays to the address of the first element of the array.

So when you have

ptr = array;

you are assigning the address of the first element of the array to the pointer ptr. Since this is an array of int, you are assigning the address of an int to a variable which can hold the address of an int. The left- and right-hand side of the assignment are the same kind of value.

Why ptr and not *ptr? What is * in this instance? It is the unary dereference / indirection operator. So

*ptr = array; 

would mean: take the value on the right-hand side, and replace the value at the address held by ptr with this right-hand side value. This is wrong for two reasons.

  1. array is an address. It is not exactly an integer value. It's just a location in memory. Sure, that location can be represented by an integer, the way a location in the US can be represented by an integer zip code, but just as you don't typically care what the numerical value of a zip code is, you probably don't really care what the integer value of a given memory address is either.
  2. ptr is uninitialized. To go back to our earlier example: int a;. What is the value of a? We haven't set a value for it yet, so it has just garbage. Similarly, ptr isn't pointing to anything yet. It can point to an integer, but we haven't yet told it what integer to point to. There is no address held at ptr. We can't say "replace the current value pointed to by ptr by this new value", because ptr isn't yet pointing to any value at all; we haven't told it where to point to begin with.

To sum up: By writing ptr = array; what you are doing is precisely correct--assigning a pointer to an int to a variable of type pointer to an int. By writing *ptr = array; you would be assigning an address to an integer, which is probably not what you mean to do; and secondly, since the integer itself is not allocated anywhere in memory, the assignment has nowhere to go.

That's why ptr = array; is correct, and *ptr = array would be quite wrong.

The question about function pointers is a separate one, so please ask a different question about func(ptr) vs. func(*ptr).

Upvotes: 7

Code-Apprentice
Code-Apprentice

Reputation: 83527

Let's look at your suggested code:

*ptr = array

Remember that here, * is the indirection operator. It returns the object at the memory location to which the pointer points. Also, in this context array is converted to a pointer. So the above line assigns a pointer (i.e. a memory address) to the object ptr points to. This can only be valid if ptr points to a pointer. However, ptr points to an int instead.

On the other hand ptr = array is correct because assigns ptr to point to the first element in the array.

Upvotes: 1

Fred
Fred

Reputation: 8602

int *ptr, i;
int array[20];

ptr  = &i;        // make sure ptr points somewhere valid
ptr  = array;     // put the address of array[0] in the variable ptr
*ptr = array;     // put the address of array[0] into the location ptr points to
ptr  = array[0];  // put the integer in array[0] into the variable ptr
*ptr = array[0];  // put the integer in array[0] into the location ptr points to.

Upvotes: 1

Kerrek SB
Kerrek SB

Reputation: 476950

You can transform a traditional, index-based iteration into one using only pointer arithmetic like this:

T array[N];

// traditional:

for (size_t i = 0; i != N; ++i)
{
    foo(array[i]);
}

// using pointer arithmetic

for (T * p = array; p != array + N; ++p)
{
    foo(*p);
}

The pointer T * p = array is obtained via the decay of an array name to a pointer to its first element. The connection between the two forms is the fundamental identity array[i] == *(array + i).

Upvotes: 3

Related Questions