This is in C. I am learning C and this is an example in a slide from class.
int main(int argc, char *argv[]) {
int a = 5, b = 10, c;
int *p = &a, *q = &b;
c = p - q;
printf("%d", c);
return 0;
}
The output when I run it is 3 and I don't understand why. It seems like since it is using & it would subtract to memory addresses and the output would be a memory address to -5.
You are subtracting the address of the pointers not what they are pointing to and you'll get whatever the difference is between the two memory addresses is which is not guaranteed to be anything specific. If you run it on a different machine or compiler it will most likely be totally different values as a and b can be assigned a variety of addresses. For example on my machine it is 1. A phenomenons like this are called undefined behavior for a reason as you cannot guarantee the same result across all compilers and machines.
If you instead dereferenced p and q like this c = *p - *q; you would get -5 as c as the difference between the two set vales. Also if you assigned p and q as int *p = a, *q = b; then you would also get c as -5 because then you are literally setting the pointers to different address and trying to access after doing something like that will in all cases be a terrible idea.
Subtracting 2 pointers that are not of the same array is undefined behavior.
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. C11 §6.5.6 9
Instead, to get some numeric difference, convert values to intptr_t.
int main(int argc, char *argv[]) {
int a = 5, b = 10, c;
int *p = &a, *q = &b;
intptr_t ip = (intptr_t) p;
intptr_t iq = (intptr_t) q;
intptr_t diff = ip -iq;
printf("%lld", (long long) diff);
return 0;
}
Of course the value you print may not be 5. The locations of the int vary from compile to compile.
Related
Using DevCpp with TDM GCC 4.9.2 on Windows 8. But I don't think the platform matters for this question.
I know that we can use a pointer to point to a single data or an array of data.
I have learned about pointer to arrays but never used it. What advantage does one have over the other?
Sample Code...
#include <stdio.h>
int main()
{
int x[2]={10,20};
int *p1= NULL; //simple pointer
int (*p2)[] = NULL; //pointer to an array, specifically
p1 = x;
p2 = &x; //removing the & gives me a warning of "assignment from incompatible pointer types".
printf("x[1] = %d\n", x[1]);
*(p1+1) = 7;
printf("x[1] = %d\n", x[1]);
(*p2)[1] = 55;
printf("x[1] = %d", x[1]);
return 0;
}
Does p1 or p2 have an advantage over the other?
They are completely different.
int *p; - is the pointer to the int
int (*p)[1]; is a pointer to the array (in this case one element only)
In your trivial example the pointer arithmetic will be the same and generated code will be the same. But they still have different types and you may get warnings when compiled.
The "advantages" you will see when your example will be less trivial:
int (*p)[100];
p++; the pointer will point to the next 100 elements int array.
Pointer to an array means a pointer which accepts address of an array.
let's say array is int arr[5],in which size of int is 4 byte.
p is a pointer to an array that accept the address of an int array.
int arr[5];
int (*p)[5];
p=&arr;//address of an array block
let's say the base address is 1000 .So after increment in p it will lead us to 1020 address,because the size of the array block is 20 bytes.
p points to 1000 address
p++;
//Now p points to 1020 not 1004.
Whereas in case of int *q, q will point to 1004 as usual.
I was thinking about pointer initialization and tried the following two cases:
#include <stdio.h>
int main(int argc, char **argv)
{
int *d;
int f;
int p;
*d = 6;
printf("%d %d %d\n", *d, f, p);
return 0;
}
This code segfaults at the line (seen in gdb):
*d = 6;
Which makes sense because I am trying store a value at a random address.
I then tried the following:
#include <stdio.h>
int main(int argc, char **argv)
{
int *d;
int f = 10;
int p = 9;
*d = 6;
printf("%d %d %d\n", *d, f, p);
return 0;
}
This runs to completion with the output:
6 10 9
If only f is initialized to 10 (p is not initialized) or vice versa, the program still completes with output
6 10 0
or
6 0 9
(p initialized). I do not understand why this works. My initial guess is that the initialization of either f or p makes space or orients memory to allow for the safe initialization of d. I also thought about stack allocations, but am still unsure.
Your first problem is in *d = 6; as you're trying to to dereference an invalid pointer.
d is not initialized (allocated memory) and it points to an invalid memory location. Any attempt to dereference that will lead to undefined behavior.
FWIW, the second code also produces UB for the same reason.
Additionally, in the first code snippet, by writing
printf("%d %d %d\n", *d, f, p);
where f and p are uninitialized automatic local variable, you're trying to read indeterminate values, which again, produces UB. This is avoided in the second snippet by explicit initialization.
In your program -
*d = 6; // writing to an invalid memory location
You leave the pointer with uninitialized value. So when you dereference it (*d), you access unauthorized location in memory, resulting in a segmentation fault.
you also try to print uninitialized local variables-
printf("%d %d %d\n", *d, f, p); // where f and p are indeterminate
Therefore , your code invokes undefined behaviour and your program give output which literally can be anything.
This code segfaults at the line (seen in gdb):
*d = 6;
Which makes sense because I am trying to give random address to a
value.
It does make sense that that segfaults, but your explanation is grossly incorrect. You are not in any way giving / or assigning an address to a value. Rather, you are attempting to store a value at an unspecified address.
It is critically important to understand the difference between d and *d. The former (as you have declared it) is a pointer that is expected to hold the address of an int. The latter is the int that d points to. If d has not, in fact, been initialized to point to an int, then evaluating the expression *d produces undefined behavior.
Undefined behavior is exactly that -- undefined. You cannot expect a similar source of undefined behavior to produce the same actual behavior in other circumstances, and you cannot even rely on the behavior to manifest an obvious indication of brokenness. Anything can happen, including, in principle, what the programmer wanted to happen.
Declaring a pointer variable does not automatically cause any storage to be allocated. There are any number of ways you could initialize d, but one would be
d = &f;
You need to Allocate your memory with malloc()
this work:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int *d;
int f = 10;
int p = 9;
d = /*(int *)*/malloc(sizeof(int) * 1);
if (!d)
exit(-1);
*d = 6;
printf("%d %d %d\n", *d, f, p);
free(d);
return 0;
}
If I have a 2d array B defined as :
int B[2][3] = {{1,3,5},{2,4,6}};
Is int **p = B same as int (*p)[3] = B ?
int **f = B; printf("%d ",*f+1);
gives 5 as output while printf("%d ",*f) gives 1 as answer. Why
is that happening?
printf("%d ",**f);
returns a segmentation fault! Why?
No. int **p = B; is an error. (Both a compilation error, and a logical error). An int ** must point to an int *. However, there are no int * stored in B. B is a group of contiguous ints with no pointers involved.
int **f = B; must give a compilation error. The behaviour of any executable generated as a result is completely undefined.
See 2.
To explain why you might be seeing 1 and 5. (The C standard does not define this, but your compiler bulls on ahead anyway). Probably your compiler treats the line as
int **f = (int **)B;
Then the expression *f will read bytes from the storage of B (which actually hold ints) and pretend that those are the bytes that make up a pointer representation. This is further undefined behaviour (violation of strict-aliasing rules). Probably the result of this is that *f is a pointer to address 0x00000001.
Then you print a pointer by using %d, causing further undefined behaviour. You see 1 because your system uses the same method for passing int to printf as it does to pass int *.
When you add 1 to (int *)0x00000001, you get (int *)0x00000005, because incrementing a pointer means to point to the next element of that type.
When you dereference this pointer, it causes a segfault because that address is outside of your valid address space.
1) Is int **p = b same as int (*p)[3] = b ? - No. int **p = b is an error.
Because here int **p is a pointer to pointer to an integer, but int (*p)[3] is pointer to an array of 3 integers!
2) int **f = B; It is an error, May results in Undefined behavior!
3) printf("%d ",**f); - It is same as (2). int **f = B; is error, so Undefined behavior!
NOTE: To avoid this type of error enable some warning flags in compiler option and try!
Can anyone explain the logic how to add a and b?
#include <stdio.h>
int main()
{
int a=30000, b=20, sum;
char *p;
p = (char *) a;
sum = (int)&p[b]; //adding a and b!
printf("%d",sum);
return 0;
}
The + is hidden here:
&p[b]
this expression is equivalent to
(p + b)
So we actually have:
(int) &p[b] == (int) ((char *) a)[b]) == (int) ((char *) a + b) == a + b
Note that this technically invokes undefined behavior as (char *) a has to point to an object and pointer arithmetic outside an object or one past the object invokes undefined behavior.
C standard says that E1[E2] is equivalent to *((E1) + (E2)). Therefore:
&p[b] = &*((p) + (b)) = ((p) + (b)) = ((a) + (b)) = a + b
p[b] is the b-th element of the array p. It's like writing *(p + b).
Now, when adding & it'll be like writing: p + b * sizeof(char) which is p + b.
Now, you'll have (int)((char *) a + b) which is.. a + b.
But.. when you still have + in your keyboard, use it.
As #gerijeshchauhan clarified in the comments, * and & are inverse operations, they cancel each other. So &*(p + b) is p + b.
p is made a pointer to char
a is converted to a pointer to char, thus making p point to memory with address a
Then the subscript operator is used to get to an object at an offset of b beyond the address pointed to by p. b is 20 and p+20=30020 . Then the address-of operator is used on the resulting object to convert the address back to int, and you've got the effect of a+b
The below comments might be easier to follow:
#include <stdio.h>
int main()
{
int a=30000, b=20, sum;
char *p; //1. p is a pointer to char
p = (char *) a; //2. a is converted to a pointer to char and p points to memory with address a (30000)
sum = (int)&p[b]; //3. p[b] is the b-th (20-th) element from address of p. So the address of the result of that is equivalent to a+b
printf("%d",sum);
return 0;
}
Reference: here
char *p;
p is a pointer (to element with size 1 byte)
p=(char *)a;
now p points to memory with address a
sum= (int)&p[b];
p pointer can be use as array p[] (start address (in memory) of this array is a)
p[b] means to get b-th element - this element address is a+b
[ (start address)a + b (b-th element * size of element (1 byte)) ]
&p[b] means to get address of element at p[b] but its address is a+b
if you use pointer to int (mostly 4 bytes)
int* p
p = (int*)a;
your sum will be a+(4*b)
int a=30000, b=20, sum;
char *p; //1. p is a pointer to char
p = (char *) a;
a is of type int, and has the value 30000. The above assignment converts the value 30000 from int to char* and stores the result in p.
The semantics of converting integers to pointers are (partially) defined by the C standard. Quoting the N1570 draft, section 6.3.2.3 paragraph 5:
An integer may be converted to any pointer type. Except as previously
specified, the result is implementation-defined, might not be
correctly aligned, might not point to an entity of the referenced
type, and might be a trap representation.
with a (non-normative) footnote:
The mapping functions for converting a pointer to an integer or an
integer to a pointer are intended to be consistent with the addressing
structure of the execution environment.
The standard makes no guarantees about the relative sizes of types int and char*; either could be bigger than the other, and the conversion could lose information. The result of this particular conversions is very unlikely to be a valid pointer value. If it's a trap representation, then the behavior of the assignment is undefined.
On a typical system you're likely to be using, char* is at least as big as int, and integer-to-pointer conversions probably just reinterpret the bits making up the integer's representation as the representation of a pointer value.
sum = (int)&p[b];
p[b] is by definition equivalent to *(p+b), where the + denotes pointer arithmetic. Since the pointer points to char, and a char is by definition 1 byte, the addition advances the pointed-to address by b bytes in memory (in this case 20).
But p is probably not a valid pointer, so any attempt to perform arithmetic on it, or even to access its value, has undefined behavior.
In practice, most C compilers generate code that doesn't perform extra checks. The emphasis is on fast execution of correct code, not on detection of incorrect code. So if the previous assignment to p set it to an address corresponding to the number 30000, then adding b, or 20, to that address will probably yield an address corresponding to the number 30020.
That address is the result of (p+b); now the [] operator implicitly applies the * operator to that address, giving you the object that that address points to -- conceptually, this is a char object stored at an address corresponding to the integer 30020.
We immediately apply the & operator to that object. There's a special-case rule that says applying & to the result of a [] operator is equivalent to just doing the pointer addition; see 6.5.3.2p2 in the above referenced standard draft.
So this:
&p[b]
is equivalent to:
p + b
which, as I said above, yields an address (of type char*) corresponding to the integer value 30020 -- assuming, of course, that integer-to-pointer conversions behave in a certain way and that the undefined behavior of constructing and accessing an invalid pointer value don't do anything surprising.
Finally, we use a cast operator to convert this address to type int. Conversion of a pointer value to an integer is also implementation-defined, and possibly undefined. Quoting 6.3.2.3p6:
Any pointer type may be converted to an integer type. Except as
previously specified, the result is implementation-defined. If the
result cannot be represented in the integer type, the behavior is
undefined. The result need not be in the range of values of any
integer type.
It's not uncommon for a char* to be bigger than an int (for example, I'm typing this on a system with 32-bit int and 64-bit char*). But we're relatively safe from overflow in this case, because the char* value is the result of converting an in-range int value. there's no guarantee that converting a given value from int to char* and back to int will yield the original result, but it commonly works that way, at least for values that are in range.
So if a number of implementation-specific assumptions happen to be satisfied by the implementation on which the code happens to be running, then this code is likely to yield the same result as 30000 + 20.
Incidentally, I've worked on a system where this would have failed. The Cray T90 was a word-addressed machine, with hardware addresses pointing to 64-bit words; there was no hardware support for byte addressing. But char was 8 bits, so char* and void* pointers had to be constructed and manipulated in hardware. A char* pointer consisted of a 64-bit word pointer with a byte offset stored in the otherwise unused high-order 3 bits. Conversions between pointers and integers did not treat these high-order bits specially; they were simply copied. So ptr + 1 and (char*)(int)ptr + 1) could yield very different results.
But hey, you've managed to add two small integers without using the + operator, so there's that.
An alternative to the pointer arithmetic is to use bitops:
#include <stdio.h>
#include <string.h>
unsigned addtwo(unsigned one, unsigned two);
unsigned addtwo(unsigned one, unsigned two)
{
unsigned carry;
for( ;two; two = carry << 1) {
carry = one & two;
one ^= two;
}
return one;
}
int main(int argc, char **argv)
{
unsigned one, two, result;
if ( sscanf(argv[1], "%u", &one ) < 1) return 0;
if ( sscanf(argv[2], "%u", &two ) < 1) return 0;
result = addtwo(one, two);
fprintf(stdout, "One:=%u Two=%u Result=%u\n", one, two, result );
return 0;
}
On a completely different note, perhaps what was being looked for was an understanding of how binary addition is done in hardware, with XOR, AND, and bit shifting. In other words, an algorithm something like this:
int add(int a, int b)
{ int partial_sum = a ^ b;
int carries = a & b;
if (carries)
return add(partial_sum, carries << 1);
else
return partial_sum;
}
Or an iterative equivalent (although, gcc, at least, recognizes the leaf function and optimizes the recursion into an iterative version anyway; probably other compilers would as well)....
Probably needs a little more study for the negative cases, but this at least works for positive numbers.
/*
by sch.
001010101 = 85
001000111 = 71
---------
010011100 = 156
*/
#include <stdio.h>
#define SET_N_BIT(i,sum) ((1 << (i)) | (sum))
int sum(int a, int b)
{
int t = 0;
int i = 0;
int ia = 0, ib = 0;
int sum = 0;
int mask = 0;
for(i = 0; i < sizeof(int) * 8; i++)
{
mask = 1 << i;
ia = a & mask;
ib = b & mask;
if(ia & ib)
if(t)
{
sum = SET_N_BIT(i,sum);
t = 1;
/*i(1) t=1*/
}
else
{
t = 1;
/*i(0) t=1*/
}
else if (ia | ib)
if(t)
{
t = 1;
/*i(0) t=1*/
}
else
{
sum = SET_N_BIT(i,sum);
t = 0;
/*i(1) t=0*/
}
else
if(t)
{
sum = SET_N_BIT(i,sum);
t = 0;
/*i(1) t=0*/
}
else
{
t = 0;
/*i(0) t=0*/
}
}
return sum;
}
int main()
{
int a = 85;
int b = 71;
int i = 0;
while(1)
{
scanf("%d %d", &a, &b);
printf("%d: %d + %d = %d\n", ++i, a, b, sum(a, b));
}
return 0;
}
void main()
{
int (*d)[10];
d[0] = 7;
d[1]=10;
printf("%d\n",*d);
}
It should print 10 but compiler is showing error such as follows:
test.c:4:7: error: incompatible types when assigning to type ‘int[10]’ from type ‘int’
Note that I have included some errors , not all.
As noted by chris, d is a pointer to an array. This means you use the variable improperly when you access it, but also that you will access random memory unless you assign d to point to a valid array.
Change your program as follows:
int main(void)
{
int (*d)[10]; /* A pointer to an array */
int a[10]; /* The actual array */
d = &a; /* Make `d` point to `a` */
/* Use the pointer dereference operator (unary prefix `*`)
to access the actual array `d` points to */
(*d)[0] = 7;
(*d)[1] = 10;
/* Double dereference is okay to access the first element of the
arrat `d` points to */
printf("%d\n", **d);
return 0;
}
In C, [] is the same as *, the pointer syntax. Thus the following lines are the same:
int** array2d1;
int* array2d2[];
int array2d3[][];
To relate to a closer example, the main function has the following popular forms:
int main(int argc, char** argv){ ... }
or
int main(int argc, char* argv[]){ ... }
Thus
int (*d)[10]
is the same as
int* d[10]
which is the same as
int** d;
int firstArray[10];
d = &firstArray;
Effectively, you are creating a pointer to a pointer (which is a pointer to an array) and allocating the first pointer to an array that 10 elements. Therefore, when you run the following lines:
d[0] = 7;
d[1] = 10;
You are assigning the 1st array's address to 7 and the second array's address to 10. So as Joachim has mentioned, to assign values, you need to deference twice:
(*d)[0] = 7
(*d)[1] = 10
Which says "Assign 7 to the 0th index at the value pointed by d". I hope that makes sense?
d is a pointer to an array of 10 ints.
int (*d)[10] is the declaration for a point to an array of 10 ints.
vs.
int *d[10], which is an array of 10 int pointers.
For more complex syntax like this (usually involving pointers), I use cdecl to help me decode it.
It's used in this form
int d[10]
I guess you are mistaken that d must be a "kind of pointer" and therfor you put an * before the d.
But that's not what you want. You wan to name an array of integer and the notation for that is seen above.
Concept of pointer can get confusing sometimes in C.
Consider an array int d[6] = {0,1,2,3,4,5}
Then, *d is equivalent to d[0]. d is itself an pointer to an array and *d dereferences that pointer and gives us the value.
Hence, following code would print the same values:
int main()
{
int (d)[10];
*d = 7;
*(d + 1)=10;
printf("%d\n",*d);
printf("%d\n",d[0]);
return 0;
}
result:
7
7
Please see http://codepad.org/LYY9ig1i.
If you change your code as follows:
#include<malloc.h>
int main()
{
int *d[10]; //not (*d)[10]
d[0] = (int *)malloc(sizeof(int *) * 10);
d[0][0] = 7;
printf("%d\n",d[0][0]);
return 0;
}
Hope this helps you!