What the *?
August 16, 2009 4:09 PM
int *ptr=(int*)2;
...could someone explain the use of the second asterisk?So I'm trying to wrap my head around 'C' (...or is that 'C' around my head?)
I've been reading a pointer tutorial. I understand that I can declare a pointer by saying:
int *skybird;
...or declare it and assign an address of a variable to it by saying:
int *skybird=&dropkick;
...but if I declare the pointer and then assign the address to it in seperate statements, like thus:
int *skybird;
*skybird=&dropkick;
...Xcode warns me that my assignment makes integer from pointer without a cast. I take this to mean that the address of dropkick has no predetermined cast. So, I fix this by saying:
...
*skybird=(int)&dropkick;
...although this:
int *skybird=&dropkick;
...without having to using the integer operator on
&dropkick
, is fine. (I'm not sure why that is.)I could declare a pointer and assign it a value right there and then, like:
int *crystal_palace=2;
...but I get the same cast warning as before. So I change it to:
int *crystal_palace=(int)2;
Makes sense to me. But, same warning. So I do as I've seen in my text books and type in an extra asterisk:
int *crystal_palace=(int*)2;
...and all is well. Thing is, I don't understand why. In short. Why the *?
This works:
int *skybird;
*skybird=(int)&dropkick;
But this doesn't:
int *skybird=(int)&dropkick;
My brain is casserole.
I've scoured my books but cannot find an explanation for the asterisk in the rvalue cast operator. (Am I speaking the correct jargon?) I understand the asterisk used before the pointer when declaring the pointer tells the compiler that I'm declaring a pointer. I understand that the asterisk is used before the pointer name when referencing the value stored at the location pointed to. I understand the no operator is used when the address pointed to needs to be referenced. I also understand that to reference the address of the pointer itself, the ampersand operator is used. I've looked and looked and looked, and I'm stuck. Bonus points if you could tell me why
(int)*bo=(int*)2;
is wrong.It's a typecast to type "pointer to integer". What it means is the variable "ptr" will get the address "2" loaded into it, without the compiler complaining about mixed types.
By the way, it's lousy code style. Magic numbers are evil.
posted by Chocolate Pickle at 4:13 PM on August 16, 2009
By the way, it's lousy code style. Magic numbers are evil.
posted by Chocolate Pickle at 4:13 PM on August 16, 2009
Actually, BaxterG4 is right -- it's still going to get a type mismatch error because the left side of the assign resolves to type "integer", not to type "integer pointer".
posted by Chocolate Pickle at 4:14 PM on August 16, 2009
posted by Chocolate Pickle at 4:14 PM on August 16, 2009
To follow-up to myself: if you say "*skybird = &dropkick", you're saying "dereference skybird (in other words, figure out what it's pointing to, which right now will be nothing good since you haven't assigned to it) and then set the memory *at that location, the address skybird currently points at* to the address of dropkick.
posted by BaxterG4 at 4:17 PM on August 16, 2009
posted by BaxterG4 at 4:17 PM on August 16, 2009
One thing I've noticed in this post is that you always put the '*' next to the variable name when declaring an integer and I think this is causing the majority of your problems.
when the C compiler sees
int *skybird=(int)&dropkick;
it really sees this...
[int *] skybird = [int] [&]dropkick;
so you're assigning the value of dropkick to be a casted int to a pointer to an integer named skybird. An integer is not a pointer.
Read the C based chapter of Thinking in C++ to learn more about how the C compiler reads all those *'s and &'s.
posted by sleslie at 4:25 PM on August 16, 2009
when the C compiler sees
int *skybird=(int)&dropkick;
it really sees this...
[int *] skybird = [int] [&]dropkick;
so you're assigning the value of dropkick to be a casted int to a pointer to an integer named skybird. An integer is not a pointer.
Read the C based chapter of Thinking in C++ to learn more about how the C compiler reads all those *'s and &'s.
posted by sleslie at 4:25 PM on August 16, 2009
(int*) means an int pointer.
(int * skybird;) declares an int pointer named "skybird"
(int * skybird = value;) would declare an int pointer "skybird", and set its pointing address to "value".
(int * skybird = &value;) would assign an int pointer "skybird", and set its pointing address to the address of "value".
(skybird = value;) would assign "skybird" to point to the address "value".
(skybird = &value;) would point "skybird" to the address "value" is at
(*skybird = value;) would assign the memory at "skybird" to the value "value"
(*skybird = &value;) would assign the memory at "skybird" to the address of "value" - the hexidecmial address.
Off the top of my head, the only reason you should be casting something to (int*) would be if you're going from a void pointer.
posted by leafxor at 4:25 PM on August 16, 2009
(int * skybird;) declares an int pointer named "skybird"
(int * skybird = value;) would declare an int pointer "skybird", and set its pointing address to "value".
(int * skybird = &value;) would assign an int pointer "skybird", and set its pointing address to the address of "value".
(skybird = value;) would assign "skybird" to point to the address "value".
(skybird = &value;) would point "skybird" to the address "value" is at
(*skybird = value;) would assign the memory at "skybird" to the value "value"
(*skybird = &value;) would assign the memory at "skybird" to the address of "value" - the hexidecmial address.
Off the top of my head, the only reason you should be casting something to (int*) would be if you're going from a void pointer.
posted by leafxor at 4:25 PM on August 16, 2009
BaxterG4 has it. You're confusing pointers with what they point to. int* skybird is a pointer to an integer. As you say yourself, "I understand that the asterisk is used before the pointer name when referencing the value stored at the location pointed to." Your statement "*skybird = &dropkick" attempts to store the address of dropkick where an integer should be stored.
Since you are trying to store an address, not a value, you want "skybird = &dropkick."
The reason "int *skybird = &dropkick" works is because what you're actually doing is declaring a pointer to int called skybird, then assigning to it the address of dropkick. If it helps, you can follow this convention when declaring pointers:
"int* skybird = &dropkick" - stick the asterisk onto the int instead. It's exactly the same, but a bit clearer. You're saying "pointer to int skybird gets the address of dropkick."
posted by pravit at 4:29 PM on August 16, 2009
Since you are trying to store an address, not a value, you want "skybird = &dropkick."
The reason "int *skybird = &dropkick" works is because what you're actually doing is declaring a pointer to int called skybird, then assigning to it the address of dropkick. If it helps, you can follow this convention when declaring pointers:
"int* skybird = &dropkick" - stick the asterisk onto the int instead. It's exactly the same, but a bit clearer. You're saying "pointer to int skybird gets the address of dropkick."
posted by pravit at 4:29 PM on August 16, 2009
"int* skybird = &dropkick" - stick the asterisk onto the int instead. It's exactly the same, but a bit clearer.
In this one instance it's exactly the same. But in this case it's not:
int* foo1 = &bar1, pointer2 = &bar2;
Here you'll get a warning because pointer2 is not actually type int*! It's type int instead. It's a historical thing in C/C++ that the proper way to do this is:
int *foo1 = &bar1, *pointer2 = &bar2;
Which is probably why your book put the * next to the variable and not the type.
IMHO, the confusion you're having is with context. When you declare a variable, "*" means to make it a pointer to the type. Everywhere else, "*" means to dereference the pointer contained in the variable (unless it's in a context where it means multiplication).
Also, forget that you even know casting exists. It's one of the most frequent mistakes beginner C/C++ users make. They see a compiler warning about types, add a cast w/o knowing why, and then think everything is fine. It's not, so don't do it.
In scripting languages, casting means "change the type of this variable". In C/C++, casting means "trust me when I say that this variable can be treated like TYPE." No conversion takes place! Casting an int to a char* does not magically make it a string. What it will do is probably cause a segfault.
The exception to that being that C++ classes can override casting to do conversions. There's always an exception, but until you know what can be safely cast to what, don't reach for those () on every error!
posted by sbutler at 4:44 PM on August 16, 2009
In this one instance it's exactly the same. But in this case it's not:
int* foo1 = &bar1, pointer2 = &bar2;
Here you'll get a warning because pointer2 is not actually type int*! It's type int instead. It's a historical thing in C/C++ that the proper way to do this is:
int *foo1 = &bar1, *pointer2 = &bar2;
Which is probably why your book put the * next to the variable and not the type.
IMHO, the confusion you're having is with context. When you declare a variable, "*" means to make it a pointer to the type. Everywhere else, "*" means to dereference the pointer contained in the variable (unless it's in a context where it means multiplication).
Also, forget that you even know casting exists. It's one of the most frequent mistakes beginner C/C++ users make. They see a compiler warning about types, add a cast w/o knowing why, and then think everything is fine. It's not, so don't do it.
In scripting languages, casting means "change the type of this variable". In C/C++, casting means "trust me when I say that this variable can be treated like TYPE." No conversion takes place! Casting an int to a char* does not magically make it a string. What it will do is probably cause a segfault.
The exception to that being that C++ classes can override casting to do conversions. There's always an exception, but until you know what can be safely cast to what, don't reach for those () on every error!
posted by sbutler at 4:44 PM on August 16, 2009
The "int x=5;" notation is really an abbreviation of "int x; x= 5"
and
"int y; int *x= &y; is really "int y; int *x; x= &y;"
but
"int y; int *x; *x= &y;" is bad; *x is an int but &y is an int*
If you find pointers confusing, you are correct.
It's part of the reason Java did away with them.
posted by hexatron at 4:49 PM on August 16, 2009
and
"int y; int *x= &y; is really "int y; int *x; x= &y;"
but
"int y; int *x; *x= &y;" is bad; *x is an int but &y is an int*
If you find pointers confusing, you are correct.
It's part of the reason Java did away with them.
posted by hexatron at 4:49 PM on August 16, 2009
The * operator means substantially different things in different places.
In variable definitions and type casts, it means 'pointer to', so int* means pointer to int. In variable definitions you have to be aware of the issue, like sbutler said. When used in a non-definition context, it means to get the value at the address where the pointer points to.
Now, I think you're confused when you say
int *crystal_palace=2;
In this case, you're defining a pointer to an int and assigning it a value of 2. Now this is not the same thing as defining an int that has a value of 2. The value of the pointer is supposed to be an index in memory that is the address of a int.
When you say something like this:
int foo = 5;
int *bar = &foo;
the value of bar is going to be some memory address like 0x34A9B425 or something. You don't care about the exact value. So, bar is 0x34A9B425, the address of foo (represented by &foo) is 0x34A9B425, foo is 5 and *bar is 5. Assigning a pointer a value like 2 directly like you did with crystal_palace doesn't make too much sense. This PDF has some diagrams that might help you
posted by demiurge at 5:54 PM on August 16, 2009
In variable definitions and type casts, it means 'pointer to', so int* means pointer to int. In variable definitions you have to be aware of the issue, like sbutler said. When used in a non-definition context, it means to get the value at the address where the pointer points to.
Now, I think you're confused when you say
int *crystal_palace=2;
In this case, you're defining a pointer to an int and assigning it a value of 2. Now this is not the same thing as defining an int that has a value of 2. The value of the pointer is supposed to be an index in memory that is the address of a int.
When you say something like this:
int foo = 5;
int *bar = &foo;
the value of bar is going to be some memory address like 0x34A9B425 or something. You don't care about the exact value. So, bar is 0x34A9B425, the address of foo (represented by &foo) is 0x34A9B425, foo is 5 and *bar is 5. Assigning a pointer a value like 2 directly like you did with crystal_palace doesn't make too much sense. This PDF has some diagrams that might help you
posted by demiurge at 5:54 PM on August 16, 2009
Actually, BaxterG4 is right -- it's still going to get a type mismatch error because the left side of the assign resolves to type "integer", not to type "integer pointer".
No, it doesn't. "int *i" is a pointer to int. Your first comment was correct.
posted by kenko at 6:20 PM on August 16, 2009
No, it doesn't. "int *i" is a pointer to int. Your first comment was correct.
posted by kenko at 6:20 PM on August 16, 2009
I've scoured my books
Have you gone all the way through K&R and done the exercises? Declarations, types, and pointers are very well-discussed in the book in clear, concise manners.
posted by secret about box at 7:50 PM on August 16, 2009
Have you gone all the way through K&R and done the exercises? Declarations, types, and pointers are very well-discussed in the book in clear, concise manners.
posted by secret about box at 7:50 PM on August 16, 2009
Think of your variables as being areas inside your computer which are capable of holding data values. By declaring a variable, you are restricting and specifying just what kind of data values will be stored there. You are also saying how a value stored there will be interpreted.
These areas, because of how computer hardware is laid out, can be specified numerically, though unless you are doing a very specialized kind of programming (not the kind someone just learning would do) you would never use such numbers explicitly. However, it is sometimes useful to record or modify the location where data is stored and C gives you ways to do so. If you want to talk about where a variable named dropkick is stored, you would call that place &dropkick. Just as some variables are restricted to integers, some variables are restricted to the places integers can be stored. This second kind of variable is called a pointer to an integer. If dropkick is an integer, &dropkick is of type pointer to an integer.
int * skybird; is a declaration of a variable that can be used to hold the location of an integer variable. Since &dropkick is just that kind of a value, we can assign it to skybird as in:
skybird = &dropkick;
Putting a cast on a variable is saying that you plan on treating (or interpreting) that variable in a way other than it was declared. So if you want to take a pointer and treat it as an integer, you coud do things like
dropkick = ((int) skybird + 3)/ 37;
Why you would want to do such a thing, though, is suspect, so C makes you write it out in a way that helps you see the error of your ways. (originally, C would allow this without the cast and maybe just give a warning but times have changed.)
When you say:
int *crystal_palace=(int*)2;
You are saying that the pointer to integer named crystal_palace has the numeric value 2.
In other words, whatever is in hardware location 2 in your computer (dependent on how your operating system manages memory) is being pointed to by variable crystal_palace. This is normally not what you want to do so you'd have to go out of your way with casts to say such a thing. The int * before crystal palace is part of the declaration, not part of the assignmen (innitialization) so you are assigning that 2 to crystal_palace, not to *crystal_palace. *crystal_palace refers to what the pointer named crystal_palace is pointing to. In this case, it refers to whatever is at hardware location 2.
You are not expected to understand this. (obscure reference to comment in Unix version 6 source code)
posted by Obscure Reference at 7:53 PM on August 16, 2009
These areas, because of how computer hardware is laid out, can be specified numerically, though unless you are doing a very specialized kind of programming (not the kind someone just learning would do) you would never use such numbers explicitly. However, it is sometimes useful to record or modify the location where data is stored and C gives you ways to do so. If you want to talk about where a variable named dropkick is stored, you would call that place &dropkick. Just as some variables are restricted to integers, some variables are restricted to the places integers can be stored. This second kind of variable is called a pointer to an integer. If dropkick is an integer, &dropkick is of type pointer to an integer.
int * skybird; is a declaration of a variable that can be used to hold the location of an integer variable. Since &dropkick is just that kind of a value, we can assign it to skybird as in:
skybird = &dropkick;
Putting a cast on a variable is saying that you plan on treating (or interpreting) that variable in a way other than it was declared. So if you want to take a pointer and treat it as an integer, you coud do things like
dropkick = ((int) skybird + 3)/ 37;
Why you would want to do such a thing, though, is suspect, so C makes you write it out in a way that helps you see the error of your ways. (originally, C would allow this without the cast and maybe just give a warning but times have changed.)
When you say:
int *crystal_palace=(int*)2;
You are saying that the pointer to integer named crystal_palace has the numeric value 2.
In other words, whatever is in hardware location 2 in your computer (dependent on how your operating system manages memory) is being pointed to by variable crystal_palace. This is normally not what you want to do so you'd have to go out of your way with casts to say such a thing. The int * before crystal palace is part of the declaration, not part of the assignmen (innitialization) so you are assigning that 2 to crystal_palace, not to *crystal_palace. *crystal_palace refers to what the pointer named crystal_palace is pointing to. In this case, it refers to whatever is at hardware location 2.
You are not expected to understand this. (obscure reference to comment in Unix version 6 source code)
posted by Obscure Reference at 7:53 PM on August 16, 2009
kenko: yes, int *i is a pointer-to-int, but then the original poster isn't using i, they're using *i, which dereferences i, yielding an int.
posted by BaxterG4 at 8:03 PM on August 16, 2009
posted by BaxterG4 at 8:03 PM on August 16, 2009
The question pertains to "int *ptr=(int*)2;"—that doesn't dereference it.
posted by kenko at 10:22 PM on August 16, 2009
posted by kenko at 10:22 PM on August 16, 2009
Mikey-San's "K&R" is Kernighan and Ritchie's "The C Programming Language". It's a good and classic C textbook by the people who created the language. Another great book is Randal Bryant's "Computer Systems: A Programmer's Perspective", which answers questions like yours by going right down into the assembly.
By the way, your question is one of the canonical confusions, and if your books aren't answering it, you might not have very good ones. For a language that's as old and common as C, I'd stick with the classics---there's a reason CS syllabi still list a book first published in 1978.
posted by d. z. wang at 11:03 PM on August 16, 2009
By the way, your question is one of the canonical confusions, and if your books aren't answering it, you might not have very good ones. For a language that's as old and common as C, I'd stick with the classics---there's a reason CS syllabi still list a book first published in 1978.
posted by d. z. wang at 11:03 PM on August 16, 2009
int *ptr=(int*)2; means "There is an integer at address 2 in memory. I'd like to access it via 'ptr'."
Unless you are working on embedded systems with special memory layouts, the statement you are asking about will probably set you up for a seg fault as soon as you try to use ptr.
posted by chairface at 10:22 AM on August 17, 2009
Unless you are working on embedded systems with special memory layouts, the statement you are asking about will probably set you up for a seg fault as soon as you try to use ptr.
posted by chairface at 10:22 AM on August 17, 2009
To add to what d. z. wang added to what I said, make sure you get the 2nd edition of K&R.
Don't be fooled by how thin it is compared to other programming books—there's a reason it's considered the C book by many in the field. (It doesn't cover C99 changes, but those won't be a problem to pick up.) Simply, it's a very well-written book and doesn't distract with useless language or poorly written examples.
posted by secret about box at 8:53 PM on August 17, 2009
Don't be fooled by how thin it is compared to other programming books—there's a reason it's considered the C book by many in the field. (It doesn't cover C99 changes, but those won't be a problem to pick up.) Simply, it's a very well-written book and doesn't distract with useless language or poorly written examples.
posted by secret about box at 8:53 PM on August 17, 2009
I see now. I was misinterpreting the white space.
Personally, I find the latter less confusing.
posted by run"monty at 1:31 PM on August 18, 2009
int *questionAnswered=1;
is the same as int* questionAnswered=1;
Personally, I find the latter less confusing.
posted by run"monty at 1:31 PM on August 18, 2009
This is old, but beware! You may find the latter less confusing, but it's potentially misleading. What does this declare?
A pointer to int, p, and an int, q. If you wanted to declare two pointers to int in the same statement you could say
posted by kenko at 7:15 PM on August 20, 2009
int* p, q;
A pointer to int, p, and an int, q. If you wanted to declare two pointers to int in the same statement you could say
int* p, *q;
or (in this case, this option would be less confusing) int *p, *q;
.posted by kenko at 7:15 PM on August 20, 2009
This thread is closed to new comments.
int *skybird;
*skybird=&dropkick;
Drop the first asterisk from your 2nd line — skybird is already of type pointer-to-int, so you're just wanting to set its value (i.e. what it points to) to &dropkick, the address of dropkick.
posted by BaxterG4 at 4:13 PM on August 16, 2009