In a homework project, I have to subtract the address of one pointer from another.
Here is a piece of code I tried to write to subtract the heap of void* type, from a given metadata address. It's wrong somewhere.
metadata_t* getBuddy(metadata_t* ptr)
{
metadata_t* offset = ptr - (char)heap;
int h = (char)heap;
#ifdef DEBUG
printf("ptr : %p\n", ptr);
printf("heap : %p\n", heap);
printf("offset: %p\n", offset);
printf("char : %d\n", h);
#endif
return NULL;
}
Here is the output I get:
ptr : 0x7fe7b3802440
heap : 0x7fe7b3802200
offset: 0x7fe7b3802440
char : 0
Here is the output I EXPECTED:
ptr : 0x7fe7b3802440
heap : 0x7fe7b3802200
offset: 0x000000000240
char : 0x7fe7b3802200
Questions:
1) Why would the char output be zero? (Is this not what I am doing: casting the a pointer in single bytes, and then storing it into an int)
2) If this is not how you properly do the pointer arithmetic, how else would you accomplish the offset?
Edits:
1) Heap is defined as a int*, I think. This is the given piece of code that returns its value.
#define HEAP_SIZE 0x2000
void *my_sbrk(int increment) {
static char *fake_heap = NULL;
static int current_top_of_heap = 0;
void *ret_val;
if(fake_heap == NULL){
if((fake_heap = calloc(HEAP_SIZE, 1)) == NULL) {
return (void*)-1;
}
}
ret_val=current_top_of_heap+fake_heap;
if ((current_top_of_heap + increment > HEAP_SIZE)
|| (current_top_of_heap+increment < 0)) {
errno=ENOMEM;
return (void*)-1;
}
current_top_of_heap += increment;
return ret_val;
}
Pointer arithmetic only makes sense for a specific type. In this example, the int type is size 4 but the pointer subtraction is only 1.
#include <stdio.h>
int array[2];
int *a, *b;
int main(void){
a = &array [0];
b = &array [1];
printf ("Int size = %d\n", sizeof(int));
printf ("Pointer difference = %d\n", b-a);
return 0;
}
Program output:
Int size = 4
Pointer difference = 1
Pointers arithmetic doesn't support the operation (pointer + pointer). The only operation allowed is (Pointer + Integer) so the result is a pointer.
To get the offset you need to cast both pointers to an integer type. And the resulting value is an integer not a pointer.
Example:
int offset = (int)ptr - (int)heap;
printf("ptr : %p\n", ptr);
printf("heap : %p\n", heap);
printf("offset: %d\n", offset);
Also the value of heap is too much large to be stored in a single byte and that's why casting it into a char type returns the value zero.
Related
I was reading about function pointer. That it contains address of instructions. And there I encountered one question to find an element in array using function pointer. Here is the code.
#include <stdio.h>
#include <stdbool.h>
bool compare(const void* a, const void* b)
{
return (*(int*)a == *(int*)b);
}
int search(void* arr, int arr_size, int ele_size, void* x, bool compare(const void*, const void*))
{
char* ptr = (char*)arr; // Here why not int *ptr = (int*)arr;
int i;
for (i = 0; i < arr_size; i++)
{
if (compare(ptr + i * ele_size, x))
{
return i;
}
}
return -1;
}
int main()
{
int arr[] = { 2, 5, 7, 90, 70 };
int n = sizeof(arr) / sizeof(arr[0]);
int x = 7;
printf("Returned index is %d ", search(arr, n, sizeof(int), &x, compare));
return 0;
}
In the search function char *ptr = (char*)arr; is used which is giving perfect answer = 2.
But when I have used int *ptr = (int*)arr; it gives -1 as answer.
Why is this? Can anyone explain this?
A char is the smallest addressable unit in any C program, and on most system it corresponds to a single byte. That treats the array as a generic sequence of bytes, and uses the ele_size to calculate the byte-position of each element with ptr + i*ele_size.
If you use int *ptr then the byte-position calculation will be wrong by a factor of sizeof(int) (typically 4), since the pointer arithmetic will be done in units of the base type (int instead of char).
The function search knows nothing about what is the type of elements of the array pointed to by the pointer arr of the type void *.
So casting the pointer to the type int * does not make a sense. If to do so then the expression ptr + i*ele_size where the pointer arithmetic is used will produce an incorrect result.
That it contains address of instructions
There is a subtle difference between normal (object) pointers and function pointers. It is not possible to access the single instructions of a function - they do not have the same length.
With other pointers the increment (arithmetic) is adapted to the type, whether as p[i] or p + i or *(p+i).
Side note: there still is int at the bottom of the call chain:
return (*(int*)a == *(int*)b);
Here's the code -
#include <stdio.h>
int main()
{
char character_1 = '0';
int integer_1 = 12321;
char character_2 = '1';
char character_3 = '2';
printf("Integer occupies %zu byte(s) of space.\n",sizeof(int));
printf("Address of Integer 1: %p\n",(void*)&integer_1);
printf("\n");
printf("Character occupies %zu byte(s) of space.\n",sizeof(char));
printf("Address of Character 1: %p\n",(void*)&character_1);
printf("Address of Character 2: %p\n",(void*)&character_2);
printf("Address of Character 3: %p\n",(void*)&character_3);
printf("\n");
return 0;
}
and, the generated output -
Integer occupies 4 byte(s) of space.
Address of Integer 1: 000000000061FE18
Character occupies 1 byte(s) of space.
Address of Character 1: 000000000061FE1F
Address of Character 2: 000000000061FE17
Address of Character 3: 000000000061FE16
I want to print the addresses of all the four bytes of space occupied by the integer variable integer_1, which means print all four of these - 000000000061FE18, 000000000061FE19, 000000000061FE1A and 000000000061FE1B. How do I do it?
Is this what you are trying to do?
#include <stdio.h>
int main()
{
int integer_1 = 12321;
unsigned char* p = (unsigned char*)&integer_1;
for (int i=0; i<sizeof(int); i++){
printf("Address: %p -> Value: %02hhx\n", p+i, *(p+i));
}
return 0;
}
EDIT: As pointed out by KPCT, working with void* is indeed possible, just a bit more tedious if you are also interested in the value pointed, and not the address only.
For example, adapting my above solution to use void*, would result in something like this
#include <stdio.h>
int main()
{
int integer_1 = 12321;
void* p = (void*)&integer_1;
for (int i=0; i<sizeof(int); i++){
printf("Address: %p -> Value: %02hhx\n", p+i, *((char*) p+i));
}
return 0;
}
where you would have to go through the cast to char* anyway
You would need to cast the int pointer to a char pointer (or an int8_t pointer), then step through each of the bytes, something like this:
char *cp = (char*)&integer_1;
for (int i = 0; i < sizeof(integer_1); ++i)
printf("Address of integer_1, byte %d: %p\n",i,cp++);
The man has the code
#include <conio.h>
#include <stdio.h>
void dbleInt(void *a) {
*((int*) a) *= 2;
}
void deleteEvenInt(void* a) {
int tmp = *((int*) a);
if (tmp % 2 == 0) {
*((int*) a) = 0;
}
}
void dbleDouble(void *a) {
*((double*) a) *= 2.0;
}
void deleteEvenDouble(void* a) {
int tmp = *((double*) a);
if (tmp % 2 == 0) {
*((double*) a) = 0;
}
}
// Function takes an array, its size, the size of one element and a function //pointer,
// Which is then applied to all the elements of an array
void map(void *arr, unsigned num, size_t size, void (*fun)(void *)) {
unsigned i;
char *ptr = (char*) arr;
for (i = 0; i < num; i++) {
fun((void*) (ptr + i*size));
}
}
Why does he leads void* type to char* type? I can see thats it an error, when I change this code and dont lead it, but why?
You're not allowed to perform arithmetic on void pointers in C. So the following code is illegal:
void *foo = whatever;
foo + 1;
By casting foo to a char *, she can perform arithmetic on the pointer.
My comments are on why void *ptr, one cannot perform address arithmetic. Warning , Long rambling :).
In general
when you do a ptr arithmetic like
ptr = ptr + N ;
The interpretation by C is to perform the following equivalent integer arithmetic (Infact the compiler will produce assembly code equivalent to below integer arithmetic)
ptr = ptr + N* sizeof (typeof(*N)) ;
Hence The compiler has to know the typeof (*N) for it to produce code. typeof (*N) here means, the type of variable "ptr" points to. (typeof is not a standard c construct, it is being bought here for mere explanation).
Take an e.g.
int x ; // Assume x is at addesss 1000
int *ptr = &x ; // ptr has a value of 1000
Then
ptr = ptr + 1 ;
would make ptr as 1004 during run time (assuming size of int is 4 bytes)
Explanation-1: The above statement means that ptr should contain the address of next integer variable after ptr. Since ptr points to x , which is at address 1000, the next integer variable after 1000 would be 1004. So ptr would be 1004.
Explanation-2 This is also in sync with the interpretation of ptr = ptr +N is equivalent to integer arithmeitc
ptr = ptr + N* sizeof (typeof(*N)) ; // typeof (*N)->int
// => 1000 + 1 *sizeof (typeof (int))
// => 1004
To summarize For the ptr arith operation
ptr = ptr + N ;
the compiler produces an equivalent assembly code as
ptr = ptr + N* sizeof (typeof(*N)) // Compiler Needs to typeof(*N)
Hence the compiler needs to know what is the data-type that ptr is pointing to.
Now consider
void foo (int type, void *ptr) {
ptr = ptr + 2 ;
}
f2() {
int x ;
char c ;
f1(&x) ;
f1(&c);
}
The void * ptr is a generic ptr pointing to an addresss. When called with f1(&x) the ptr points to an address of integer, when called with f1(&c) it points to address of a character. So at compile time , compiler cannot determine what is the typeof (*ptr). (for in one case it is integer and another is character). Hence it is not possible for the compiler to generate code for
ptr = ptr + n ;
So you will have to cast the ptr of being a particular known type and then do arithmetic operation.
Hope this helps.
could you explain the following code,
int main() {
int value = 2;
int *ptrWithAmpersand = &value;
int *ptrWithoutAmpersand = value;
//printf("%d", *ptrWithoutAmpersand); 1) Why Runtime error.
printf("Pointer with & --> %d\n", *ptrWithAmpersand);
printf("Pointer withOUT & and * --> %d\n", ptrWithoutAmpersand); //2) Why this works??!!
getch();
}
As commented in the code
Why Runtime Error?
Why this works?
Output is
Pointer with & --> 2
Pointer withOUT & and * --> 2
In the line
int *ptrWithAmpersand = &value;
you are creating a pointer to int and assigning the address of the variable value to it. So far so good.
In the line
int *ptrWithoutAmpersand = value;
you are creating a pointer to int and assigning the contents of the variable value (2) to it. This leads to several problems:
You are attempting to assign a value of type int to a variable of type int *, which are not compatible types; the compiler should at least issue a warning of "incompatible types in assignment" or something like that (turn on all warnings)
On your system, 2 is not a valid object address, hence the runtime error when you try to dereference ptrWithoutAmpersand.
You have several other problems in your code. You should not use the %d conversion specifier to print out pointer values; always use %p for that purpose.
Here's a slight rewrite of your code to makes some things a little clearer:
#include <stdio.h>
int main() {
int value = 2;
int *ptrWithAmpersand = &value;
int *ptrWithoutAmpersand = value; // throws a warning in gcc; you should not do this
printf("value of expression \"value\" = %d\n", value );
printf("value of expression \"&value\" = %p\n", (void *) &value );
printf("value of expression \"ptrWithAmpersand\" = %p\n", (void *) ptrWithAmpersand );
printf("value of expression \"*ptrWithAmpersand\" = %d\n", *ptrWithAmpersand );
printf("value of expression \"ptrWithoutAmpersand\" = %p\n", (void *) ptrWithoutAmpersand );
return 0;
}
And here is the output of the code:
value of expression "value" = 2
value of expression "&value" = 0x7ffecb63cf44
value of expression "ptrWithAmpersand" = 0x7ffecb63cf44
value of expression "*ptrWithAmpersand" = 2
value of expression "ptrWithoutAmpersand" = 0x2
Note how the pointer expression are printed out vs. the integer expressions.
In short:
*ptrWithAmpersand == value == 2 type == int
ptrWithAmpersand == &value type == int *
ptrWithoutAmpersand == value == 2 mismatched types int * and int
In:
int *ptrWithAmpersand = &value;
printf("Pointer with & --> %d\n", *ptrWithAmpersand);
you correctly assign an address to the pointer and in the printf you correctly dereference it to print an int with the %d parameter.
In:
int *ptrWithoutAmpersand = value;
printf("Pointer withOUT & and * --> %d\n", ptrWithoutAmpersand);
You are incorectly assigning an integer value to a pointer, but because in the printf you do not dereference it, it will be printed as an int with the %d parameter. This will only cause a problem (UB) if sizeof(int *) != sizeof(int).
In:
int *ptrWithoutAmpersand = value;
printf("%d", *ptrWithoutAmpersand);
you get a runtime error because you are dereferencing a pointer that points to memory address 2, which is not yours and so the system aborts your program.
I am a Java programmer and recently play with C for fun. Now I am learning address and pointers which are a little bit confusing for me. Here is my question. See the below two blocks of the code.
void withinArray(int * a, int size, int * ptr) {
int x;
printf("ptr is %d\n", ptr);
printf("a is %d\n", a);
printf("difference in pointers is: %d\n", ptr - a);
x = ptr - intArray;
printf("x is %d\n", x);
}
void doubleSize() {
double doubArray[10];
double * doubPtr1;
double * doubPtr2;
doubPtr1 = doubArray;
doubPtr2= doubArray+1;
int p2 = doubPtr2;
int p1 = doubPtr1;
printf("p2-p1 is %d\n", p2-p1);
printf("doubPtr2-doubPtr1 is %d\n", doubPtr2-doubPtr1);
}
int main(void)
{
int a[10];
int *intarray = a;
int *p = intarray + 9;
printf(withinArray(a, 10, p));
return 0;
}
I am wondering for function withinArray(), why we could directly get the x value, which is 9? But for the other method, we have to convert doubPtr to int first and then we can get the difference between pointers in int?
From my understanding, in doubleSize(), doubPtr2-doubPtr1 = 1 means the difference in pointer address in memory is 1. But why the withinArray() doesn't need to do so?
A difference of 1 between two pointers means that the pointers point to adjacent units of memory of the size of the objects pointed at.
Thus, given:
int i[2];
int *ip0 = &i[0];
int *ip1 = &i[1];
double d[2];
double *dp0 = &d[0];
double *dp1 = &d[1];
we could safely write:
assert((ip1 - ip0) == (dp1 - dp0));
assert(ip1 - ip0 == 1);
assert(dp1 - dp0 == 1);
However, you could also safely write:
assert((char *)ip1 - (char *)ip0 == sizeof(int));
assert((char *)dp1 - (char *)dp0 == sizeof(double));
and usually you would find that it is safe to write:
assert(sizeof(double) != sizeof(int));
though that is not guaranteed by the standard.
Also, as Filipe Gonçalves correctly points out in his comment, the difference between two pointers is formally only defined if the pointers are of the same type and point to two elements of the same array, or point to one element beyond the end of the array. Note that standard C demands that given:
int a[100];
it is safe to generate the address int *ip = &array[100];, even though it is not safe to either read from or write to the location pointed at by ip. The value stored in ip can be used in comparisons.
You also formally cannot subtract two void * values because there is no size for the type void (which is why my example used casts to char *, not void *). Beware: GCC will not object to the subtraction of two void * values unless you include -pedantic in the options.
Do you know why the value of doubPtr2 - doubPtr1 (in my second method) is different from x = ptr - a (in my first method)?
Assuming that intArray is meant to be a, then this code:
#include <stdio.h>
static void withinArray(int *a, int *ptr)
{
int x;
printf("ptr is %p\n", (void *)ptr);
printf("a is %p\n", (void *)a);
printf("difference in pointers is: %td\n", ptr - a);
x = ptr - a;
printf("x is %d\n", x);
}
static void doubleSize(void)
{
double doubArray[10];
double *doubPtr1 = doubArray;
double *doubPtr2 = doubArray+1;
int p2 = doubPtr2;
int p1 = doubPtr1;
printf("p1 = 0x%.8X\n", p1);
printf("p2 = 0x%.8X\n", p2);
printf("p2-p1 is %d\n", p2-p1);
printf("doubPtr1 = %p\n", (void *)doubPtr1);
printf("doubPtr1 = %p\n", (void *)doubPtr2);
printf("doubPtr2-doubPtr1 is %td\n", doubPtr2-doubPtr1);
}
int main(void)
{
int a[10];
int *intarray = a;
int *p = intarray + 9;
withinArray(a, p);
doubleSize();
return 0;
}
compiles with warnings that I would ordinarily fix (change the type of p1 and p2 to uintptr_t, include <inttypes.h>, and format using "p1 = 0x%.8" PRIXPTR "\n" as the format string), and it generates the output:
ptr is 0x7fff5c5684a4
a is 0x7fff5c568480
difference in pointers is: 9
x is 9
p1 = 0x5C5684B0
p2 = 0x5C5684B8
p2-p1 is 8
doubPtr1 = 0x7fff5c5684b0
doubPtr1 = 0x7fff5c5684b8
doubPtr2-doubPtr1 is 1
Fixed code generates:
ptr is 0x7fff5594f4a4
a is 0x7fff5594f480
difference in pointers is: 9
x is 9
p1 = 0x7FFF5594F4B0
p2 = 0x7FFF5594F4B8
p2-p1 is 8
doubPtr1 = 0x7fff5594f4b0
doubPtr1 = 0x7fff5594f4b8
doubPtr2-doubPtr1 is 1
(The difference is in the number of hex digits printed for p1 and p2.)
I assume that your puzzlement is about why the int code prints 9 rather than, say, 36, whereas the double code prints 8 instead of 1.
The answer is that when you subtract two pointers, the result is given in units of the size of the objects pointed at (which I seem to remember saying in my opening sentence).
When you execute doubPtr2-doubPtr1, the distance returned is in units of the number of double values between the two addresses.
However, the conversion to integer loses the type information, so you effectively have the char * (or void *) addresses of the two pointers in the integer, and the byte addresses are indeed 8 apart.
If we make two symmetrical routines, the information is clearer:
#include <stdio.h>
#include <inttypes.h>
static void intSize(void)
{
int intArray[10];
int *intPtr1 = intArray;
int *intPtr2 = intArray+1;
uintptr_t p2 = (uintptr_t)intPtr2;
uintptr_t p1 = (uintptr_t)intPtr1;
printf("p1 = 0x%.8" PRIXPTR "\n", p1);
printf("p2 = 0x%.8" PRIXPTR "\n", p2);
printf("p2-p1 is %" PRIdPTR "\n", p2-p1);
printf("intPtr1 = %p\n", (void *)intPtr1);
printf("intPtr1 = %p\n", (void *)intPtr2);
printf("intPtr2-intPtr1 is %td\n", intPtr2-intPtr1);
}
static void doubleSize(void)
{
double doubArray[10];
double *doubPtr1 = doubArray;
double *doubPtr2 = doubArray+1;
uintptr_t p2 = (uintptr_t)doubPtr2;
uintptr_t p1 = (uintptr_t)doubPtr1;
printf("p1 = 0x%.8" PRIXPTR "\n", p1);
printf("p2 = 0x%.8" PRIXPTR "\n", p2);
printf("p2-p1 is %" PRIdPTR "\n", p2-p1);
printf("doubPtr1 = %p\n", (void *)doubPtr1);
printf("doubPtr1 = %p\n", (void *)doubPtr2);
printf("doubPtr2-doubPtr1 is %td\n", doubPtr2-doubPtr1);
}
int main(void)
{
doubleSize();
intSize();
return 0;
}
Output:
p1 = 0x7FFF5C93D4B0
p2 = 0x7FFF5C93D4B8
p2-p1 is 8
doubPtr1 = 0x7fff5c93d4b0
doubPtr1 = 0x7fff5c93d4b8
doubPtr2-doubPtr1 is 1
p1 = 0x7FFF5C93D4B0
p2 = 0x7FFF5C93D4B4
p2-p1 is 4
intPtr1 = 0x7fff5c93d4b0
intPtr1 = 0x7fff5c93d4b4
intPtr2-intPtr1 is 1
Remember Polya's advice in How to Solve It:
Try to treat symmetrically what is symmetrical and do not destroy wantonly any natural symmetry.