I was interested in accessing portions of memory I had allocated to get a better understanding of things, lets say I allocate 10 bytes with malloc and printf("%p", &foo) returns 0xff0a, would I be able to allocate 0xff0a->0xff1a (my hexadecimal math is bad at the moment) and access any one of those individual bytes?
I think I recall being used the keyword volatile along with a memory address for this, I am not sure what that code was able to do though..
I guess what I mean is how do I access a random byte in memory, cast as a char or integer that I can store in a pointer for accessing later on.
I'll assume you want to access a single byte from a multi-byte type such as an int or a short. The common idiom is to cast the address to a char* and deference that like so:
#include <stdio.h>
int main(void)
{
int foo = 0xDEADBEEF;
int i;
for (i = 0; i < 4; i++) {
printf("byte %d of foo is x%02X\n", i, *((unsigned char*)&foo + i));
}
return 0;
}
Output
$ ./a.out
byte 0 of foo is xEF
byte 1 of foo is xBE
byte 2 of foo is xAD
byte 3 of foo is xDE
Note The reason it looks backwards is due to x86 being little endian
printf("%p", &foo) prints the address of the pointer variable foo, not the address contained in foo (which is the one that came from malloc). You actually want:
printf("%p", (void *)foo);
If you wish to access the 10 bytes in memory pointed to by foo, you can simply use:
char *p = foo;
and then access p[0] through p[9].
If you allocate 10 bytes from 0xff0a, the address range is: 0xff0a to 0xFF14.
volatile forces the compiler to grab the stored value at that location every time. This has uses in hardware programming and multi-threaded applications.
This example stores the address of the int x into the pointer p:
int x = 5;
int * p = &x; //assign address of (operator &) x into a pointer
printf("%d\n", *p); // will display 5
You may want to use a union in order to always apply the same bunch of code to loop over the bytes area of your variable. The member 'byte' will always point to the same address as the others. You can include it into a struct in order to keep the size along with the union. A the end, you just call a function to print out or check the content of a bunch of memory...
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
union byteMap {
char* addressString;
void* addressInt;
unsigned char* byte;
};
struct structByteMap {
size_t size;
union byteMap map;
};
int main (int argc, char* argv[]) {
struct structByteMap map;
if (argc > 1) {
int temp = strtoimax(argv[1], NULL, 10);
map.map.addressInt = &temp;
map.size = sizeof(int);
} else {
map.map.addressString = "HELLO, YES HELLO";
map.size = strlen(map.map.addressString);
}
for (int i = 0; i < map.size; i++) {
printf("byte %d of param is x%02X\n", i, *(map.map.byte + i));
}
}
Related
I wrote a pretty simple piece of C code:
int main(void) {
void *area = malloc(2 * sizeof(int));
unsigned int *int_one = (unsigned int *) area;
unsigned int *int_two = ((unsigned int *) area) + 3;
*int_two = 4293422034;
*int_one = 2;
printf("%u\n%u\n", *int_two, *int_one);
return 0;
}
sizeof(int) is 4 on my machine. Per my understanding, shouldn't the modification of memory at address int_one have an effect on the value stored at address int_two?
Modifying *int_one alters the first 4 bytes of mem. address area (perhaps not all 4, but enough to warrant the result I'm expecting?), and the integer at address int_two starts at the last byte of integer int_one.
So, shouldn't changing memory at int_one have an effect on memory at int_two?
Yet the printf call produces 4293422034 and 2 respectively.
I made sure to use unsigned variables to avoid confusion around 2s complement and negative values, and to use a small value for *int_one to warrant the change of its last byte (don't know if this is right?)
What am I not getting?
Operator '+', when applied to a pointer, increases the pointer n times the size of the object it points to. So increasing an int* by 3 does not add 3 bytes but 3*sizeof(int) bytes.
Pointer arithmetic is scaled by the size of the type the pointer points at. (sizeof(unsigned int) in your case). You'd need to cast to (char*) before adding 3 if you want to increase the address by 3 bytes, but converting that to an unsigned* pointer would incur undefined behavior by violating alignment requirements (6.3.2.3p7) and dereferencing the pointer would make the program even "more undefined" by violating strict aliasing rules (6.5p7).
To realy do this kind of type punning right, you'd need to use memcpy (or unions).
Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
void *area = malloc(2 * sizeof(int));
if(!area) return EXIT_FAILURE;
unsigned int *int_one_p = area;
void *int_two_p = (((char*) area) + 3); /*saving this to an (unsigned*) would be UB*/
memcpy(int_two_p,&(unsigned){4293422034},sizeof(unsigned));
memcpy(int_one_p,&(unsigned){2},sizeof(unsigned));
unsigned one,two;
memcpy(&one,int_one_p, sizeof(one));
memcpy(&two,int_two_p, sizeof(two));
printf("%u\n%u\n", two, one);
return 0;
}
I have the following code
#include <stdlib.h>
#include <stdio.h>
typedef struct {
int age;
} data;
int storage (data **str) {
*str = malloc(4 * sizeof(**str));
(*str)[0].age = 12;
return 0;
}
int main() {
data *variable = NULL;
storage(&variable);
return 0;
}
I took it from a website source. I think I have a misunderstanding about a basic pointer to pointer concept because here in this code, we have a pointer to a struct, variable, and we are passing this to storage function, which expects pointer to pointer of struct type. After memory was malloced, I don't understand this assignment
(*str)[0].age = 12
It was assigned as if, str was of (*)[] type. I dont understand how this assignment works, like str is now a pointer to an array of structs?
First, a note about C syntax for dereferencing pointers:
a[b] is equivalent to *(a + b), is equivalent to *(b + a), is equivalent to b[a].
Now, in
int main() {
data *variable = NULL;
storage(&variable);
return 0;
}
variable is of type "pointer to data", therefore its address &variable is of type "pointer to pointer to data". This is passed to int storage(data **str), and is the correct type for the argument str.
int storage (data **str) {
*str = malloc(4 * sizeof(**str));
(*str)[0].age = 12;
return 0;
}
Here, str is dereferenced, yielding an lvalue of type data * designating the same object as main()s variable. Since it is an lvalue, it can be assigned to.
malloc() allocates memory without declared type, large enough (and sufficiently aligned) to contain four contiguous objects of type data. It returns a pointer to the beginning of the allocation.
(*str)[0] is now an lvalue designating an object of type data, and by accessing the memory malloc() allocated through this expression, the effective type of the memory becomes data. (*str)[0].age = 12; assigns the value 12 to the age-member of this object, leaving the other members of the struct (and the rest of the allocated memory) uninitialized.
It can be illustrated like this
main:
data* variable = NULL; //variable is a pointer
storage(&variable) //the address of the pointer is &variable
the storage(data**) allows the function to take the address
of the pointer variable
this allows storage to change what variable points to
In storage, the following statement changes what variable points to by dereferencing (since we did pass the address of variable):
*str = malloc(4 * sizeof(**str) )
The malloc allocates a memory block containing four structs (which each has the size sizeof(struct data) bytes)
A struct is just a convenient way to access a part of memory, the
struct describes the layout of the memory. The statement
(*str)[0].age = 12;
is the equivalent of
data* d = *str;
d[0].age = 12;
or you can write it as a ptr with offset:
data* d = *str;
*(d + 0).age = 12;
edit: a clarification about malloc
malloc returns a block of memory allocated in bytes, the return type of malloc is void* so per definition it has no type and can be assigned to a pointer of arbitrary type:
T* ptr = malloc(n * sizeof(T));
After the assignment to ptr, the memory is treated as one or more elements of type T by using the pointer T*
Well, I think your code is simply identical to:
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
int age;
} data;
int main()
{
data *variable = NULL;
variable = malloc(4 * sizeof(*variable));
*(variable + 0).age = 12;
return 0;
}
So variable is malloced with a block of memory, which is large enough to hold 4 datas(from variable[0] to variable[3]). That's all.
This piece of code might help illustrate what's happening, the really interesting line is
assert(sizeof(**str2) == sizeof(data));
Your numbers may vary form mine but first lets create a struct with a rather dull but hard to fake size for testing purposes.
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct {
uint8_t age;
uint8_t here_as_illustartion_only[1728];
} data;
int main() {
data str;
data * str1 = &str;
data ** str2 = &str1;
printf("sizeof(str) =%*zu\n", 5, sizeof(str));
printf("sizeof(str1) =%*zu\n", 5, sizeof(str1));
printf("sizeof(str2) =%*zu\n", 5, sizeof(str2));
printf("sizeof(*str2) =%*zu\n", 5, sizeof(*str2));
printf("sizeof(**str2) =%*zu\n", 5, sizeof(**str2));
assert(sizeof(**str2) == sizeof(data));
return 0;
}
On my machine this prints the following
sizeof(str) = 1729
sizeof(str1) = 8
sizeof(str2) = 8
sizeof(*str2) = 8
sizeof(**str2) = 1729
Note the size of the pointer to pointer ie sizeof(**) is the dull number we're looking for.
I really don't know how to ask it more properly, but I will try to explain my problem.
Lets say we have the following:
int *ptr = foo(&ptr);
This for me I believe it means that, there is a declaration with initialization to the function foo with the pointer it self used as function argument.
Now the following:
int *ptr = foo();
I think is the same, but without any function argument, which means that, the function foo doesn't take any arguments.
Now lets take a look at the following two programs:
Program 1:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 3
int *foo(int **ptr);
int main(void){
int *ptr = foo(&ptr);
for (int i=0 ; i<SIZE ; i++){
*(ptr + i) = i + 1;
}
for (int j=0 ; j<SIZE ; j++){
printf("%d\n",*(ptr + j));
}
free(ptr);
}
int *foo(int **ptr){
*ptr = malloc(SIZE * sizeof(*ptr));
if(*ptr == NULL){
printf("Error, malloc\n");
exit(1);
}
return *ptr;
}
Program 2:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 3
int *foo(void);
int main(void){
int *ptr = foo();
for (int i=0 ; i<SIZE ; i++){
*(ptr + i) = i + 1;
}
for (int j=0 ; j<SIZE ; j++){
printf("%d\n",*(ptr + j));
}
free(ptr);
}
int *foo(void){
int *ptr = malloc(SIZE * sizeof(*ptr));
if(ptr == NULL){
printf("Error, malloc\ņ");
exit(1);
}
return ptr;
}
What is the differences/benefits of program 1 or program 2.
Is the pointer in the first or second program somehow different affected? Or is there any reason of using program 1 or program 2 ?
I'm asking, because the way how to program behaves looks that program 1 and program 2 are the same.
EDIT:
I know that the fist program has the pointer ptr modified by the foo function and in the second one I declare it inside the Function foo, but this is not my Question.
The only practical difference between the programs is that the first one could allocate double the amount of memory compared to the second.
In the first program you use *ptr to get the size, but *ptr is of type int * which on a 64-bit system is usually 64 bits. In the second program *ptr is an int and the size of an int is usually 32 bits on both 32 and 64 bit systems.
Since the first program emulates passing by reference, you could use it without using the returned pointer, and in fact it doesn't have to return a value at all and could be declared as returning void. Which one is preferred is a personal choice, I personally prefer the second alternative, but it also depends on use-case.
In first program, you alloc SIZE * sizeof(int *) bytes, and use that memory as if it was SIZE * sizeof(int) long. That means that if you had sizeof(int *) < sizeof(int) you would run in a buffer overflow.
Another problem is that in int *ptr = foo(&ptr); you are modifying the variable ptr twice in one single expression, which is bad because you cannot know which one occurs first. But as you normally write same value it should be ok here.
Another difference is that in first program, you set the value of ptr to NULL in case of allocation error before calling exit(), while in the second, the variable remains uninitialized. But as you use exit in that case, the ptr variable immediately vanishes and could not be used even in an atexit registered function.
IMHO provided you fix first program by using *ptr = malloc(SIZE * sizeof(int)); or *ptr = malloc(SIZE * sizeof(**ptr));, the 2 versions behave the same.
i have this array where i am trying to access its elements by incrementing ptr, as suggested here Trying to find different methods of accessing array elements?...i must be doing something stupid...please help me!
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
char *p1 = "Cnversions";
char *p2 = "Divided";
char *p3 = "Plain";
char *p4 = "Solid";
char *arr[3];
arr[0] = p1;
arr[1] = p2;
arr[2] = p3;
arr[3] = p4;
for(i=0;i<=3;i++)
{
printf("string at arr[%d] is: %s\n",i,*arr);
arr++;
}
return 0;
}
An array like arr is located at a specific spot in memory, so it makes no sense to increment arr (what does it mean to increment an array?)
Instead, you will need to create a pointer to the start of the array and increment the pointer:
char **ptr = arr;
for(i=0; i<4; i++) {
printf("arr[%d] = %s\n", i, *ptr);
ptr++;
}
(Note also that you need to make arr four elements big, i.e. char *arr[4], to accommodate the four string pointers you put in it.)
Remember that although we tend to think of double pointers as arrays, all the compiler sees them as are pointers. When you increment a pointer, it adds a value to the address of the pointer equal to the size of the data type it's pointing at. For example:
int *p;
p = (int *) malloc(sizeof(int));
p is pointing to an int, so the size of p's pointed data is (typically) 4 bytes. This means when you increment p, it will be pointing at a location 4 bytes greater than where it was before.
The type of arr is a char**, meaning that it's a pointer to a pointer to a char. Pointers on most machines these days are 8 bytes. So when you incrementing arr, you are effectively telling the computer to set arr to point to an address 8 bytes higher than what it was at before. In the case of arr, this is an illegal address, so you'll get some kind of crash.
Ignoring padding/alignment issues and given the following struct, what is best way to get and set the value of member_b without using the member name.
struct mystruct {
int member_a;
int member_b;
}
struct mystruct *s = malloc(sizeof(struct mystruct));
Put another way; How would you express the following in terms of pointers/offsets:
s->member_b = 3;
printf("%i",s->member_b);
My guess is to
calculate the offset by finding the sizeof the member_a (int)
cast the struct to a single word pointer type (char?)
create an int pointer and set the address (to *charpointer + offset?)
use my int pointer to set the memory contents
but I get a bit confused about casting to a char type or if something like memset is more apropriate or if generally i'm aproching this totally wrong.
Cheers for any help
The approach you've outlined is roughly correct, although you should use offsetof instead of attempting to figure out the offset on your own. I'm not sure why you mention memset -- it sets the contents of a block to a specified value, which seems quite unrelated to the question at hand.
Here's some code to demonstrate how it works:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
typedef struct x {
int member_a;
int member_b;
} x;
int main() {
x *s = malloc(sizeof(x));
char *base;
size_t offset;
int *b;
// initialize both members to known values
s->member_a = 1;
s->member_b = 2;
// get base address
base = (char *)s;
// and the offset to member_b
offset = offsetof(x, member_b);
// Compute address of member_b
b = (int *)(base+offset);
// write to member_b via our pointer
*b = 10;
// print out via name, to show it was changed to new value.
printf("%d\n", s->member_b);
return 0;
}
The full technique:
Get the offset using offsetof:
b_offset = offsetof(struct mystruct, member_b);
Get the address of your structure as a char * pointer.
char *sc = (char *)s;
Add the add the offset to the structure address, cast the value to a pointer to the appropriate type and dereference:
*(int *)(sc + b_offset)
Ignoring padding and alignment, as you said...
If the elements you're pointing to are entirely of a single type, as in your example, you can just cast the structure to the desired type and treat it as an array:
printf("%i", ((int *)(&s))[1]);
It's possible calculate the offset based on the struct and NULL as reference pointer
e.g " &(((type *)0)->field)"
Example:
struct my_struct {
int x;
int y;
int *m;
int *h;
};
int main()
{
printf("offset %d\n", (int) &((((struct my_struct*)0)->h)));
return 0;
}
In this particular example, you can address it by *((int *) ((char *) s + sizeof(int))). I'm not sure why you want that, so I'm assuming didactic purposes, therefore the explanation follows.
The bit of code translates as: take the memory starting at address s and treat it as memory pointing to char. To that address, add sizeof(int) char-chunks - you will get a new address. Take the value that the address thus created and treat it as an int.
Note that writing *(s + sizeof(int)) would give the address at s plus sizeof(int) sizeof(mystruct) chunks
Edit: as per Andrey's comment, using offsetof:
*((int *) ((byte *) s + offsetof(struct mystruct, member_b)))
Edit 2: I replaced all bytes with chars as sizeof(char) is guaranteed to be 1.
It sounds from your comments that what you're really doing is packing and unpacking a bunch of disparate data types into a single block of memory. While you can get away with doing that with direct pointer casts, as most of the other answers have suggested:
void set_int(void *block, size_t offset, int val)
{
char *p = block;
*(int *)(p + offset) = val;
}
int get_int(void *block, size_t offset)
{
char *p = block;
return *(int *)(p + offset);
}
The problem is that this is non-portable. There's no general way to ensure that the types are stored within your block with the correct alignment, and some architectures simply cannot do loads or stores to unaligned addresses. In the special case where the layout of your block is defined by a declared structure, it will be OK, because the struct layout will include the necessary padding to ensure the right alignment. However since you can't access the members by name, it sounds like this isn't actually what you're doing.
To do this portably, you need to use memcpy:
void set_int(void *block, size_t offset, int val)
{
char *p = block;
memcpy(p + offset, &val, sizeof val);
}
int get_int(void *block, size_t offset)
{
char *p = block;
int val;
memcpy(&val, p + offset, sizeof val);
return val;
}
(similar for the other types).