I am currently trying to understand pointers in C but I am having a hard time understanding this code:
int a[10];
int *p = a+9;
while ( p > a )
*p-- = (int)(p-a);
I understand the code to some degree. I can see that an array with 10 integer elements is created then a pointer variable to type int is declared. (But I don't understand what a+9 means: does this change the value of the array?).
It would be very helpful if someone could explain this step by step, since I am new to pointers in C.
When used in an expression1, the name of an array in C, 'decays' to a pointer to its first element. Thus, in the expression a + 9, the a is equivalent to an int* variable that has the value of &a[0].
Also, pointer arithmetic works in units of the pointed-to type; so, adding 9 to &a[0] means that you get the address of a[9] – the last element of the array. So, overall, the p = a + 9 expression assigns the address of the array's last element to the p pointer (but it does not change anything in that array).
The subsequent while loop, however, does change the values of the array's elements, setting each to the value of its position (the result of the p - a expression) and decrementing the address in p by the size of an int. (Well, that what it's probably intended to do; but, as mentioned in the comments, the use of such "unsequenced operations" – i.e. the use of p-- and p - a in the same statement – is actually undefined behaviour because, in this case, the C Standard does not dictate which of those two expressions should be evaluated first.)
To avoid that undefined behaviour, the code should be written to use an explicit intermediate, like this:
int main()
{
int a[10];
int* p = a + 9;
while (p > a) {
int n = (int)(p - a); // Get the value FIRST ...
*p-- = n; // ... only THEN assign it
}
return 0;
}
1 There two exceptions: when that array name is used as the operand of a sizeof operator or of the unary & (address of) operator.
int a[10];
This declares an array on e.g. the stack. a represents the starting address of the array. The declaration tells the compiler that a will hold 10 integers. C assumes you know what you are doing so it is up to you to keep yourself in that range.
int *p = a+9;
p is declared a pointer e.g. like a RL street address. When you add an offset to a an offset is added to the address a. The compiler converts the offset like +5 to bytes +5*sizeof(int) so you don't need to think about that, so your p pointer is now pointing inside the array at offset 9 - which is the last int in the array a since index starts at 0 in C.
while( p > a )
The condition says that do this while the address of what p is pointing to is larger than the address where a is.
*p-- = (int)(p-a);
here the value what p points to is overwritten with a crude(1) subtraction between current p and starting address a before the pointer p is decremented.
(1) Undefined Behavior
Related
In the textbook "Modern C" by Jens Gustedt, I read for pointers that "A pointer must point to a valid object or one position beyond a valid object or be null.". Why is pointing to one position beyond a valid object acceptable? E.g.:
int array[5] = {0};
int* p = array;
p = array + 5 // points to a valid location
p = array + 6 // points to an invalid location
Supporting “one beyond the last” makes working with arrays simpler. For example, if a function is called with a pointer Start to some element, it might want to prepare an end pointer End and use a loop such as:
for (ElementType *p = Start; p < End; ++p)
To do this, End must be a valid pointer.
We might consider instead setting End to be the last element to be processed, rather than one beyond it, and using:
for (ElementType *p = Start; p <= End; ++p)
However, note that, after the final element is processed, p will be incremented to beyond End. Then, in order for p <= End to be a valid expression, p must be a valid pointer. So, we need to be able to do address arithmetic up to one beyond the last element of an array.
Your code comments express a probable misunderstanding. With ...
int array[5] = {0};
int* p = array;
p = array + 5 // points to a valid location
... p does not point to a valid location. It is allowed and well defined to evaluate array + 5, and that produces a value that p can store, but undefined behavior results from any attempt to dereference that pointer value.
Such a value for p is sometimes useful as an exclusive upper bound on the addresses of elements of array, or for indexing array backwards (with strictly negative indexes), but you may not attempt to access a value through that value itself.
In contrast, in this case ...
p = array + 6 // points to an invalid location
... p does not point to anything, at least inasmuch as can be determined by analysis of the code. Attempting to evaluate the expression array + 6 produces undefined behavior, and in particular, the result is not well defined.
I am trying to figure out all the possible ways I could fill in int pointer k considering the following givens:
int i = 40;
int *p = &i;
int *k = ___;
So far I came up with "&i" and "p". However, is it possible to fill in the blank with "*&p" or "&*p"?
My understanding of "*&p" is that it is dereferencing the address of an integer pointer. Which to me means if printed out would output the content of p, which is &i. Or is that not possible when initializing an int pointer? Or is it even possible at all anytime?
I understand "&*p" as the memory address of the integer *p points to. This one I am really unsure about also.
If anyone has any recommendations or suggestions I will greatly appreciate it! Really trying to understand pointers better.
Pointer Basics
A pointer is simply a normal variable that holds the address of something else as its value. In other words, a pointer points to the address where something else can be found. Where you normally think of a variable holding an immediate values, such as int i = 40;, a pointer (e.g. int *p = &i;) would simply hold the address where 40 is stored in memory.
If you need the value stored at the memory address p points to, you dereference p using the unary '*' operator, e.g. int j = *p; will initialize j = 40).
Since p points to the address where 40 is stored, if you change that value at that address (e.g. *p = 41;) 41 is now stored at the address where 40 was before. Since p points to the address of i and you have changed the value at that address, i now equals 41. However j resides in another memory location and its value was set before you changed the value at the address for i, the value for j remains 40.
If you want to create a second pointer (e.g. int *k;) you are just creating another variable that holds an address as its value. If you want k to reference the same address held by p as its value, you simply initialize k the same way you woul intialize any other varaible by assigning its value when it is declared, e.g. int *k = p; (which is the same as assigning k = p; at some point after initialization).
Pointer Arithmetic
Pointer arithmetic works the same way regardless of the type of object pointed to because the type of the pointer controls the pointer arithmetic, e.g. with a char * pointer, pointer+1 points to the next byte (next char), for an int * pointer (normal 4-byte integer), pointer+1 will point to the next int at an offset 4-bytes after pointer. (so a pointer, is just a pointer.... where arithmetic is automatically handled by the type)
Chaining & and * Together
The operators available to take the address of an object and dereference pointers are the unary '&' (address of) operator and the unary '*' (dereference) operator. '&' in taking the address of an object adds one level of indirection. '*' in dereferening a pointer to get the value (or thing) pointed to by the pointer removes one level of indirection. So as #KamilCuk explained in example in his comment it does not matter how many times you apply one after the other, one simply adds and the other removes a level of indirection making all but the final operator superfluous.
(note: when dealing with an array-of-pointers, the postfix [..] operator used to obtain the pointer at an index of the array also acts to derefernce the array of pointers removing one level of indirection)
Your Options
Given your declarations:
int i = 40;
int *p = &i;
int *k = ___;
and the pointer summary above, you have two options, both are equivalent. You can either initialize the pointer k with the address of i directly, e.g.
int *k = &i;
or you can initialize k by assinging the address held by p, e.g.
int *k = p;
Either way, k now holds, as its value, the memory location for i where 40 is currently stored.
I am a little bit unsure what you're trying to do but,
int* p = &i;
now, saying &*p is really just like saying p since this gives you the address.
Just that p is much clearer.
The rule is (quoting C11 standard footnote 102) that for any pointer E
&*E is equivalent to E
You can have as many &*&*&*... in front of any pointer type variable that is on the right side of =.
With the &*&*&* sequence below I denote: zero or more &* sequences. I've put a space after it so it's, like, somehow visible. So: we can assign pointer k to the address of i:
int *k = &*&*&* &i;
and assign k to the same value as p has:
int *k = &*&*&* p;
We can also take the address of pointer p, so do &p, it will have int** - ie. it will be a pointer to a pointer to int. And then we can dereference that address. So *&p. It will be always equal to p.
int *k = &*&*&* *&p;
is it possible to fill in the blank with "*&p" or "&*p"?
Yes, both are correct. The *&p first takes the address of p variables then deferences it, as I said above. The *&variable should be always equal to the value of variable. The second &*p is equal to p.
My understanding of "*&p" is that it is dereferencing the address of an integer pointer. Which to me means if printed out would output the content of p, which is &i. Or is that not possible when initializing an int pointer? Or is it even possible at all anytime?
Yes and yes. It is possible, anytime, with any type. The &* is possible with complete types only.
Side note: It's get really funny with functions. The dereference operator * is ignored in front of a function or a function pointer. This is just a rule in C. See ex. this question. You can have a infinite sequence of * and & in front of a function or a function pointer as long as there are no && sequences in it. It gets ridiculous:
void func(void);
void (*funcptr)(void) = ***&***********&*&*&*&****func;
void (*funcptr2)(void) = ***&***&***&***&***&*******&******&**funcptr;
Both funcptr and funcptr2 are assigned the same value and both point to function func.
gcc 4.4.4
What am I doing wrong?
char x[10];
char y[] = "Hello";
while(y != NULL)
*x++ = *y++;
Many thanks for any advice.
x++ is the short form of x = x + 1. However, x here is an array and you cannot modify the address of an array. So is the case with your variable y too.
Instead of trying to increment arrays, you can declare an integer i and increment that, then access the i'th index of an arrays.
char x[10], y[5] = "Hello";
int i = 0;
while (y[i] != 0)
{
x[i] = *y[i];
i++;
}
x[i] = 0;
Most likely you fell victim to a popular misconception that "array is a pointer", i.e. when you define an array what you actually get is an ordinary pointer that points to some block of memory allocated somewhere. In your code you are making an attempt to increment that pointer.
The code does not "work" because in reality arrays are not pointers. Arrays are arrays. Arrays cannot be incremented. There's no such operation as "increment an array" in C language. In fact, arrays by themselves in C are non-modifiable lvalues. There are no operations in C that can modify the array itself (only individual elements can be modifiable).
If you want to traverse your arrays using the "sliding pointer" technique (which is what you are actually trying to do), you need to create the pointers explicitly and make them point to the starting elements of your arrays
char *px = x;
char *py = y;
After that you can increment these pointers as much as you want.
Arrays in C are indeed pointers, but constant pointers, which means after declaration their values can't be changed.
int arr[] = {1, 2, 3};
// arr is declared as const pointer.
(arr + 1) is possible but arr++ is not possible because arr can not store another address since it is constant.
char x[10];
char y[] = "Hello";
char *p_x = &x[0];
char *p_y = &y[0];
while(*p_y != '\0') *p_x++ = *p_y++;
Since you can't modify the array addresses (done by x++ and y++ in your code) and you can modify the pointer address, I copied over the address of the array into separate pointers and then incremented them.
If you want, I'm sure you can reduce the notation, but I hope you got the point.
x and y are arrays, not pointers.
They decay into pointers in most expression contexts, such as your increment expression, but they decay into rvalues, not lvalues and you can only apply increment operators to lvalues.
At most times, array just like a pointer.
Just remember you can't modify array!
And y++ is y = y + 1.
char y[] = "Hello";
So you do modify array when you y++!!
It will produce error: lvalue required as increment operand.
Since you've defined both x and y as arrays, you can't modify them. One possibility would be to use pointers instead:
char x[10];
char *xx = x;
char *y = "Hello";
while (*y != '\0')
*xx++ = *y++;
Note that I've also fixed your termination condition -- a pointer won't become NULL just because it's reached the end of a string.
We can not modify a array name, but What about argv++ in f(int argv[])?
Quotes from K&R in p99 “an array name is not a varible; construction like a = pa and a++ are illegal" which says the name of an array is a synonym for the location of the initial element.”
But why in function parameter func(char *argv[]), we can do argv++ despite of argv is a array name.
And in int *a[10], we can't do the a++ like argv++.
The name of array is a synonym for the location of the initial element. ---K&R
arrayname++ is illegal.
In function parameter, such as char *argv[], it is the same as char **argv. type *arrayname_para[] in parameter is a another synonym for type **arrayname_para.
Array is a static continuous block of allocated memory. Array names are immutable references to the first block memory. An attempt to increment the address (referenced by name of array) would result in loss (better to say deference) of other memory locations.
Say we have array
int p[]={10,20,30}
Here p (by design) refers to index 0. Say somewhere we increment p as :
p++
Assuming increment to be allowed would result in p to point to index 1. Now thinking what p[1]=? p[1] would then translate to dereferencing the value one place to the right of the current p location Or location p[2] for original array.
Do this repeatedly and soon tracking the array indices would become very troublesome.
So to avoid such mishaps array names(lvalues) addresses are immutable.
Another concept is word addressing and byte addressing:-
Character Arrays(string) in C are byte addressable instead of being word addressable. So if we have an array
int a[]={10,20,30}
printf("%d",*(a+1)) //Ouput:20 (int is word addressable)
printf("%d",*(++a)) // Error: Array references are immutable
int* cpya=a;
printf("%d",*(++cpya)) /* Output:20 (cpy is not array reference but a copy. Hence is Mutable) */
char b[]="Hello"
printf("%c",*(++b)) // Error : Array references are immutable
printf("%c",*(b+1)) /* undefined_behavior as character Array(strings) are byte addressable and not word addressable */
printf("%c",*(b+sizeof(char)*1)) // Output :e (It's byte addressable).
To understand more I suggest reading the official docs for B Programming Lang at
[B Reference Manual- Data Objects][1]
Arrays are constant pointers. We can't change them.
int q;
int *const p = &q;
p = NULL; // this is not allowed.
Why if I subtract from a pointer another pointer (integer pointers) without typecasting the result will be 1 and not 4 bytes (like it is when I typecast to int both pointers). Example :
int a , b , *p , *q;
p = &b;
q = p + 1; // q = &a;
printf("%d",q - p); // The result will be one .
printf("%d",(int)q - (int)p); // The result will be 4(bytes). The memory address of b minus The memory address of a.
According to the C Standard (6.5.6 Additive operators)
9 When two pointers are subtracted, both shall point to elements of
the same array object, or one past the last element of the array
object; the result is the difference of the subscripts of the two
array elements....
If the two pointers pointed to elements of the same array then as it is said in the quote from the Standard
the result is the difference of the subscripts of the two array
elements
That is you would get the number of elements of the array between these two pointers. It is the result of the so-called pointer arithmetic.
If you subtract addresses stored in the pointers as integer values then you will get the number that corresponds to the arithmetic subtract operation.
Why If If I subtract from a pointer another pointer (integer pointers) without typecasting the result will be 1 and not 4 bytes
That's the whole point of the data type that a pointer pointing to. It's probably easier to look at an array context like below. The point is regardless of the underlying data type (here long or double), you can use pointer arithmetic to navigate the array without caring about how exactly the size of its element is. In other words, (pointer + 1) means point the next element regardless of the type.
long l[] = { 10e4, 10e5, 10e6 };
long *pl = l + 1; // point to the 2nd element in the "long" array.
double d[] = { 10e7, 10e8, 10e9 };
double *pd = d + 2; // point to the 3rd element in the "double" array.
Also note in your code:
int a , b , *p , *q;
p = &b;
q = p + 1; // q = &a; <--- NO this is wrong.
The fact that a and b are declared next to each other does not mean that a and b are allocated next to each other in the memory. So q is pointing to the memory address next to that of b - but what is in that address is undefined.
Because the ptrdiff_t from pointer subtraction is calculated relative to the size of the elements pointed to. It's a lot more convenient that way; for one, it tells you how many times you can increment one pointer before you reach the other pointer.
where you have
int a , b , *p , *q;
The compiler can put a and b anywhere. They don't have to even be near each other. Also, when you subtract two int pointers, the result is sized in terms of int, not bytes.
C is not assembly language. So pointers are not just plain integers -- pointers are special guys that know how to point to other things.
It's fundamental to the way pointers and pointer arithmetic work in C that they can point to successive elements of an array. So if we write
int a[10];
int *p1 = &a[4];
int *p2 = &a[3];
then p1 - p2 will be 1. The result is 1 because the "distance" between a[3] and a[4] is one int. The result is 1 because 4 - 3 = 1. The result is not 4 (as you might have thought it would be if you know that ints are 32 bits on your machine) because we're not interesting in doing assembly language programming or working with machine addresses; we're doing higher-level language programming with an array, and we're thinking in those terms.
(But, yes, at the machine address level, the way p2 - p1 is computed is typically as (<raw address value in p2> - <raw address value in p1>) / sizeof(int).)
int s[4][2] = {
{1234, 56},
{1212, 33},
{1434, 80},
{1312, 78}
};
int (*p)[1];
p = s[0];
printf("%d\n", *(*(p + 0))); // 1234
printf("%d\n", *(s[0] + 0)); // 1234
printf("%u\n", p); // 1256433(address of s[0][0])
printf("%u\n", *p); // 1256433(address of s[0][0])
Can anyone explain why doing *(*(p + 0)) prints 1234, and doing *(s[0] + 0) also prints 1234, when p = s[0] and also why does p and *p gives the same result?
Thanking you in anticipation.
This is the way arrays work in C -- arrays are not first class types, in that you can't do anything with them other than declaring them and getting their size. In any other context, when you use an expression with type array (of anything) it is silently converted into a pointer to the array's first element. This is often referred to as an array "decaying" into a pointer.
So lets look at your statements one by one:
p = s[0];
Here, s has array type (it's an int[4][2] -- a 2D int array), so its silently converted into a pointer to its first element (an int (*)[2], pointing at the word containing 1234). You then index this with [0] which adds 0 * sizeof(int [2]) bytes to the pointer, and then dereferences it, giving you an int [2] (1D array of 2 ints). Since this is an array, its silently converted into a pointer to its first element (an int * pointing at 1234). Note that this is the same pointer as before the index, just the pointed at type is different.
You then assign this int * to p, which was declared as int (*)[1]. Since C allows assigning any pointer to any other pointer (even if the pointed at types are different), this works, but any reasonable compiler will give you a type mismatch warning.
p now points at the word containing 1234 (the same place the pointer you get from s points at)
printf("%d\n", *(*(p+0)));
This first adds 0*sizeof(int[1]) to p and dereferences it, giving an array (int[1]) that immediately decays to a pointer to its first element (an int * still pointing at the same place). THAT pointer is then dereferenced, giving the int value 1234 which is printed.
printf("%d\n", *(s[0]+0));
We have s[0] again which via the multiple decay and dereference process noted in the description of the first line, becomes an int * pointing at 1234. We add 0*sizeof(int) to it, and then dereference, giving the integer 1234.
printf("%u\n", p);
p is a pointer, so the address of the pointer is simply printed.
printf("%u\n",*p)
p is dereferenced, giving an int [1] (1D integer array) which decays into a pointer to its first element. That pointer is then printed.
s[0]points to a location in memory. That memory location happens to be the starting point of int s[4][2]. When you make the assignment p = s[0], p and p+0 also point to s[0]. So when you print any one of these with a "%d" specifier, you will get the value stored at that location which happens to be `1234'. If you would like to verify the address is the same for all of these, use a format specifier "%p" instead of "%d".
EDIT to address OP comment question...
Here is an example using your own int **s:
First, C uses pointers. Only pointers. No arrays. The [] notation gives the appearance of arrays, but any variable that is created using the [] notation (eg. int s[4][2]) is resolved into a simple pointer (eg. int **s). Also, a pointer to a pointer is still just a pointer.
int a[8]={0}; (or int *a then malloced)
will look the same in memory as will:
int a[2][4]; ( or in **a=0; then malloced)
The statment:
s[row][col] = 1;
creates the same object code as
*(*(s + row) + col) = 1;
It is also true that
s[row] == *(s + row)
Since s[row] resolves to a pointer, then so does *(s + row)
It follows that s[0] == *(s + 0) == *s
If these three are equal, whatever value is held at this address will be displayed when printing it.
It follows that in your code: given that you have assigned p = s[0]; and s[0] == *s
*(*(p + 0)) == *(s[0] + 0) == *s[0] == **s
printf("%d\n", >>>fill in any one<<<); //will result in 1234
Note, in the following printf statements, your comment indicates addresses were printed. But because you used the unsigned int format specifier "%u",
Consider p == s[0]; which is a pointer to the first location of s. Note that either s[0][0] or **s would give you the value held at the first location of s, but s[0] is the _address_ of the first memory location of s. Therefore, since p is a pointer, pointing to the address at s[0], the following will give you the address of p, or s[0] (both same):
printf("%p\n", *p); // 1256433(address of s[0][0])
As for *p, p was created as int (*p)[1]; and pointer array of 1 element. an array is resolved into a pointer, so again, in the following you will get the address pointing to s[0]:
printf("%u\n", **p);
In summary, both p and *p are pointers. Both will result in giving address when printed.
Edit 2 Answer to your question: So my question is what is the difference between a simple pointer and a pointer to an array?
Look toward the bottom of this tutorial download a pdf. It may explain it better...
But in short, C Does not implement arrays in the same way other languages do. In C, an array of any data type always resolves into a pointer. int a[10]; is just really int *a;, with memory set aside for space to hold 10 integers consecutively. In memory it would look like:
a[0] a[9]
|0|0|0|0|0|0|0|0|0|0| (if all were initialized to zero)
Likewise you would be tempted to think of float b[2][2][2]; as a 3 dimensional array: 2x2x2, it is not. It is really a place in memory, starting at b[0] that has room for 8 floating point numbers. Look at the illustrations HERE.