Pointer operation yields unexpected result - c

I was expecting the code below to print 4 (since a float is 4 bytes), but it prints 1. Would someone explain why this happens?
#include <stdio.h>
int main()
{
float a[4]={0.0,0.1,0.2,0.3};
printf("%d", &a[1]-&a[0]);
return 0;
}

First of all, change
printf("%d", &a[1]-&a[0]);
to
printf("%td", &a[1]-&a[0]);
as the result type of two subtraction yields a type ptrdiff_t and %td is the conversion specifier for that type.
That said, quoting C11, chapter §6.5.6, subtraction operator (emphasis mine)
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. [....] In
other words, if the expressions P and Q point to, respectively, the i-th and j-th elements of
an array object, the expression (P)-(Q) has the value i−j provided the value fits in an object of type ptrdiff_t. [....]
In your case, P is &a[1] and Q is &a[0], so i is 1 and j is 0. Hence the result of the subtraction operation is i-j, i.e., 1-0, 1.

You are correct that the two pointers are 4 bytes apart. And if you were subtracting two integers you'd get 4. But &a[1] and &a[0] are of type float *. Pointer arithmetic in C takes into account the size of the thing being pointed to, so &a[1]-&a[0] is 1.
This is the basic means by which array indexing works. You can take advantage of this to iterate through an array without needing a separate index and instead terminating on a boundary such as NaN.
#include <stdio.h>
#include <math.h>
int main()
{
float a[] = { 0.0,0.1,0.2,0.3,NAN };
float *iter = a;
while(!isnan(*iter)) {
printf("%f\n", *iter);
iter++;
}
}
If you instead cast the values to unsigned int you will indeed get 4.
printf("%u\n", (unsigned int)&a[1]-(unsigned int)&a[0]);

Related

can't I use double in array?

what's problem here?
it shows a bug, help me I'm a beginner.
can I use double in array?
#include <stdio.h>
int main()
{
double a;
scanf("%lf",&a);
double s[a];
double b,c=0, d;
for(b=0;b<a;b++){
scanf("%lf",&s[b]);
}
for(b=0;b<a;b++){
c = c + s[b];
d=b+1;
printf("%lf\n",c/d);
}
return 0;
}
In case it isn't clear, your array cannot be of double length. It's undefined behavior.
This is because a double is not an integer, but a rational number that could be an integer. A simple way to understand this issue is to take some floating point value, say 3.5.
What is an array of length 3.5 Is it 3 and a half slots of some size in contiguous memory? Is is enough slots for 3? 4? 3.5 slots would likely be useless and unintended, and if it's not a fractional slot, it might be unclear and likely unintended, hence undefined behaviour.
While the other people have proposed solutions creating an integral type, you cannot create an array of double length. You can create an array of doubles, ie
double arr[5];
But you can't create an array of double length like
int arr[3.3];
Use this :
int a;
scanf("%d",&a);
Rest of your code is just fine .
While variable length arrays are supported in modern C, the size of an array must be positive and integral.
What you could do instead is round to the nearest size_t:
size_t ASIZE = ceil(fabs(a));
double s[ASIZE];
Include <math.h> to access ceil and fabs.
You cannot use floating-point types (float or double) to specify an array size or array index:
6.7.6.2 Array declarators
Constraints
1 In addition to optional type qualifiers and the keyword static, the [ and ] may delimit
an expression or *. If they delimit an expression (which specifies the size of an array), the
expression shall have an integer type. If the expression is a constant expression, it shall
have a value greater than zero. The element type shall not be an incomplete or function
type. The optional type qualifiers and the keyword static shall appear only in a
declaration of a function parameter with an array type, and then only in the outermost
array type derivation.
C 2011 Online Draft
6.5.2.1 Array subscripting
Constraints
1 One of the expressions shall have type ‘‘pointer to complete object type’’, the other
expression shall have integer type, and the result has type ‘‘type’’.
ibid.
So a and b must be of integral type - I typically use size_t for array size and index variables:
size_t a;
printf( "Gimme the array size: " );
scanf( "%zu", &a );
double s[a];
for ( size_t b = 0; b < a; b++ )
scanf( "%lf", &s[b] );

how is distance between two addresses computed?

I would like to compute the number of bytes between two addresses.
uint32_t length = &b - &a;
When a and b are uint32_t, length is 1.
uint32_t a, b;
uint32_t length = &b - &a; // length is one
When a and b are uint8_t, length is 4.
uint8_t a, b;
uint32_t length = &b - &a; // length is four
The computation, therefore, is the number of uint32_t or uint8_t between a and b, not the mathematical difference between the addresses as I falsely expected.
My question: What part of the C language covers computation of addresses? Can someone reference a location in the spec that discusses the topic?
Pointer subtraction is covered in section 6.5.6 of the C standard:
3 For subtraction, one of the following shall hold:
both operands have arithmetic type;
both operands are pointers to qualified or unqualified versions of compatible complete object types; or
the left operand is a pointer to a complete object type and the right operand has integer type.
...
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. The size of the result is implementation-defined, and
its type (a signed integer type) is ptrdiff_t defined in the
header. If the result is not representable in an object of
that type, the behavior is undefined. In other words, if the
expressions P and Q point to, respectively, the i-th and j-th elements
of an array object, the expression (P)-(Q) has the value i−j provided
the value fits in an object of type ptrdiff_t. Moreover, if the
expression P points either to an element of an array object or one
past the last element of an array object, and the expression Q points
to the last element of the same array object, the expression
((Q)+1)-(P) has the same value as ((Q)-(P))+1 and as -((P)-((Q)+1)),
and has the value zero if the expression P points one past the last
element of the array object, even though the expression (Q)+1 does not
point to an element of the array object.
So the difference is the number of elements between the two, not the number of bytes.
Note that this only allows subtracting pointers between two elements of the same array. So this is legal:
uint32_t a[5];
uint32_t len = &a[1] - &a[0];
But this is not:
uint32_t a, b
uint32_t len = &b - &a;
in the standard compliant C pointer arithmentics is not allowed if the pointers have different types or not point to the same memory block (ie table or allocated other way). Otherwise it is the UB
But if the variables are located in the same continuous address space - for example in the ARM uC result of this arithmetics will be defined if pointes have the same type or you cast them to the same type.
this is nor C standard compliant code
#include <stdio.h>
#include <stdint.h>
uint64_t c;
uint64_t d;
uint16_t e;
uint8_t f;
int main(void)
{ uint32_t a,b;
printf("%lld\n", (long long)((uint8_t *)&b - (uint8_t *)&a));
printf("%lld\n", (long long)((uint8_t *)&c - (uint8_t *)&a));
printf("%lld\n", (long long)((uint8_t *)&d - (uint8_t *)&c));
printf("%lld\n", (long long)((uint8_t *)&e - (uint8_t *)&d));
printf("%lld\n", (long long)((uint8_t *)&f - (uint8_t *)&c));
}
What will be printed is 100% up to implementation. Some of the results might have sense another not.
This kind of arithmetic is used in the embedded development for example by defining the symbols in the linker script (for example start of bss and end of bss) and then those symbols (their addresses actually) are used to do something like zeroing the bss or initializing the data segment
You can try it on Linux machine:
https://ideone.com/dm0R5M
I would like to compute the number of bytes between two addresses.
If the addresses are in the same array, code can subtract pointers to get a count of the number of elements in the difference. Then multiply by the size of the type to report the number of "bytes".
ptrdiff_t diff = &a[some_index] - &a[some__other_index];
diff *= sizeof a[0];
printf("Diff %td\n", diff);
If the address of 2 objects are not known to be in the same array, code can carefully subtract, yet depending on the memory model, the difference may or may not represent the "byte" difference. IAC, the below avoids undefined behavior.
#include <inttypes.h>
#include <stdio.h>
void *va = &a;
void *vb = &b;
// optional types
uintptr_t ua = (uintptr_t)va;
uintptr_t ub = (uintptr_t)vb;
uintptr_t diff = ua > ub ? ua - ub : ub - ua;
printf("Maybe byte difference of %" PRIuPTR "\n", diff);

Subtle Concept of pointers and array

I have a very strange example of pointers, which requires your kind help. In general, pointers are used to point to a variable (see first example below), but when it points to an array. I don't understand why it no longer requires deferencing to obtain the array (see second example below)
printf("TEST: %i\n", x[i]);// I expect this should be *x[i]
This is indeed very strange. Is it just a C convention or how do you explain this?
EDIT::Since many have provided a clear answer, I want to include another small follow up question, as all of you mentioned x[i] = *(x+i), what about x[i][j] for a 2 dimensional array? what is it equivalent to ? Does it require dereferencing?
With a normal variable
int j = 4;
int* pointerj=&j;//pointerj holds address of j or points to j
printf("%d",*pointerj); returns the value that pointer j points to
With an array :
#include <stdio.h>
#include <stdlib.h>
int *function(unsigned int tags) {
int i;
int *var;
var = (int*)malloc(sizeof(int)*tags); // malloc is casted to int* type , allocated dynamical memory, it returns a pointer!
//so now var holds the address to a dynamical array.
for (i = 0; i < tags; i++) {
var[i] = i;
}
return var;
}
int main() {
int *x;
int i;
x = function(10);
for (i = 0; i < 10; i++) {
printf("TEST: %i\n", x[i]);// I expect this should be *x[i]
}
free(x); x = NULL;
return 0;
}
don't understand why it no longer requires dereferencing to obtain the array (element)
Well, you are dereferencing, it's just not using the dereference operator *.
The array subscripting operator [] is serving as job of dereferencing here. quoting C11, chapter §6.5.2.1
A postfix expression followed by an expression in square brackets [] is a subscripted
designation of an element of an array object. The definition of the subscript operator []
is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that
apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the
initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th
element of E1 (counting from zero).
It's a syntactic sugar. The expressions x[i] and *(x+i) are equivalent. The later satisfies your expectation, whereas, the first one, disguises the dereference operator, but does the exact same job you expected.
That said, also follow the data type closely. What you were expecting, something along the line of *x[i] would be plain invalid, as it boils down to something like `((x+i) ). Now,
x is of type int [] (integer array, which decays to a pointer to integer)
x+i gives you a pointer to int type result.
the inner dereference operator is applied to it, resulting an int.
The outer *, now will try to operate on an operand of type int (not a pointer), and, this operation will be a syntactical error, as, the constraint for dereference operator says,
The operand of the unary * operator shall have pointer type.
in C11, chapter §6.5.3.2.
Answering the additional question:
Let me use the quote, once again, this one's from paragraph 2, chapter §6.5.2.1
Successive subscript operators designate an element of a multidimensional array object.
If E is an n-dimensional array (n ≥ 2) with dimensions i × j × . . . × k, then E (used as
other than an lvalue) is converted to a pointer to an (n − 1)-dimensional array with
dimensions j × . . . × k. If the unary * operator is applied to this pointer explicitly, or
implicitly as a result of subscripting, the result is the referenced (n − 1)-dimensional
array, which itself is converted into a pointer if used as other than an lvalue. It follows
from this that arrays are stored in row-major order (last subscript varies fastest).
Consider the array object defined by the declaration
int x[3][5];
Here x is a 3 × 5 array of ints; more precisely, x is an array of three element objects, each of which is an
array of five ints. In the expression x[i], which is equivalent to (*((x)+(i))), x is first converted to
a pointer to the initial array of five ints. Then i is adjusted according to the type of x, which conceptually
entails multiplying i by the size of the object to which the pointer points, namely an array of five int
objects. The results are added and indirection is applied to yield an array of five ints. When used in the
expression x[i][j], that array is in turn converted to a pointer to the first of the ints, so x[i][j]
yields an int.
This is ok. No * there.
If you have pointer int *a which points to array of valid data, for example:
int *a;
int arr[5] = {1, 2, 3, 4, 5];
a = arr;
By using a[0] you are already dereferencing pointer and * is not required as a[0] is the same as *(a + 0).
You can go further and even more complicate code for readers.
You may use i[x] in your example instead of x[i]. Why?
x[i] is equal to *(x + i) but it is also equivalent to *(i + x) which is what arrays are in C.
It works even with numbers, such as x[3] or 3[x] will give you the same result.
In C, doing x[i] is equivalent (yeah I know) at i[x]. Your compiler compiles this by doing :
*(x+i), where you retrieve your favorite symbole.
x+i is a pointer where you start from x and advance by i. The result takes account of the type of the pointer (0xff is not the same address for a char* than for a int*).
You misunderstood how arrays work. Indeed, when using a variable such as int you should access it's address by
int x;
int *p2x = &x
but when using array, it's a bit different. int y[SOME_SIZE]; is a chunk of bytes in the memory, and *y will take you to the first element in that memory location, and dereference it. y[0] will do the same. *y[0] will first take the value in y[0] and then will try to dereference it... not what you usually want :(
the simple answer to your question is that :
The name of array is pointer to first element of array.

Is array the pointer to the first element, if yes...?

...then why is the code below give same value (meatballs) for address and the actual content? And how to make sense of %d value of meatballs, is it random?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main()
{
int i;
int meatballs[5]= {1,2,3,4,5};
printf("\nmeatsballs %p %p %d \t \n",meatballs, &meatballs,
meatballs);
return 0;
}
meatballs is an array, and it has type int[5]. However C doesn't allow passing arrays by value, so array decays into pointer for function call. This is equivalent of pointer to first element of array &meatballs[0], and it has type int*.
&meatballs is a pointer to an array, and it has type int(*)[5]. Since it's a pointer it can be passed to a function.
As you can see, both 1. and 2. return same address, but they have different types: pointer to integer array vs pointer to single integer.
Note: Types void* and int* don't necessarily have the same representation(1), and for %p only valid type is void*(2) or you will get undefined behaviour(3). Always convert pointer to void* when printing addresses:
printf("%p %p", (void*)meatballs, (void*)&meatballs);
Last situation is same as first, but you are using wrong type specifier %d. Resulting type is again int* as in case 1, but it is interpreted as int. This is clear undefined behaviour, and output is garbage.
To print integer array element, use any of the following methods:
printf("%d %d %d", meatballs[i], *(meatballs + i), *meatballs);
First two will print array element at index i, and last will print first element. I recommend using the meatballs[i] in most cases, as it's most clear.
References to C standard (draft):
N1570, 6.2.5 paragraph 28
A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.48)... ...Pointers to other types need not have the same representation or alignment requirements.
N1570, 7.21.6 paragraph 8
p The argument shall be a pointer to void. ...
N1570, 7.21.6 paragraph 9
... If any argument is
not the correct type for the corresponding conversion specification, the behavior is
undefined.
You have to use the unary dereference operator *, so that the actual value is shown as %d expects an integer.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main()
{
int i;
int meatballs[5]= {1,2,3,4,5};
printf("\nmeatsballs %p %p %d \t \n",meatballs, &meatballs,
*meatballs);
return 0;
}
Look at the last parameter: *meatballs. This code actually prints 1 as value and is the first element in your array. So your guess is right and it is only a bug.

Addition of a number to a pointer

#include<stdio.h>
int main()
{
float a=10;
float* p=&a;
printf("%u\n",p);
p=p+3;
printf("%u",p);
}
After execution of this program I got 2 memory addresses as an output, thelatter with a value greater by 12 than the former.
#include<stdio.h>
int main()
{
float a=10;
float* p=&a;
printf("%u\n",p);
p=p+3.5;
printf("%u",p);
}
I tried changing 3 to 3.5 but I got an output with equal values of both the addresses. I expected that the value would increment at least by 12 in either cases.
What could be the reason ?
That's how pointer arithmetic works. It's designed to work on arrays.
float array[4];
float *q;
q = array; /* Now q points to the first element of the array: q == &array[0] */
printf("%p\n", q);
q += 3; /* Now q points to the fourth element of the array: q == &array[3] */
printf("%p\n", q);
When you add an integer to a pointer, it points that many elements further into the array. If the size of the array elements is N bytes, then adding x to a pointer adds x*N to the address.
On your machine, it appears that sizeof(float) is 4: you see that x*N=12, with x=3, so N=4.
Note that there are several errors in your code. In your program, p=p+3 has undefined behavior because p points to a single float (which has the same memory layout as an array of 1 float). It is an error to make a pointer point outside the boundaries of an object. On a typical PC compiler you just silently get an invalid pointer; a rare few implementations would detect the invalid pointer as soon as it's computed and abort the program with an error.
Printing the pointer value with %u is also an error. In practice it may work, print garbage, or crash, depending on your compiler and on whether pointers have the same size as unsigned int. Any halfway decent compiler would warn you that printf("%u", p) is incorrect; if yours doesn't, make sure to enable its useful warnings (e.g. gcc -O -Wall if you're using GCC).
There is only three types of pointer arithmetic is allowed in C:
Adding an integer to a pointer.
Subtracting an integer from a pointer.
Subtracting one pointer from another (they should point to same array).
Standard says that:
C11:6.5.6 Additive operators:
2 For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to a complete object type and the other shall have integer type. (Incrementing is equivalent to adding 1.)
3 For subtraction, one of the following shall hold:
— both operands have arithmetic type;
— both operands are pointers to qualified or unqualified versions of compatible complete object types; or
— the left operand is a pointer to a complete object type and the right operand has integer type.
Any other arithmetic operation is invalid and will invoke undefined behavior. Note that the correct specifier for printing address is %p.
the program contains several errors and poor programing practices
#include<stdio.h>
int main()
{
float a=10; // init floats with float values, so use '10.0f'
float* p=&a;
printf("%u\n",p); // print addresses with '%p' not '%u'
p=p+3; // now 'p' is pointed to some unknown area
printf("%u",p); // print addresses with '%p' not '%u'
}
good thing the code did not 'de-reference' 'p' after 'p'
was modified, because that would have been undefined behaviour
possibly leading to a seg fault event

Resources