Have a look at my code :
#include <stdio.h>
#include <limits.h>
int main (int argc, const char *argv[]) {
typedef unsigned char byte;
byte *pointer;
byte b1=1;
byte b2=2;
int i1 =4;
int i2 =0x12345678;
byte b3=5;
byte b4=6;
byte b5=7;
byte b6=9;
//pointer = &b6;
pointer = (byte*)&i2;
printf("pointer has value %p\n", pointer);
printf("the byte it points to contains %x\n", *pointer);
pointer = pointer + 1;
printf("the byte it points to contains %x\n", *pointer);
pointer = pointer + 1;
printf("the byte it points to contains %x\n", *pointer);
pointer = pointer + 1;
printf("the byte it points to contains %x\n", *pointer);
pointer = pointer + 1;
printf("the byte it points to contains %x\n", *pointer);
pointer = pointer + 1;
printf("the byte it points to contains %x\n", *pointer);
pointer = pointer + 1;
printf("the byte it points to contains %x\n", *pointer);
pointer = pointer + 1;
printf("the byte it points to contains %x\n", *pointer);
pointer = pointer + 1;
printf("the byte it points to contains %x\n", *pointer);
pointer = pointer + 1;
printf("the byte it points to contains %x\n", *pointer);
pointer = pointer + 1;
printf("the byte it points to contains %x\n", *pointer);
pointer = pointer + 1;
printf("the byte it points to contains %x\n", *pointer);
pointer = pointer + 1;
*pointer = 255;
printf("the byte it points to contains %x\n", *pointer);
pointer = pointer + 1;
*pointer = 45;
printf("the byte it points to contains %x\n", *pointer);
pointer = pointer + 1;
*pointer = 34;
printf("the byte it points to contains %x\n", *pointer);
//printf("How big is int in this machine? %d\n", INT_MAX);
//insert code here ...
printf (" b1 (%p) = %x\n", &b1, b1);
printf (" b2 (%p) = %x\n", &b2, b2);
printf (" i1 (%p) = %d\n", &i1, i1);
printf (" i2 (%p) = %x\n", &i2, i2);
printf (" b3 (%p) = %x\n", &b3, b3);
printf (" b4 (%p) = %x\n", &b4, b4);
printf (" b5 (%p) = %x\n", &b5, b5);
printf (" b6 (%p) = %x\n", &b6, b6);
return 0;
}
The line saying *pointer = 255; , maybe 40th line , the compiler blows , or the code stops working , saying this
if I make , *pointer = 255 or *pointer = 254
and if I set any other values except this , my program works well i.e.
*pointer = 4556 or *pointer = 45
Or in case of any other arbitrary values as well , it runs without any blow . Please tell me about this behaviour of addresses.
Source : Prof. Richard Buckland , I'm exploring all these due to his guidance.
The compiler has nothing to do with this. You're trying to dereference and assign to an invalid pointer, to memory you do not own.
Doing just ++pointer; *pointer = <value>; is dangerous as pointer points to a single value of type int, so ++pointer (or adding any number except zero to it) is moving the pointer to some memory location you probably don't have permission to write to or even access. Hence the errors.
Related
I'm a beginner in C language.
I'm practicing several codes on my own, while doing I came across this algo.
Below is the code.
#include <stdio.h>
int main() {
int a = 1;
printf("value of a = %d\n", a);
printf("address of a = %u\n", &a);
int *p;
printf("value of p = %d\n", p);
p = 2;
printf("value of p = %d\n", p);
a = a+p;
printf("value of addition =%d\n", a);
return 0;
}
**OUTPUT**
value of a = 1
address of a = 947268620
value of p = 947268880
value of p = 2
value of addition =6
Why I'm getting 6 instead of 3,
is there anything I'm missing on result
because you're not setting the value of the address p is pointing to to 2, you're assigning/pointing the variable int *p to the value 2 in memory, which is not memory you should be accessing. Instead, you need to point p to memory you have access to (a variable or dynamically allocated memory) and dereference the pointer using *p = 2 which accesses the value that p is pointing to. Your code should instead look like this
int a = 1;
printf("value of a = %d\n", a);
printf("address of a = %u\n", &a);
int _p = 0;
int *p = &_p;
printf("value of p = %d\n", *p);
*p = 2;
printf("value of p = %d\n", *p);
a = a+*p;
printf("value of addition =%d\n", a);
One has to "walk right past" the compiler warnings about that code.
Below is the same code with coercive casting to silence some of the warnings. An additional calculation and print statement should make obvious how the compiler deals differently with the values of pointers (memory addresses) and the values of integers.
#include <stdio.h>
int main() {
int a = 1;
printf("value of a = %d\n", a);
printf("address of a = %u\n", &a); // incorrect format spec for printing address
int *p;
printf("value of p = %d\n", p); // uninitialised and undefined behaviour
p = (int*)2; // coercive casting integer to pointer-to-integer
printf("value of p = %d\n", p); // incorrect format spec for a memory address
a = (int)(a + p); // coercive casting address to integer
printf("value of addition =%d\n", a);
// ADDED these statements
a = 1; // restore value of a
a = a + (int)p; // coercive casting address to integer
printf("value of addition =%d\n", a);
return 0;
}
value of a = 1
address of a = 1703728
value of p = 1
value of p = 2
value of addition =6
value of addition =3 <== was this the expected result?
C will try to do its best with explicit program statements.
"Garbage in, garbage out."
Write correct code, not 'cute' code.
Thanks for your response Awayy. Helpful.
I got the output I needed. But the thing I need to know is, in what logic
the line a = a+p; gave 6 as result in my code.
As u said I'm assigning 2 as address to p(which is p = 0x2).
So, when the addition happens a = 1 and p = 0x2 which has a random value that we don't know that is because I'm not assigning a particular address to the pointer variable p. It results 6 I'm I right.
Trying to double dereference and print them (TOP TWO ARE EXAMPLES):
printf ("a's value = %d \n", a) ;
printf ("a's address = %p \n", &a) ;
printf ("a_ptr_ptr deref'ed defer'ed =d% \n",
What would go after the \n", for a_ptr_ptr deref'ed defer'ed
If you want the address of the address of a, you're going to have to store a's address in a pointer variable, and take the address of that. But having done so, yes, you can double-dereference that pointer with **, and get a's value back. Something like this:
int a = 5;
int *ip = &a;
int **ipp = &ip;
printf("ipp = %p\n", ipp);
printf("*ipp = %p, ip = %p, &a = %p\n", *ipp, ip, &a);
printf("**ipp = %d, *ip = %d\n", **ipp, *ip);
Theoretically you can continue this as long as you like:
int ***ippp = &ipp;
int ****ipppp = &ippp;
int *****ippppp = &ipppp;
printf("*****ippppp = %d\n", *****ippppp);
But by now this is mostly a game; there's no practical use in a real C program for a 5-level pointer, and at some point (after 8 or 10 levels, I think) the compiler's allowed to say "All right, enough, game over!".
I'm running this program:
#include<stdio.h>
void main(){
int num = 1025;
int *poinTer = #
char *pointChar = poinTer+1;
*pointChar = 'A';
printf("Size of Integer: %d\n", sizeof(int));
printf("Address: %d, Value: %d\n", poinTer, *poinTer);
printf("Address: %d, Value: %c\n", poinTer+1, *(poinTer+1));
printf("Address: %d, Value: %c\n", pointChar, *pointChar);
}
*pointChar and *(poinTer+1) should output same result but the output that I'm getting is different. *pointChar is not outputting any value:
Size of Integer: 4
Address: 1704004844, Value: 1025
Address: 1704004848, Value: A
Address: 1704004673, Value:
What's happening here?
When you perform + 1 on a pointer, it does not necessarily increase the memory address by 1. It increases it by sizeof(*ptr).
In this case, poinTer + 1 is equivalent to (char*)poinTer + sizeof(int). This actually makes dealing with arrays much easier.
The good old fashioned ptr[i] is syntactic sugar for *(ptr + i). So, if you have an array of 10 integers, ptr[4] will point to the 5th element rather than 4 bytes away from the base address (since integers are generally 4 or 8 bytes).
So what you've actually done is:
Create an int (num) on the stack and gave it the value 1025
Created a int*(poinTer) on the stack and assigned it the memory address of num
Incremented the pointer by sizeof(int) (which unintentionally points to a different memory address), then cast it to a char* and assigned it to a new pointer.
Assigned the byte pointed to at this new memory address the value 65 ('A').
This is probably what you wanted to do:
#include<stdio.h>
void main(){
int num = 1025;
int *poinTer = #
char *pointChar = (char*)poinTer + 1;
*pointChar = 'A';
printf("Size of Integer: %d\n", sizeof(int));
printf("Address: %d, Value: %d\n", poinTer, *poinTer);
printf("Address: %d, Value: %c\n", (char*)poinTer + 1, *((char*)poinTer+1));
printf("Address: %d, Value: %c\n", pointChar, *pointChar);
}
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.
I am making an error somewhere at the last line. It is not showing the correct value at the address.
/* an array with 5 elements */
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double backup[5];
double *p;
double address;
int i = 0;
memcpy(&backup, &balance, sizeof(balance));
p = backup;
/* output each array element's value */
printf( "Array values using pointer\n");
for ( i = 0; i < 5; i++ )
{
//printf("*(p + %d) : %f\n", i, *(p + i) );
printf("&p[%d] : %f\n", i, p[i]);
printf("&p[%d] : address: %p\n", i, (void*)(&p+i));
}
int offset = 4;
printf("Contents of &p[%d] : address: %x is %f\n", offset, ((&p)+(offset)), p[offset]);
double* newPointer;
newPointer = ((&p)+(offset));
printf("The content again: %f at address: %x\n", *(newPointer), newPointer);
// output is incorrect
The content again: 0.000000 at address: 28feec
Just from the typing I'd say, this:
newPointer = ((&p)+(offset));
should be:
newPointer = p + offset;
This:
((&p)+(offset))
returns a double **, as you take the address of a double *. Adding to this any offset still leaves it a double **. This you surely would not like to assign to a double *.
I am making an error somewhere at the last line
This mistake of taking the address of p is also made at several other location before "the last line".
And to point this out again:
To print out a pointer's value cast it to void * (if it isn't one already) and use the p conversion specifier:
printf("The content again: %f at address: %p\n", *newPointer, (void *) newPointer);
Using x or d or i offers you a fair chance to lose half of the address' significant bits.
memcpy(backup, balance, sizeof(balance));
p = backup;
printf( "Array values using pointer\n");
for ( i = 0; i < 5; i++ ){
//printf("*(p + %d) : %f\n", i, *(p + i) );
printf("p[%d] : %f\n", i, p[i]);
printf("p[%d] : address: %p\n", i, (void*)(p+i));
}
int offset = 4;
printf("Contents of p[%d] : address: %p is %f\n", offset, p+offset, p[offset]);
double* newPointer;
newPointer = p+offset;
printf("The content again: %f at address: %p\n", *newPointer, newPointer);
double *p; Here p itself is a address locating pointer p. So while adding an offset just do, p + offset
Here is an diagrammatic representation how pointer behaves. p is a pointer pointing/holding address of backup. So p has address 0x2000 but &p is address of p which is 0x3000. Therefore &p + offset leads to different memory location which is happening in your case.
p backup
+------+ +------+
| | | |
|0x2000|------------>|0x1000|
| | | |
+------+ +------+
0x3000 0x2000
Also use,
%p format specifier for pointer addresses.