Pointer Arithmetic in C using Array Variables - c

I am in the process of learning C, and have begun exploring the world of pointers and pointer arithmetic. For example, in the following code snippet:
int nums[] = {1, 2, 3};
nums is an Array variable and acts like a pointer that points to the first memory location of the array. I wrote the following sample code and am trying to understand why I am getting the results that I am getting:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int nums[] = {1, 2, 3};
if(nums == &nums)
puts("nums == &nums");
else
puts("nums != &nums");
if((nums + 1) == (&nums + 1))
puts("(nums + 1) == (&nums + 1)");
else
puts("(nums + 1) != (&nums + 1)");
printf("nums: %i\n", nums);
printf("&nums: %i\n", &nums);
printf("nums + 1: %i\n", nums + 1);
printf("&nums + 1: %i\n", &nums + 1);
return 0;
}
I am getting that nums == &nums is true as expected; however, when I apply pointer arithmetic and add 1 to nums this result does not equal &nums + 1. In other words (nums + 1) != (&nums + 1) even though nums == &nums.
This is the output of the program that I get:
nums == &nums
(nums + 1) != (&nums + 1)
nums: 2345600
&nums: 2345600
nums + 1: 2345604
&nums + 1: 2345612
It appears that nums and nums + 1 are off set by 4 bytes; however, &nums and &nums + 1 are offset by 12. Why is it that this offset is by 12 bytes and not by 4?

The confusion is related to how in C, arrays implicitly decay into pointers in certain contexts.
The easier one to explain, nums + 1 effectively means &nums[0] + 1. nums[0] is type int, which is 4 bytes per element. Thus &nums[0] + 1 is 4 bytes after &nums.
As for &nums + 1, &nums is of type int(*)[3], which is 12 bytes per element. Thus &nums + 1 is 12 bytes after &nums.

Both expressions, (int*) nums and &nums have pointer types, but the types pointed to are different. You only can test them for equality in C, not C++.
The type of nums is int[3], that is, 'array of 3 objects of type int' and the type of (int*) nums is int*, that is, 'a pointer to int' . Adding 1 to (int*) nums means obtaining a pointer to an object of type int that follows nums[0]. In terms of addresses that means adding 1 * sizeof (int).
The type of &nums is int(*)[3], that is, 'pointer to an array of 3 objects of type int'. Adding 1 to &nums means obtaining a pointer to an object of type int[3] that follows nums. In terms of addresses that means adding 1 * sizeof (int[3]), that is, 3 * sizeof (int).

Related

C getting the size of an array

the code:
int arr[5] = {10, 20, 30, 40, 50};
printf("%lu %lu\n", *(&arr + 1), arr); // 6422036 6422016
printf("%lu\n", *(&arr + 1) - arr); // 5
Why the second printf prints 5 instead of 20?
There are two points in your interesting question :
How does operation on pointers work ?
What is the difference between arr and &arr ?
1 : How does operation on pointers work ?
Try the following code :
#include <stdio.h>
#include <inttypes.h>
int main(int argc, char **argv) {
int simpleInt= 10 ;
printf("Output 1 : %p %p \n", &simpleInt+1, &simpleInt); // 61FE20 and 61FE1C
printf("Output 2 : %lld \n", &simpleInt+1 - &simpleInt); // 1
printf("Output 3 : %lld\n", (uint64_t)(&simpleInt+1) - (uint64_t)(&simpleInt)); // 4
}
Output 1 : Clearly, the difference between the two printed pointer values is 4
Output 2 : You are performing operation on int *. 1 is added to an operand of type int * and after an operand of type int * is substracted. From an " int * point of view" (if I could simplify it like that), only one is added. So, the output is 1.
Ouput 3 : Each operands of the substraction are casted to a long long unsigned int. So the substraction is done on integers and not on pointers. The ouput is 4, as expected.
2. What is the difference between arr and &arr ?
Let's have a look to the following code
int arr[5] = {10, 20, 30, 40, 50};
printf("Output 1 : %p %p %p \n", arr, &arr, *(&arr) ); //Seems to be the same thing but NOT. int*, int*[5], int*, respectively
// printf("%lld\n", arr - &arr ); // compilation error : int * and int(*)[5]
printf("Output 2 : %lld\n", arr - *(&arr) );
//printf("%lld\n", &arr - *(&arr) ); // compilation error : int(*)[5] and int *
printf("Output 3 : %p %p %p \n", (arr + 1), (&arr + 1), *(&arr + 1) ); // +4, +20, +20
printf("Output 4 : %lld\n", *(&arr + 1) - arr);
printf("Output 5 : %lld\n", (uint64_t)(*(&arr + 1)) - (uint64_t)(arr));
Ouput 1 : The value are the same but not the type of arguments. And this point is very important. The name of an array is a pointer to its first element. In your case, your array is an array of int, so arr is a pointer to int : int*. &arr is the address of your variable arr which is an array of 5 integers. So the type of &arr is int(*)[5]. And the type of *(&arr) is int*
Output 2 : Some lines give compilation errors because of the explanation above. And you could do operations on the same pointer type : arr and *(&arr)
Output 3 : Depending which kind of pointer is incremented, +4 or +20 is obtained. +20 because 1 is added to an operand of type int(*)[5] : 5 * 4 (sizeof int = 4)
Output 4 & 5 : As, in the first point (operation on pointer), your are performing a substraction with int* as operand
Why the second printf prints 5 instead of 20?
Code is living on the edge.
&arr is the address of the array, so + 1 is the address of the next array: 5 int later. So far, this is good.
*(&arr + 1) de-references that address. So we get that next array. Not so good #RobertS supports Monica Cellio. An array passed to a ... function like printf() is converted to the address of the first element, an int *.
*(&arr + 1) - arr subtracts two pointers of the same type int * that are 5 int apart leading to difference of 5 of type intptr_t. Recall that pointer subtraction is the difference of the number of the referenced types (int in this case), not the difference of the pointer values. 5 not 20.
Code attempts to print a intptr_t as an unsigned long with "%lu", which might work, might not (UB). Not so good. Better to use "%td".
printf("%td\n", *(&arr + 1) - arr);

difficulty in multidimensional pointers in c?

I have a C program that uses pointers but I am not able to understand the output. Why is the first output 1 and the other is 210. They are both pointers to a 3 dimensional array.
I'm not able to find a solution
int main() {
char arr[5][7][6];
char (*p)[5][7][6] = &arr;
printf("%d\n", (&arr + 1) - &arr);
printf("%d\n", (char *)(&arr + 1) - (char *)&arr);
printf("%d\n", (unsigned)(arr + 1) - (unsigned)arr);
printf("%d\n", (unsigned)(p + 1) - (unsigned)p);
return 0;
}
the first output is 1 and the last is 210
C does pointer arithmetic in units of the pointed-to type.
In (&arr + 1) - &arr, &arr is the address of a char [5][7][6] (an array of 5 arrays of 7 arrays of 6 char). Then &arr +1 is the address of one char [5][7][6] beyond &arr and (&arr + 1) - &arr is distance from &arr to &arr + 1 measured in units of char [5][7][6], so the distance is one unit.
In (char *)(&arr + 1) - (char *)&arr), the two addresses are converted to char *, so the arithmetic is done in units of char. So the result is the distance from &arr to &arr + 1 measured in units of char. Since the distance from &arr to &arr + 1 is one char [5][7][6], it is 5•7•6 char, which is 210 char, so the result is 210.
Incidentals
Do not use %d to print the results of subtracting pointers. When two pointers are subtracted, the type of the result is ptrdiff_t, and it may be printed with %td, as in printf("%td\n", (&arr + 1) - &arr));.
To convert pointers to integers, it is preferable to use uintptr_t, defined in <stdint.h>, rather than unsigned.
To print unsigned values, use %u, not %d.
To print uintptr_t values, include <inttypes.h> and use "%" PRIuPTR, as in printf("%" PRIuPTR "\n", (uintptr_t) (p + 1) - (uintptr_t) p);.
First, it's not safe to use %d to print pointer differences, which have type ptrdiff_t (which is a signed version of size_t).
Ignoring that, you have the following declarations:
char arr[5][7][6];
char (*p)[5][7][6] = &arr;
When subtracting two pointers, result is divided by the size of the target (i.e., the inverse of what happens when you add an integer to a pointer, in which case the integer is scaled by the size).
For the first example:
(&arr + 1) - &arr
Here both &arr and &arr + 1 have type char (*)[5][7][6], so the size of what they point to is sizeof(char [5][7][6]). The pointer addition multiplies 1 by this size, and the pointer subtraction divides the difference by this size, canceling it out. So the result is 1, regardless of the target size.
For the second example:
(char *)(&arr + 1) - (char *)&arr
Here the pointer addition again multiplies 1 by sizeof(char [5][7][6]), which is sizeof(char)*5*7*6, i.e. 1*5*7*6 which is 210. But the subtraction divides by sizeof(char) which is 1. So the result is 210.
For the third example:
(unsigned)(arr + 1) - (unsigned)arr
The effect of the unsigned casts is similar to the effect of the char * casts in the previous example. However, in this one two pointers are arr and arr + 1. In this context, the array types "decay" to the pointer types char (*)[7][6]. The size of the pointer target is therefore sizeof(char)*7*6 i.e. 1*7*6 which is 42. So the result is 42.
Finally, for the last example:
(unsigned)(p + 1) - (unsigned)p)
Both p and p + 1 have type char (*)[5][7][6], so the target size is 210. The unsigned casts again result in straight address subtraction, with no division applied to the result. So the result is 210.
char (*p)[5][7][6] = &arr;
Here p is an array of pointers to chars, not a pointer to an array of chars.
printf("%d\n", (&arr + 1) - &arr);
& sign returns address. you are doing math on addresses not values! and anything plus 1 and minus itself will result in 1
(unsigned)p
this casting behavior is not guaranteed and is not safe to do. and you are not dereferencing your pointer anywhere.
You should read more about pointers, types and casting and operator priority before doing this.
I recommend this two videos by Brian Will:
the C language (part 2 of 5)
the C language (part 5 of 5)

How to express relationship between two/multi dimensional array & the pointer expressions

#include<stdio.h>
void main()
{
int a[2][2][2]={1,2,3,4,5,6,7,8};
printf("%d\t%d",*(*(*(a+1)+1)+1),a[1][1][1]);
}
The output of the code is 8 8 but the expression *(*(*(a+i)+j)+k); & a[i][j][k]; are equal I know how to evolve the expression a[i][j][k]; but I don't have an idea how to evolve the expression *(*(*(a+i)+j)+k); with proper priority operations of * operator & () operator. Please explain it with taking some values of i,j,k.
In pointer arithmetic,
array[i] = *(array + i).
array[i][j] = *(*(array + i) + j).
array[i][j][k] = *(*(*(array + i) + j) + k)
Initially, a is pointing towards 1. When you do a+1 it moves to the 5, and when you dereference (*) you cause the next +1 to make it move only 2 positions, to the 7. The second * causes the third +1 to move it to the last element, 8, and the final * actually gets the value from that address (which is 8).

In C, how does arithmetic between a pointer and an array work?

What should be the value of y and why?
int x[] = { 1, 4, 8, 5, 1, 4 };
int *ptr, y;
ptr = x + 4;
y = ptr - x;
I think y should be 4*sizeof(int), but it is giving 4. Why ?
I think y should be 4*sizeof(int)
Good thinking, and guess what? It is giving 4*sizeof(int), but you're not looking at it right. ;)
When you're playing with pointers, you're looking at addresses, so let's check out some addresses
int x[] = { 1, 4, 8, 5, 1, 4 };
//Just for fun, what is the address of each element in the array?
printf("%#x, %#x, %#x, %#x, %#x, %#x\n", x+0, x+1, x+2, x+3, x+4, x+5);
ptr = x + 4;
printf("%#x - %#x\n", ptr, x); // Give us the address of ptr in hex
// and give us the address of x
y = ptr - x;
printf("%d\n", y);
Output:
x[0] x[1] x[2] x[3] x[4] x[5]
0xbf871d20, 0xbf871d24, 0xbf871d28, 0xbf871d2c, 0xbf871d30, 0xbf871d34
ptr x
0xbf871d30 - 0xbf871d20
4
So ptr is x+4 (which is really x + 4*sizeof(int) or x+16 in your case). And we're going to subtract from that x or the base address, so the actual math is 0x30 - 0x20 = 0x10 or in dec 16.
The reason you're seeing 4 on the output is because the compiler knows you're doing operations on int * so it's dividing that 16 by sizeof(int) for you. Nice hm?
If you want to see the actual value you need to do something like this:
int one, two;
...
one = (int)ptr; //get the addresses, ignore the "type" of the pointer
two = (int)x;
y = one - two;
Now y will give you 0x10(hex) or 16(dec)
It should be the number of int's between the address that points to the start of x and the address of x's 4-th element => 4.
From c99 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.
To find out more, try searching for pointer arithmetic.
Just apply some simple algebra
if
ptr = x + 4
and
y = ptr - x
therefore
y = (x + 4) - x
hence y = 4 + x - x
thus y = 4 + 0
y = 4
Edit: Addressing the comment
This is C, a ptr is just value of whatever size bits. Adding a number to it (except in the case of overflow) is just some integral number + another integral number (cast to the appropriate size), and thus removing the original number leaves a remainder. Since we only added 4 (smaller than an int) this means that there is no issue implicitly casting it to the y int.
if the operands of the binary '-'
are both pointers of same type it is evaluated as
(p-q)/sizeof(type of p or q)
in case the second operand is integer
then
p - sizeof(p)*q

Adding two numbers without using +

I have this code which does the trick:
#include <stdio.h>
int main()
{
int a = 30000, b = 20,sum;
char *p;
p=(char *)a;
sum = (int)&p[b]; // adding a & b
printf("%d",sum);
return 0;
}
Can someone please explain what is happening in the code?
p = (char*)a;
sum = (int)&p[b]; // adding a & b
&p[b] is basically sugar for:
&*(p + b)
The * and & operators are inverse operations here and cancel, leaving simply p + b. The casts just circumvent C's type checking. The fact that a char * pointer is used is signficant, however; C scales pointer arithmetic, and since sizeof(char) == 1 by definition, the scaling factor is 1.
I think it is worth adding to the other answers a quick explanation of pointers, arrays and memory locations in c.
Firstly arrays in c are just a block of memory big enough to hold the number of items in the array (see http://www.cplusplus.com/doc/tutorial/arrays/)
so if we said
int[5] example;
example[0] = 1;
example[1] = 2;
example[2] = 3;
example[3] = 4;
example[4] = 5;
Assuming int is 32 bits we would have a block of memory 5*32bits = 160bits long.
As C is a low level language it tries to be as efficient as possible, therefor stores the least amount of information about arrays as possible, in this case the least amount possible is the memory address of the first element. So the type of example could be expressed as
int *example;
Or example points to an int. To get the items in the array you then add the correct number to the address stored in example and read the number at that memory address.
If we assumed memory look like
Memory Address = Value (ints take up 4 bytes of space)
1000 = 1 <-- example
1004 = 2
1008 = 3
1012 = 4
1016 = 5
So
int i = example[3]; //The 4th element
could be expressed as
int i = *(example + 3 * sizeof(int));
int i = *(example + 3 * 4);
int i = *(1000 + 12);
int i = *(1012); // Fetch the value at memory location 1012
int i = 4;
The sizeof(int) is 4 (int is 32 bits, or 4 * 8 bit bytes). If you where trying to do addition you would want a char which is 8 bits or 1 * 8 bit bytes.
So back to you code
char* p; // declare p as a pointer to a char/
p = (char *)a; // point p at memory location 3000
// p[b] would be the 21st element of the "array" p =>
// p[20] =>
// p + 20 * sizeof(char) =>
// p + 20 * 1 =>
// p + 20 =>
// 3000 + 20 =>
// 3020
// the & operator in c gets the address of the variable so
sum = (int) &p[b];
// &p[b] => find the address pointed to by p[b] => 3020
// (int) casts this pointer to a int.
So sum is assigned the address of the 21st element of the array.
Long winded explanation.
p[b] returns the b-th element of the array p, which is equivalent to *(p + b). &p[b] equals to p + b*sizeof(char) that is converted back to int.
If the question was "adding two numbers without the + operator", here is one:
#include <stdio.h>
int main()
{
int a=5, b=7;
int a1=a, b1=b;
int res;
res = (++a1 * ++b1) - (a * b) -1;
printf("a1=%d b1=%d res=%d\n", a1, b1, res );
return 0;
}

Resources