-1

As I'm learning C I often see pointers.

I get that a pointer is holding the hexadecimal value of a distinct location in memory. So a pointer is nothing other than e.g.:0x7fff5fbff85c

Every pointer is also of a distinct type.

int var = 10;
int *ptr = &var;

Ptr here points to the location of var. To get the value of var I have to dereference the pointer with *ptr. Like

printf("Var = %d", *ptr);

would print `Var = 10;

However If I do a non inline declaration of a pointer like:

int var = 10;
int *ptr;
ptr = &var;

I don't have to use the * in the third line when I'm actually assigning the memory adress to the pointer. But when I got a function that takes a pointer:

int var = 10;
void assignPointer(int *ptr) {
*ptr = 10;
}

Oh, wait! As I'm writing this I recognized that there are two different assignments for pointers:

*ptr = 10;

and

ptr = &var;

What is the difference? Am I in the first case first dereferencing the pointer, assigning 10 to the location that its holding? And in the second case I'am assigning the actual location to the pointer.

I'm a little bit confused when to use the * and when not to in terms of assignment.

And if I'm working with arrays, why do I need pointers at all?

int array[];

"array" here is already holding the hexadecimal memory location. Doesn't that make it a pointer? So If I wanted to assign something to array wouldn't I write:

*array = [10, 2];

First I'm dereferencing, then I'm assigning.

I'm lost :(

EDIT: Maybe it's a bit unclear. I don't know when you have to use a * when you are working with pointers an when not. Everything that is carrying a hexadecimal is a pointer right? The variable name of an array is carrying it's hexadecimal memory location. So why isn't it a pointer?

EDIT2: Thank you people you helped me a lot!

user148013
  • 361
  • 1
  • 2
  • 12
  • I see a long intro to pointers here.. What is the question? Arrays are not pointers. – Eugene Sh. May 10 '16 at 12:58
  • 4
    Please start with a good C book...you need that. – Sourav Ghosh May 10 '16 at 12:58
  • _There are either too many possible answers, or good answers would be too long for this format. Please add details to narrow the answer set or to isolate an issue that can be answered in a few paragraphs._ – Sourav Ghosh May 10 '16 at 12:59
  • Roughly spoken: `x` is the value of the pointer, `*x` is the value of the item pointed by the pointer. And don't mixup _declaration_ of a pointer (`int *p;`) and _using_ the pointer that has been previously declared (e.g. `*x = 5;` or `x = &value;`) – Jabberwocky May 10 '16 at 13:00
  • 1
    The confusion comes from `int *ptr = &var;` which defines `int *ptr` and sets its value to `&var`. If you already defined the pointer, you assign it with `ptr = &var`. You use the `*` to derefernce the pointer, ie to access what it is pointing to. So `ptr` is perhaps `0xffeebbcc` and `*ptr` is `10`. – Weather Vane May 10 '16 at 13:01
  • 1
    *"Everything that is carrying a hexadecimal is a pointer right?"* No - there is no hexadecimal inside the machine. Hex is a human readable format used when printing a pointer with the `%p` format, but you can print an `int` in hex too, with `%x` format. – Weather Vane May 10 '16 at 13:08
  • `Oh, wait! As I'm writing this I recognized that there are two different assignments for pointers:` You are funny. **1)** `*ptr = 10;` and `ptr = &var;` has nothing in common. There are two different things. **2)** Get a good book. – Michi May 10 '16 at 13:52

7 Answers7

6
I don't know when you have to use a * when you are working with pointers an when not. Everything that is carrying a hexadecimal is a pointer right? The variable name of an array is carrying it's hexadecimal memory location. So why isn't it a pointer?

Last thing first - the name of an array is not a pointer; it does not store an address anywhere. When you define an array, it will be laid out more or less like the following:

         +---+                
    arr: |   | arr[0]        Increasing address
         +---+                       |
         |   | arr[1]                |
         +---+                       |
          ...                        |
         +---+                       |
         |   | arr[n-1]              V
         +---+

There is no storage set aside for an object arr separate from the array elements arr[0] through arr[n-1]. C does not store any metadata such as length or starting address as part of the array object.

Instead, there is a rule that says if an array expression appears in your code and that expression is not the operand of the sizeof or unary & operators, it will be converted ("decay") to a pointer expression, and the value of the pointer expression will be the address of the first element of the array.

So given the declaration

T arr[N]; // for any type T

then the following are true:

    Expression         Type        Decays to        Value
    ----------         ----        ---------        -----
           arr         T [N]       T *              Address of first element
          &arr         T (*)[N]    n/a              Address of array (same value
                                                      as above
          *arr         T           n/a              Value of arr[0]
        arr[i]         T           n/a              Value of i'th element
       &arr[i]         T *         n/a              Address of i'th element
    sizeof arr         size_t                       Number of storage units (bytes)
                                                      taken up by arr

The expressions arr, &arr, and &arr[0] all yield the same value (the address of the first element of the array is the same as the address of the array), but their types aren't all the same; arr and &arr[0] have type T *, while &arr has type T (*)[N] (pointer to N-element array of T).

Everything that is carrying a hexadecimal is a pointer right?

Hexadecimal is just a particular representation of binary data; it's not a type in and of itself. And not everything that can be written or displayed in hex is a pointer. I can assign the value 0xDEADBEEF to any 32-bit integer type; that doesn't make it a pointer.

The exact representation of a pointer can vary between architectures; it can even vary between different pointer types on the same architecture. For a flat memory model (like any modern desktop architecture) it will be a simple integral value. For a segmented architecture (like the old 8086/DOS days) it could be a pair of values for page # and offset.

A pointer value may not be as wide as the type used to store it. For example, the old Motorola 68000 only had 24 address lines, so any pointer value would only be 24 bits wide. However, to make life easier, most compilers used 32-bit types to represent pointers, leaving the upper 8 bits unused (powers of 2 are convenient).

I don't know when you have to use a * when you are working with pointers an when not.

Pretty simple - when you want to refer to the pointed-to entity, use the *; when you want to refer to the pointer itself, leave it off.

Another way to look at it - the expression *ptr is equivalent to the expression var, so any time you want to refer to the contents of var you would use *ptr.

A more concrete example might help. Assume the following:

void bar( T *p )
{
  *p = new_value();  // write new value to *p
}

void foo( void )
{
  T var;
  bar( &var );  // write a new value to var
}

In the example above, the following are true:

 p == &var
*p == var

If I write something to *p, I'm actually updating var. If I write something to p, I'm setting it to point to something other than var.

This code above is actually the primary reason why pointers exist in the first place. In C, all function arguments are passed by value; that is, the formal parameter in the function definition is a separate object from the actual parameter in the function call. Any updates to the formal parameter are not reflected in the actual parameter. If we change the code as follows:

void bar( T p )
{
  p = new_value();  // write new value to p
}

void foo( void )
{
  T var;
  bar( var );  // var is not updated
}

The value of p is changed, but since p is a different object in memory from var, the value in var remains unchanged. The only way for a function to update the actual parameter is through a pointer.

So, if you want to update the thing p points to, write to *p. If you want to set p to point to a different object, write to p:

int x = 0, y = 1;
int *p = &x; // p initially points to x
printf( "&x = %p, x = %d, p = %p, *p = %d\n", (void *) &x, x, (void *) p, *p );
*p = 3;
printf( "&x = %p, x = %d, p = %p, *p = %d\n", (void *) &x, x, (void *) p, *p );
p = y; // set p to point to y
printf( "&y = %p, y = %d, p = %p, *p = %d\n", (void *) &y, y, (void *) p, *p );

At this point you're probably asking, "why do I use the asterisk in int *p = &x and not in p = y?" In the first case, we're declaring p as a pointer and initializing it in the same operation, and the * is required by the declaration syntax. In that case, we're writing to p, not *p. It would be equivalent to writing

int *p;
p = &x;

Also note that in a declaration the * is bound to the variable name, not the type specifier; it's parsed as int (*p);.

C declarations are based on the types of expressions, not objects. If p is a pointer to an int, and we want to refer to the pointed-to value, we use the * operator to dereference it, like so:

x = *p;

The type of the expression *p is int, so the declaration is written as

int *p;
John Bode
  • 119,563
  • 19
  • 122
  • 198
  • Wow thats the best explanation I've ever seen! Thank you! – user148013 May 11 '16 at 09:03
  • "If I write something to *p, I'm actually updating var. If I write something to p, I'm setting it to point to something other than var." - this is one good explanation – puerile Apr 30 '21 at 16:21
2

C syntax is weird like this. When you declare a variable, the * is only there to indicate the pointer type. It does not actually dereference anything. Thus,

int *foo = &bar;

is as if you wrote

int *foo;
foo = &bar;
fuz
  • 88,405
  • 25
  • 200
  • 352
1

One of your examples isn't valid. *ptr = 10;. The reason is that 10 is a value but there is no memory assigned to it.

You can think of your examples as "assigning something to point at the address" or "the address of something is". So,

int *ptr is a pointer to the address of something. So ptr = &val; means ptr equals the address of val. Then you can say *ptr = 10; or val = 10; cause both *ptr and val are looking at the same memory location and, therefore, the same value. (Note I didn't say "pointing").

Rob
  • 14,746
  • 28
  • 47
  • 65
  • *ptr = 10; This is getting the place where ptr is pointing to and then puts 10 into that place right? So why isn't it valid? Its assigning a value to the place where the pointer is pointing. – user148013 May 10 '16 at 13:04
  • @user148013 No. With C, everything is manual. You must assign a memory location and its value yourself. That's why, in your example, you set `int val = 10`. You declare a memory location that is an int and set it to 10. – Rob May 10 '16 at 13:05
  • @Rob, the context of OP's example is that ptr is a function argument, so generally it is safe to assume that there is memory allocated to hold a value. For a beginner. – HighPredator May 10 '16 at 13:06
  • @HighPredator No. You cannot declare a pointer to a value of "10" alone. Or at least that's dangerous cause then you are pointing at an unknown memory address and putting 10 in there. – Rob May 10 '16 at 13:07
  • I basically assumed this: `int var = 3; int *ptr = &var; *ptr = 9;` Var ist first 3, then ptr points to var's location, then var is set to 9 through the pointer. That's what I meant. I just didn't write the var assignment there because I did it in the first few lines. – user148013 May 10 '16 at 13:10
  • @Rob, we may have a slight misunderstanding here. The context of where " ptr = 10;" appears is "void assignPointer(int* ptr) { *ptr = 10;}" So as long as a valid memory address is supplied, you can't call it an unknown memory address. – HighPredator May 10 '16 at 13:14
  • @user148013 Yes. You declare ptr as a pointer to an int and you set it to the address of var, which is an int. Memory location var contains '3'. You then change the value at var with the pointer to it, ptr, by setting it to 9. – Rob May 10 '16 at 13:14
1

You are pretty much correct.

Am I in the first case first dereferencing the pointer, assigning 10 to the location that its holding? And in the second case I'am assigning the actual location to the pointer.

Exactly. These are two logically different actions as you see.

"array" here is already holding the hexadecimal memory location. Doesn't that make it a pointer?

And you got the grasp of it as well here. For the sake of your understanding I would say that arrays are pointers. However in reality it is not that simple -- arrays only decay into pointers in most circumstances. If you are really into that matter, you can find a couple of great posts here.

But, since it is only a pointer, you can't "assign to array". How to handle an array in pointer context is usually explained in a pretty good way in any C book under the "Strings" section.

HighPredator
  • 790
  • 4
  • 21
  • 1
    To be annoyingly pedantic, array *expressions* decay to pointers in most circumstances; array *objects* are always arrays. And you can't assign to arrays because the language definition says so; the compiler is smart enough to know when the target of an assignment is an array expression, and to complain accordingly. – John Bode May 10 '16 at 15:54
1

Pointers are declared similar to regular variables.The asterisk character precede the name of the pointer during declaration to distinguish it as a pointer.At declaration you are not de-referencing,e.g.:

int a = 0;
int *p = &a // here the pointer of type int is declared and assigned the address of the variable a

After the declaration statement,to assign the pointer an address or value,you use it's name without the asterisk character,e.g:

int a;
int *p;
p = &a;

To assign the target of the pointer a value,you dereference it by preceding the pointer name with *:

int a = 0;
int *p;
p = &a;
*p = 1;
machine_1
  • 4,266
  • 2
  • 21
  • 42
1

Dereferenced pointer is the memory it points to. Just don't confuse declaring the pointer and using it.

It may be a bit easier to understand if you write * in declaration near the type:

int* p;

In

int some_int = 10;
int* p = &some_int; // the same as int *p; p = &some_int;
*p = 20; // actually does some_int = 20;
Vasfed
  • 18,013
  • 10
  • 47
  • 53
1

You are right about the difference between assignment and dereferencing.

What you need to understand is that your array variable is a pointer to the first element of your continuous memory zone

So you can access the first element by dereferencing the pointer :

*array = 10;

You can access the nth element by dereferencing a pointer to the nth element :

*(array + (n * sizeof(my_array_type)) ) = 10;

Where the address is the pointer to the first element plus the offset to the nth element (computed using the size of an element in this array times n).

You can also use the equivalent syntax the access the nth element :

array[n] = 10; 
Tezirg
  • 1,629
  • 1
  • 10
  • 20
  • "You are also right on the fact that an array is a pointer." No, sorry, that's just wrong. An array is not a pointer, but it can decay to it. A difference can be seen when you use the `sizeof` operator on an array: the returned value is not the size of a pointer. See http://stackoverflow.com/questions/1641957/is-an-array-name-a-pointer-in-c for more. – Fabio says Reinstate Monica May 10 '16 at 13:19
  • Yep nice catch, I explained myself poorly. edited ;] – Tezirg May 10 '16 at 13:21