0

In C, the pointer is always my pain.

My question: When we add * to a pointer?

I see those two code:

First one:

int x;
int *ptr;
ptr = &x;

Second one:

int x;
int *ptr;
*ptr = 5;

Why first pointer has * in front of the pointer, but the second pointer does not?

Update: Why we don't do *pr = &x and ptr = 5?

FullStackDeveloper
  • 910
  • 1
  • 16
  • 40
  • May I know why I receive the down vote? – FullStackDeveloper Aug 29 '17 at 02:55
  • I didn't give the downvote but, if you hover over the image, you'll see "This question does not show any research effort; it is unclear or not useful". I'd be guessing the first stanza would be appropriate here. We're more than happy to help out new developers with basic questions but we need some indication that you've done more than simply put a question up here without thinking or looking for an answer first. Try not to take it as personal criticism, the vast majority of us vote the question, not the person. – paxdiablo Aug 29 '17 at 03:15
  • @paxdiablo I did do a lot of reading about the pointer. Just I said in the first sentence of my post, I just cannot understand the pointer well. Even though I read a lot of the pointer, but I just cannot completely understand it all. So, I ask the help in here, because I can discuss with a person like in a real-time. – FullStackDeveloper Aug 29 '17 at 03:20
  • Go back to your book. – iBug Aug 29 '17 at 04:02
  • @iBug I do not think you can down vote my post by saying 'Go back to your book'. This is a sharing platform, everyone can ask a question. If you cannot answer, please just leave my post. Thanks. – FullStackDeveloper Aug 29 '17 at 04:04
  • @QuestionContributor-- don't feel bad about some confusion on first encountering pointers. Note that there has been some tripping over language in the answers in trying to describe pointers. Note that `*` is also called the _indirection_ operator, and describing indirection in a direct way can be a tongue-twister.... – ad absurdum Aug 29 '17 at 04:09
  • 1
    QContrib, I understand, it's just that "In C, the pointer is always my pain" doesn't really give any indication as to what you'd tried. Saying something like "I've read book X and done free course Y at Edux but I still don't understand in which circumstances a `*` is needed" lets us know that you had given it some thought. I'm not saying you *hadn't* done any research, just that you should have indicated it. – paxdiablo Aug 29 '17 at 05:18
  • 1
    @paxdiablo All right, I will mention what effort I put before I ask a question, only SO does not think it is a noise message :) – FullStackDeveloper Aug 29 '17 at 13:57

7 Answers7

3

A variable holds a value, and that value is stored somewhere in memory (at an address). A pointer is a variable that holds as a value an address.

One use of * is in declaring a pointer; in the posted code, int *ptr; declares a pointer to int. The expression &x evaluates to the address of x, and so ptr = &x; stores the address of the variable x in the (pointer) variable ptr. If you use the variable ptr alone, as in:

printf("ptr = %p\n", (void *) ptr);

ptr will evaluate to the value stored in ptr, which is the address of x. Note here that the %p conversion specifier is needed to print a pointer value, and that it must be cast to (void *) to avoid undefined behavior.

If you want to use the value stored in the variable pointed to by a pointer, you dereference the pointer, using the * operator. That is, if you want to use ptr to obtain the value stored in x, you use *ptr:

printf("*ptr = x = %d\n", *ptr);

Similarly, if you want to store a value in a variable pointed to by a pointer, you can dereference the pointer:

*ptr = 5;
printf("x is now %d\n", x);

Now note that in your first code snippet, x is uninitialized (holds an indeterminate value), but x has been defined, and has an address, so ptr does hold a determinate value. But in the second code snippet, ptr is uninitialized, and so holds an indeterminate value. It is undefined behavior to use an indeterminate value, so in this case the line:

*ptr = 5; 

causes undefined behavior.

Here is a version of the posted code that avoids undefined behavior:

#include <stdio.h>

int main(void)
{
    int x;
    int *ptr;

    ptr = &x;
    printf("ptr = %p\n", (void *) ptr);

    x = 1;
    printf("*ptr = x = %d\n", *ptr);

    *ptr = 5;
    printf("x is now %d\n", x);

    return 0;
}
ad absurdum
  • 19,498
  • 5
  • 37
  • 60
  • Thanks. Can I say/remember this way, if a value on the right hand side is a variable, we do not need *, but if it is a constant value, we need to add * to the pointer? – FullStackDeveloper Aug 29 '17 at 04:22
  • No. You could have `int x = 0; int *ptr = &x; int y = 5; *ptr = y;` Then the variable `x` would hold the value `5`. Better to remember that pointer variables hold addresses and allow access to other variables through these addresses. It is a mouthfull at first, but you'll get used to it.... – ad absurdum Aug 29 '17 at 04:25
  • Got. If I want to change the value of the variable that pointer point to, I need to dereference the pointer, then I need to add * to the pointer? Only dereference a pointer need the pointer, am I right? – FullStackDeveloper Aug 29 '17 at 04:28
  • Yes to the first part. I am not quite sure what you mean with "Only dereference a pointer need the pointer." Dereference a pointer when you need to work with the value of the variable the pointer points to. Don't dereference the pointer when you need to work with the address of the variable the pointer points to. – ad absurdum Aug 29 '17 at 04:32
  • Also, note that you may want to dereference a pointer in a circumstance like this: `int *x; size_t size = sizeof *x;` Here `x` is a pointer to `int`, and in most expressions `*x` would be evaluated to the value held by the variable pointed to by `x`. But here, `x` does not point to any variable yet. Yet the behavior is not undefined, as it was in your 2nd code snippet. The difference is, `*x` is not _evaluated_ in a `sizeof` expression, only the _type_ of the expression `*x`, which is `int`, is used. I don't add this to confuse, only to give a preview of what is to come with pointers.... – ad absurdum Aug 29 '17 at 04:36
  • My bad. Just a typo. "Only dereference a pointer need the pointer." => Only dereference a pointer need the *. – FullStackDeveloper Aug 29 '17 at 04:46
  • After you explained, now I know when to do dereference the pointer. The last question, I just want to confirm how to dereference the pointer. Just add * in front of the pointer if I want to deference the pointer, no * means no dereference the pointer, right? – FullStackDeveloper Aug 29 '17 at 04:48
  • That is exactly right. The `*` is an operator (the _indirection_ operator). When you have a pointer such as `int x = 1; int *ptr = &x;`, the expression `*ptr` means that you want to operate on the pointer `ptr` with the indirection operator to dereference the pointer. The result is the value held by the variable pointed to by `ptr`, which is the value of `x`. This is why it is called indirection, you get at the value of one variable indirectly through another. – ad absurdum Aug 29 '17 at 04:52
  • 1
    I appreciate a lot of your answers and comments. I learned a lot. I will read more in here (http://www.cplusplus.com/doc/tutorial/pointers/). Thanks so much : ) – FullStackDeveloper Aug 29 '17 at 04:54
1

* in the declaration just specifies that this variable is a pointer. * when using the variable (i.e., anywhere other than the declaration) means you want to access whatever thing the pointer points to, rather than the pointer itself.

Leave the * out when you want to make the pointer point to a different object than it pointed to before (whatever's on the right should be an address of something):

ptr = &thing_it_points_to;

Use a * when you want the pointer to stay pointing to the same object, but change that object's value: *ptr = 5; // 5 is not an address here, it's the value I'm assigning to the int that this points to

So, your first one:

int x;
int *ptr; // * while declaring the variable tells us this is a pointer type
ptr = &x; // Get a pointer that points to 'x', and store it in 'ptr'

Second one:

int x;
int *ptr; // * while declaring the variable tells us this is a pointer type
*ptr = 5; // * while using the variable means to get the thing this pointer points to, and set it to 5

BTW, both of these are invalid code; x is used before being initialized in the first one, and ptr is used before being initialized in the second one.

Charles Srstka
  • 16,665
  • 3
  • 34
  • 60
  • In your second one, "while using the variable means to get the thing this pointer points to", what do you mean 'get the thing'? Could you explain more 'get the thing this pointer points to'? – FullStackDeveloper Aug 29 '17 at 03:06
  • The pointer is like a treasure map. The `x` variable is like a buried treasure chest. `*` means to go to the spot marked by the X on the treasure map, and get the treasure chest. Assigning without the `*` means to just get a new treasure map. – Charles Srstka Aug 29 '17 at 03:08
  • Only the second code snippet in the OP is invalid. The first defines `x`, so `x` has an address. The value of `x` is not used, only its address. [See this SO question](https://stackoverflow.com/questions/39918506/is-using-the-address-of-an-uninitialized-variable-ub) – ad absurdum Aug 29 '17 at 04:46
  • I mean, you are of course right, `x` has an address, so it's not *technically* invalid. But still. Initialize your variables. – Charles Srstka Aug 29 '17 at 06:04
1

Pointers can be suuuupppeerrr confusing.

To start, a pointer is a variable that stores the address of another variable.

When you declare a pointer, you need to declare it with a *. C is a statically-typed language and you need to define the type of the variable before assigning it.

So, int *ptr is declaring a integer pointer. char *string is a char pointer.

However, after declaring, when you use the * again it's for dereferencing the pointer. You can basically "read" that as "the value of" the memory address the pointer is pointing at.

Example:

int *ptr;
int x;

x = 10;
/*
* store the address of x in ptr
* so ptr is now pointing to x
*/
ptr = &x

/*
* this is printing the pointer
* which is pointing to the address of x
* so this will print you a memory address
* Output will be something like: 0x7fff9575c05f
*/
printf("%p\n", ptr);

/*
* this prints the value of the memory address
* save which is the value of x
* so in this case, this will print 10
*/    
printf("%i\n", *ptr);
glyif
  • 107
  • 1
  • 6
  • 1
    `int *ptr` is not initializing a pointer, but _declaring_ a pointer; there is an important difference here. – ad absurdum Aug 29 '17 at 03:46
  • @DavidBowling, sorry. You're right. just changed my answer to reflect. thanks for pointing it out – glyif Aug 29 '17 at 03:50
1

If * appear in declaration, for example:

It is declaring a pointer variable pt, not pointer variable *pt. variable pt is pointing to int type, and you can use it to store an address.

int *ptr;
ptr = &x;

If * appear in the an assignment statement, It is dereferencing a pointer, *ptr actually would means get the data/value in the memory that the pointer points to.

*ptr = 5;

It means to assign integer 5 to the content of pointer variable `ptr.

Why we don't do *pr = &x and ptr = 5?

*pr = &x and ptr=5 is actually (i) assigning address of x to the value of the pointer pointing to (ii) assigning an integer to an pointer variable

which cause an error/ undefined behavior.

Shiu Chun Ming
  • 227
  • 2
  • 13
0

So basically pointers in C store an address to a particular memory.

Any variable(such as the x in the above example) is stored in a location in the memory and therefore can be used a pointer to represent the location.

In C, the operation of getting the location of a variable in the memory is using the operator &, so ptr = &x means getting the pointer that points to the memory storing x and store the location into the pointer ptr.

And getting the variable at the location of a pointer is the operator * at the front of the pointer, so *ptr = 5 means setting the 4 bytes of memory that the pointer ptr points to 5.

However, the x in the first code is uninitialized, resulting in undefined behavior, and ptr in the second code is also uninitialized, and the statement *ptr = 5 certainly result in a runtime error because the memory ptr represents cannot be modified by the program. So strictly speaking, both of your code is invalid.

leyanpan
  • 433
  • 2
  • 9
  • "ptr = &x means getting the pointer that points to the memory storing x and store the location into the pointer ptr." I under this. Actually, I want to know, why we do not have '*' in ptr = & x, and why we have '*' in *ptr = 5? – FullStackDeveloper Aug 29 '17 at 03:17
  • In `ptr = &x`, you're changing the pointer itself (getting a new treasure map). In `*ptr = 5` we're leaving the treasure map unchanged, but we're putting something new in the treasure chest the map points to. – Charles Srstka Aug 29 '17 at 03:24
  • Although `x` is uninitialized in the first code snippet, `x` is _defined_, and has an address. It is fine to take this address and store it in a pointer variable. [See this SO question](https://stackoverflow.com/questions/39918506/is-using-the-address-of-an-uninitialized-variable-ub) – ad absurdum Aug 29 '17 at 03:42
0

In your code

int *ptr;
ptr =&x;

here ptr is looking for an address to store an integer of int type.

Eg: 0x77C79AB2

*ptr = 5;

here ptr looks for an integer and not an address.

Eg: 5 // (some number)

Because address is not treated as integer. You need to cast it to use as an integer

In your question

*ptr = &x and ptr =5

will throw error as it couldn't find the integer in the first and address in the second

roshan_nazareth
  • 311
  • 5
  • 16
0

As others have pointed out, '*' can be used to tell the compiler and other programmers that you are declaring a variable that holds an address. On the first case, you are storing taking the address of variable x(using '&') and storing in ptr. On the second case, you are taking the value that the address ptr stores has. So you have something like this:

--------------      --------------
|    ptr     |      |      x     |
|++++++++++++|      |++++++++++++|
|  xaddress  |----->|   xvalue   |       
|++++++++++++|      |++++++++++++|

You say ptr points to x because ptr is holding x's address.

Now really, pointers are just a convenience feature from the language. You don't have to use pointers to store addresses, although you should. The following is perfectly valid:

int x;
int ptr;
ptr = &x;

but you lose on readability and the convenience pointer arithmetic provides. If you did ptr+1 you would only advance 1 byte instead of 4 if you had declared ptr as a pointer. Furthermore, eventually you would want to access the contents of the address stores in your integer variable, so you would have to make an ugly cast, like so: * (int*)ptr and you would have to be extra careful because integer sizes are not always the same as integer pointer sizes. Your pointer might be 8 bytes and the integer might be 4, so you would actually have to declare long long ptr = &x;

savram
  • 500
  • 4
  • 18
  • 1
    Using this code: `int ptr; ptr = &x;` you obtain: `warning: assignment makes integer from pointer without a cast ptr = &x;` ^ – Sir Jo Black Aug 29 '17 at 09:44
  • 1
    An `int` may not be wide enough to hold a pointer value (as you note), but a `long long int` may also be too narrow to hold an address. A `long long` is required to be at least 8 bytes wide, but an address is not required to fit into 8 bytes; the width of a pointer is implementation dependent. Further, a pointer type is not an integer type; note that the width of the pointer is needed in pointer arithmetic. In your example, `ptr + 1` would be different than `ptr + 1` in OP examples. Use pointers to hold addresses. – ad absurdum Aug 29 '17 at 12:33
  • I know the width of the pointer is implementation dependent, it was just an example to show how unwise it is to store an address in a normal integer. And yes, there are different pointer types, integer pointer, char pointers, etc. When I said about the ptr+1 I assumed the integer pointer was 4 bytes on the OP's example. That's why I went to talk about that it's not always the case. But thank you for the clarification, it adds to the answer. @SergioFormiggini yes, the compiler even warns you that it's a bad idea. I'm just saying that you can do it, not that you should. – savram Aug 29 '17 at 15:49