I am teaching myself C programming, using "Head First C", published by O'Reilly. (And a couple of other texts, besides.)
I got very hung-up during the book's introduction to pointers, by the example program on p.58. What threw me was a little call-out in the text, pointing to the line:
int *choice = contestants;
The call-out reads:
“choice” is now the address of the “contestants” array.
And, as far as I can tell, that's wrong. That line assigns *choice to the value stored as the contestants array, is that not so?
Disclaimer: I don't have access to the book / chapter right now.
Considering contestants is of array type, quoting C11, chapter §6.3.2.1 (emphasis mine)
Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [...]
In your case, the array variable is used as the RHS of the assignment operator, so in that case contestants is the same as &(contestants[0]).
This is the exact same type of int * which is the same of the variable to be assigned (LHS).
So you have four answers already, but none of them mention the difference between assignment and initialization syntaxes.
int *choice = contestants; // initialization
The above is equivalent to this:
int *choice; // declaration
choice = contestants; // assignment to pointer
but completely different from this (which can't be done in an initialization):
int *choice; // declaration
*choice = contestants; // assignment to target (not valid unless choice is initialized)
The second version is incorrect as written because it tries to store the value of contestants at the address pointed to by choice -- but choice does not contain an address, unless you initialize it. Dereferencing a possibly-uninitialized pointer is always a mistake.
The book is correct. Pointers work differently from variables, and * works differently in different circumstances.
To start, you probably know that a pointer is just a variable containing the address to the location in memory of another item
When we use
int *choice
we create a pointer to an integer, which stores the address of the integer
In this case, I'm assuming contestants is an array. We'll assume it's an array of ints
int contestants[5] = [0,1,2,3,4];
Collections, such as arrays, are always stored as a pointer to the first element. The second element is therefore addressof_first_item + sizeof(element_stored).
Let's assume the address is 0x12345, it's like this int contestants = 0x12345
And now we store that address in choice:
int *choice = contestants
In other words, it's a pointer to an integer, which happens to be the first element in the contestants array.
As a side note, we could also write it as:
int* choice = &contestants[0];
The other use case for the * operator with regards to pointers, is dereferencing. Dereferencing involves getting the value at the address pointed to by a pointer.
int value = *choice;
will give us an integer with a value of 0, because the address stored points to the first element
What you maybe don't know is that the name of an array is a pointer on the first element of this array. example
int contestants[] = {1, 2, 3};
means that &contestants[0] has the same value as contestants
This is explained earlier in the chapter, in the BULLET POINTS list.
An array variable can be used as a pointer.
The array variable points to the first element in the array.
And also further down in the box labeled POINTER DECAY:
Because array variables are slightly different from pointer variables, you need to be careful when you assign arrays to pointers. If you assign an array to a pointer variable, then the pointer variable will only contain the address of the array.
Strictly speaking, the book is not correct, but your reasoning is also incorrect.
Assuming contestants is an array of int, the initialisation
int *choice = contestants;
is equivalent to
int *choice = &contestants[0];
In other words, the value of choice is the address of the first element of contestants. This conversion of contestants (the name of an array) to &contestants[0] (a pointer) commonly known as an "array to pointer" conversion.
However, this differs from the address of the contestants array, since the type is wrong. The address of the contestants array is &contestants, which has type int (*)[4] (i.e. address of an array of four int).
If you try to initialise
int *choice = &contestants;
the result will be a compilation error (since an int(*)[4] cannot be implicitly converted to an int *).
Your reasoning
And, as far as I can tell, that's wrong. That line assigns *choice to the value stored as the contestants array, is that not so?
is flawed, since the contestants does not have a stored value. It is a set of values.
It is true that &contestants[0] and &contestants have the same value, but they also have different type. So a comparison of &contestant[0] == &contestants will not compile. However, if the values are converted to a common type, such as (void *)(&contestants[0]) == (void *)(&contestants), the code will compile, and the converted values will compare equal.
Related
So for a while I was confused about array names and pointers.
We declare int a[10];
And somewhere down the road also have a and &a.
So I get how the syntax works. a is the array name. When it is not used as an operand for sizeof &, etc., it will be converted or "decayed" so it returns a pointer to integer holding the address of the first element of the array.
If the array name is used as an operand for sizeof or &, its type is int (*)[10]. So I guess the type is different because that "decay" does not happen.
But I still do not understand how &a works. My understanding is that it is giving me the address of whatever it was before the "decay" happened.. So before the "decay" to pointer happened, then what is it and how does the compiler work with the "original" to evaluate &a?
In comparison, if we declare int *p;
and later have &p and p somewhere in the code...
In this case the pointer to integer p is given a separate pointer cell with its address and the value at that address will be whatever address we assign to it (or the garbage value at that address pre-assignment).
a does not get assigned a separate pointer cell in memory when it is declared int a[10]. I heard it is identified with an offset on the register %ebp. Then what is happening with the compiler when it evaluates &a? The "decay" to a pointer to integer is not happening, there was no separate "pointer" in the first place. Then what does the compiler identify a as and what does it do when it sees that unary & operator is using the array name as an operand?
Given:
int a[10];
the object a is of type int[10]. The expression a, in most but not all contexts, "decays" to a pointer expression; the expression yields a value of type int*, equivalent to &a[0].
But I still do not understand how &a works. My understanding is that it is giving me the address of whatever it was before the "decay" happened.. So before the "decay" to pointer happened, then what is it and how does the compiler work with the "original" to evaluate &a?
That's not quite correct. In &a, the decay doesn't happen at all. a is of type "array of 10 int" (int[10]), so &a is of type "pointer to array of 10 int" (int(*)[10]).
There's nothing special about this. For any name foo of type some_type, the expression &foo is of type "pointer to some_type". (What's confusing about it is that this is one of the rare cases where an array name doesn't behave strangely.)
It's best to think of the words "array" and "pointer" as adjectives rather than nouns. Thus we can have an array object, an array expression, an array type, and so forth -- but just "an array" is ambiguous.
This:
int a[10];
defines an array object named a (and allocates 4 * sizeof (int) bytes to hold it). No pointer object is created. You can create a pointer value by taking the address of the object, or of any element of it. This is no different than objects of any other type. Defining an object of type some_type doesn't create an object of type some_type*, but you can create a value of type some_type* by computing the address of the object.
Then what does the compiler identify a as and what does it do when it
sees that unary & operator is using the array name as an operand?
The compiler identifies a as a 10-element integer array, and when it sees the & operator, it returns the address of that array.
Just like it would see int i = 3; as an integer, and &i as the address of that integer.
Concerning taking the address of an array: an array is an object in and of itself, so it has both a size and an address (though taking its address is seldom useful).
The conversion of an array to a pointer to its first element is a form of type coercion. It only happens if the alternative would be a compile error.
For instance, you can't compare an array to a pointer, so the array (implicitly) is coerced (cast) to an int* (to its first element) and then the pointer types are compared. In C you can compare any pointer types. C just doesn't care (though it will likely emit a warning).
This is actually comparing int* to int(*)[10] as far as types are concerned, as you said. These will necessary have the same address (regardless of typing) because arrays hold their data directly. So the address of an array will always be the address of its first element.
However, it's not an error to get the size of an array, so sizeof(a) gets the size of the entire array, as no coercion is needed to make this legal. So this is the same as sizeof(int[10]).
Your other case sizeof(&a) is really sizeof(int(*)[10]) as you said.
If I initialized a 2d array let’s say
Int a[2][3] = {
1, 2, 3,
4, 5, 6};
Is a[0] == &a[0]??
I know a[0] refers to the address for the first element of the array. So is &a[0] still the address?
First of all, the type of arrayNum[0] is Int[3] and the type of &arrayNum[0] is Int(*)[3] (I didn't change the OP's Int to the probable int).
Secondly, arrays can decay to a pointer to its first element, so arrayNum[0] can decay to &arrayNum[0][0] which is of type Int*.
Both those pointers, &arrayNum[0] and &arrayNum[0][0] will point to the same location, but their types are very different.
I'm not sure what you meant to comapre using the == in your question, but let me tell you these, they are not the same.
Data type:
Check the data type.
a[0] is the first element of the array of type int [3].
&a[0] is the pointer to the first element of the array of type int [3], so, it is essentially int (*) [3].
Usage: Now, based on the usage, in certain cases Note, an "array type", decays to a pointer to it's first element. Considering that case, a[0] and &a[0], both are equivalent to writing &(a[0][0]), so the pointer value will be same.
For better understanding of the difference, use both a[0] and &a[0] as the argument yo sizeof operator (where the decay does not happen) and print the value using %zu conversion specifier.
Typically, they will print
12, which is (sizeof (int) * 3) and
8, which is sizeof (int (*) [3])
on a platform where size of an int is 4 and size of a pointer is 8.
[Note]:
Quoting C11, chapter §6.3.2.1
Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary& operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [....]
There are two senses in which you might ask whether a[0] equals &a[0]:
Do a[0] and &a[0] point to the same place?
and:
Does a[0] == &a[0] evaluate to true?
It is not clear from your question which you mean. Your text asks “Is a[0] == &a[0]?” Since the “==” is not in code format, it is not clear whether you intended to exclude it.
The answer to the first question is yes (given that a[0] is automatically converted to an address), and the answer to the second question is not necessarily.
As other answers and comments have pointed out, a[0] and &a[0] are different things. a is an array of two arrays of three int. So a[0] is an array of three int, and, in most expressions, it is automatically converted to a pointer to its first element. So the result is a pointer to an int, effectively &a[0][0]. In contrast, &a[0] is the address of an array of three int.
So, these expressions point to two different objects, but the two objects start at the same location, so the pointers point to the same “place.” We can see this in:
(char *) a[0] == (char *) &a[0] // Evaluates to true.
When we convert a pointer to a pointer to char, the result points to the first (lowest addressed) byte of the object. Since the two pointers point to the same place, this expression will evaluate to true.
However, when you evaluate a[0] == &a[0], there is a problem. To conform to the C standard, a comparison of pointers must compare pointers to compatible types. But int and array of three int are not compatible types. So this comparison is not strictly conforming C, although some compilers may allow it, likely with a warning message. We can instead evaluate:
a[0] == (int *) &a[0] // Value is not specified.
By converting the pointer on the right to a pointer to int, we make the left and right sides have the same type, and we can compare them. However, the result of the comparison is not defined. This is because that, although the C standard allows us to convert a pointer to one type to a pointer to another type, it does not generally guarantee what the value that results from the conversion is, except that, if you convert it back to the original type, then it will compare equal to the original pointer. (Converting to a pointer to a character type is special; for those, the compiler does guarantee the result points to the first byte of the object.)
So, since we do not know what the value of (int *) &a[0] is, we do not know whether comparing it to a[0] will return true or false.
This might seem strange; if one address points to the same place as another address, why wouldn’t they compare equal? On some computers, there is more than one way of referring to the same place in memory. Addresses may actually be formed of comnbinations of parts, such as base addresses plus offsets. For example, the address (1000, 230), representing 1230, points to the same place as (1200, 30), also representing 1230. But clearly (1000, 230) is not the same as (1200, 30).
When you compare two pointers to the same type, the compiler automatically adjusts the representations of the addresses in whatever way it needs to to perform the comparison. But, when you convert a pointer to one type to a pointer to another (non-character) type, the change of types may prevent the compiler from having the information it needs to do this adjustment properly. So the C standard does not tell us what happens in this case.
No they are not the same.
a[0] is an element of type int[3], while &a[0] is a pointer (of type int*[3]) to a[0].
But both of them points to the same address (the first element of a[0]), but are not the same.
For instance, consider;
char* a = "coding is fun";
I have understood that this line will create a pointer and put the string literal at its pointee's address.
Is that dereference operator actually doing its job there or is it just a part of the syntax and is just to tell the compiler to create a pointer data type?
Because if it really is working as a dereferencing operator there than => int* a = 5; should also put the value of 5 at the pointee's address of pointer a.
If not, then how is the former code snippet valid?
In case of a statement like
char* a = "coding is fun";
the dereference operator * is not used for any dereference. The * here can be considered as part of the type itself to denote that the variable is a pointer type, i.e., the type of the variable a is char *, i.e., pointer to a char.
That statement is basically creating an unnamed array, filling that with the coding is fun with the null-terminator and then, by assigning that unnamed array to the pointer, making the pointer point to the first element of that array, becasuse as per C11, chapter §6.3.2.1
Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [...]
To add to that,
int* a = 5;
is a valid syntax but invalid usage, because, there, you try to store the int value 5 as a pointer-to-int type, which is highly platform defined behavior.
It's valid because the language specification says it is.
You can expect 100% symmetry and orthogonality from C's syntax, but you're going to be disappointed. :)
Basically, you can read
char *a = "coding is fun";
as a shortcut for:
char a_string[] = "coding is fun";
char *a = a_string;
where, of course, the first line is a shortcut for:
char a_string[] = { 'c', 'o', 'd', 'i', 'n', 'g', ' ', 'i', 's', ' ', 'f', 'u', 'n', '\0' };
Obviously the name a_string is never introduced for real, but this is how it could be working under the hood.
No such shortcut exists for integers, but that's fine since no equivalent to the double-quoting exists either (your int *b = 5; example has a plain-looking 5, while the string example has a bunch of characters in double quotes).
The string literal becomes a pointer to an array living in the read only part of the process memory. (There is no such thing in the C standard, but that's how things actually work.)
So what you actually have is
char * a = <the said address>.
There is no such equivalent for integer values, so no, what you think doesn't work.
int* a = 5 sets the variable a to point to address 5.
char* a = "coding is fun" sets the variable a to point to the address of the "coding is fun" string, determined according to where the compiler/linker places it within the executable image.
Typically, it will reside in a read-only segment, but this is not dictated by the C-language standard.
For instance, consider;
char* a = "coding is fun";
I have understood that this line will create a pointer and put the
string literal at its pointee's address.
You've got that backward. The line declares a variable, a, of type char * (pointer to char), and initializes it with a pointer value that points to the first character of the given string literal. The literal itself represents an array of char. Its location is chosen by the compiler, and has nothing to do with the location of a, and certainly nothing to do with the indeterminate value that a would start with if it were not initialized.
Is that dereference operator actually doing its job there or is it
just a part of the syntax and is just to tell the compiler to create a
pointer data type?
It is not a dereferencing operator at all; it is part of the specification of the type of a.
Because if it really is working as a dereferencing operator there than
=> int* a = 5; should also put the value of 5 at the pointee's address of pointer a.
Your alternative definition of a as an int * is invalid because the expression 5 has type int, and assignment to a variable of pointer type requires the value assigned to have compatible pointer type, to have type void *, or to be a null pointer constant. Many compilers will still accept it, however, usually with a warning, because C allows ints to be converted to pointers (technically requiring a cast). In any event, the result is not a pointer that can be dereferenced to get the value 5, but a pointer that maybe can be converted to 5. This is the difference between evaluating *a and evaluating (int)a.
If not, then how is the former code snippet valid?
A string literal has type array of n char, where n is the number of chars in the literal, plus one for a terminator. In almost all C contexts, when a (sub-)expression of array type is evaluated, the result is a pointer to the first array element. In the case of evaluating a string literal, the type of the resulting pointer is char *, which is also the declared type of a. What could be wrong with assigning a value of a given type to a non-const variable with exactly the same type?
I just got a question from my Friend.
#include<stdio.h>
void fun(int[][3]);
int main(void){
int a[3][3]={1,2,3,4,5,6,7,8,9};
fun(a);
printf("\n%u",a);
a++;//Ques 1
printf("\n%u",a);
printf("%d",a[2][1]-a[1][2]);
return 0;
}
void fun(int a[][3]){
++a;//Ques 2
a[1][1]++;
}
The line Ques 1 will throw an error of L value as 'a' is the name of a two dimensional array. But this is not happening with the case of line Ques 2.
Can any one clear this doubt?
In Ques 1, a is an array and it will be converted to a non-lvalue pointer when used as operand of ++ operator and emit compile error.
In Ques 2, the argument int a[][3] is equivalent to int (*a)[3] and ++a is an increment of pointer variable, which is acceptable.
Quote from N1570 6.7.6.3 Function declarators (including prototypes), pargraph 7:
A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation.
When an array is passed as a function argument, it decays into a pointer to the array's first element.
Quest 1
a is an array, which is a non-modifiable lvalue. So it cannot be incremented.
Quest 2
The argument that is passed int a[][3]. This decays into a pointer to the first element, which is int (*)[3], (and not int *, contrary to common belief). A pointer may be incremented, so this works.
Also, you should be using %p for pointers in printf, and not %u.
Okay, first, "L value" means something you can assign to. a is the name of an array. So what that line is trying to do is the same as if you were doing a = a + 1 on the array itself, which doesn't make sense.
Now, what you are running into here is that C has a somewhat confusing way of treating arrays: they're really just undistinguished chunks of memory, and their name is a limited alias to the address of the beginning of the array. When you pass an array, what C actually passes is the address of the array (or in this case, the address of a particular point in memory inside the array.) So at Ques 2, that's actually a pointer, which is an L value and can be incremented.
This is called "arrays decaying to pointers" (as pointed out in a comment) and yeah, it can be confusing.
Why can't I do p=numbers++ or p=++numbers? The compiler shows the message: "lvalue required as increment operand" but isn't the pointer p a left value?
int main(int argc, char *argv[]){
int numbers[] = {1,2,3,4,5,6}, *p;
p=numbers++;
printf("%d ",*p);
return 0;
}
When you declare and define an array, the name of the array is an expression that evaluates to the address of the first element of the array. Think of the name as a constant that holds the address of the first element.
Once memory has been allocated for the array, the address of the array cannot be changed. Consequently, the value of the array identifier (name) cannot be changed either.
In your code, when you have
p = numbers++;
you are asking that numbers, which has the constant value of the address of the first element of the array, be incremented and point to the second element instead. This is not a legal operation. The increment operand requires a modifiable lvalue, and the name of the array is not a modifiable lvalue.
What is an lvalue? It is a locator value: something that identifies an area of memory that can hold another value. So when you declare:
int a = 5;
a signifies an area of memory large enough to hold an int, and the int held in that area of memory is 5. You can change that int by assignment:
a = 7;
but the identifier a still signifies the same area of memory. This means a is a modifiable lvalue.
When you declare and define your array:
int numbers[] = { 1, 2, 3, 4, 5, 6 };
numbers is an lvalue, in that it specifies an area of memory that holds the array of specified integers, but it is not modifiable. You can change the value of the elements in numbers, but you cannot change the value of numbers itself. numbers always evaluates to &numbers[0].
If you want to change where p points so that it points to the second element instead of the first, use:
p = numbers + 1;
This does not change the value of numbers itself, only that of p. numbers is still &numbers[0] and p will be &numbers[1].
Hope this is clear!
numbers++ is the equivalent of numbers = numbers + 1
However, numbers here is an array and you cannot modify the address of an array.
lvalue doesn't mean a "left value"
First I recommend that you read the C FAQ's section on Arrays and Pointers it is one of the better general references.
To directly address your error, if we look at the draft C99 standard we see that in sections 6.5.2.4 Postfix increment and decrement operators and
6.5.3.1 Prefix increment and decrement operators say in paragraph 1:
The operand of the prefix increment or decrement operator shall have qualified or
unqualified real or pointer type and shall be a modifiable lvalue.
section 6.3.2.1 Lvalues, arrays, and function designators paragraph 3 says:
Except when it is the operand of the sizeof operator or the unary & operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. [...]
and paragraph 1 says:
[...] A modifiable lvalue is an lvalue that does not have array type, [...]
so even though an array will decay to a pointer to the first element in many circumstances it is not a lvalue.
numbers is NOT a pointer. It is an array with this definition int numbers[] = {1,2,3,4,5,6}, and a rvalue. So the compiler shows the message: "lvalue required as increment operand".
Difference between array and pointer. Pointers - Difference between Array and Pointer