After using malloc() to initialize 5000 bytes of memory, how would I reference the bytes in this memory space? For example, if I need to point to a starting location of data within the memory, how would I go about that?
EDIT: Does it matter what I use to point to it? I mean I am seeing people use bytes/int/char? Is it relevant?
Error I get:
You can use the subscript array[n] operator to access the index you are interested in reading/writing, like so:
uint8_t* const bytes = (uint8_t*)malloc(5000);
bytes[0] = UINT8_MAX; // << write UINT8_MAX to the first element
uint8_t valueAtIndexZero = bytes[0]; // << read the first element (will be UINT8_MAX)
...
free(bytes), bytes = 0;
char * buffer = malloc(5000);
buffer[idx] = whatever;
char * p = buffer + idx;
*p = whatever;
Malloc doesn't initialize the bits allocated by it. Use calloc() rather.
int *p = malloc (5000); // p points to the start of the dynamically allocated area.
As has been mentioned by others, you could do something like this:
int nbytes = 23; // number of bytes of space to allocate
byte *stuff = malloc(nbytes * sizeof stuff[0]);
stuff[0] = 0; // set the first byte to 0
byte x = stuff[0]; // get the first byte
int n = 3;
stuff[n] = 0; // set the nth byte to 0
x = stuff[n]; // nth byte, or in the case of some other type, nth whatever - just make sure it's a safe value, from 0 (inclusive) to the number (nbytes here) of things you allocated (exclusive)
However, a couple of things to note:
malloc will not initialise the memory, but calloc will (as mentioned by Prasoon Saurav)
You should always check to see if the memory allocation failed (see below for an example)
int nbytes = 23; // or however many you want
byte *stuff = malloc(nbytes * sizeof stuff[0]);
if (NULL == stuff) // memory allocation failed!
{
//handle it here, e.g. by exiting the program and displaying an appropriate error message
}
stuff[0] = 0; // set the first byte to 0
byte x = stuff[0]; // get the first byte
int n = 3;
stuff[n] = 0; // set the nth byte to 0
x = stuff[n]; // nth byte, or in the case of some other type, nth whatever
malloc() returns a pointer to the allocated memory:
typedef unsigned char byte;
byte * mem = malloc( 5000 );
byte val = mem[1000]; /* gets the 1000th byte */
After using malloc() to initialize 5000 bytes of memory, how would I
reference the bytes in this memory space? For example, if I need to
point to a starting location of data within the memory, how would I go
about that?
Does it matter what I use to point to it? I mean I am seeing people
use bytes/int/char? Is it relevant?
as you have seen malloc allocates a block of memory counted in bytes, you can assign a pointer to that block and depending on the pointer type the compiler knows how to reference individual elements:
unsigned char *memblob = malloc( 1024 );
short* pshort = (short*)memblob;
now if you reference the second short value i.e. *(pshort + 1) or pshort[1] the compiler knows that it needs to add 2 bytes (sizeof(short)) in order get the next element.
float* pfloat = (float*)memblob;
now if you reference the second float value i.e. *(pfloat + 1) or pfloat[1] the compiler knows that it needs to add 4 bytes (sizeof(float)) in order get the next element.
same with own defined data types:
typedef struct s
{
short a;
long b;
} mystruct_t;
mystruct_t* pstruct = (mystruct_t*)memblob;
pstruct + 1 accesses the struct at offset sizeof(mystruct_t)
so it is really up to you how you want to use the allocated memory
Related
so I want to create my own malloc. I was given a library that gives me my own sbrk() function to increase my heap which basically uses malloc() to create "simulated" virtual memory.
Anyway, I stumbled across problems when implementing my free() method. Resulting in pointer confusion and questioning the whole existence of the universe. I thus create an example code.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t *seg_lists[4] = {NULL};
// Allocate two memory blocks of size 2
// First 8 bytes hold the size
// the last 2 8 bytes partition hold the data
void *mem1 = malloc(3*sizeof(size_t));
void *mem2 = malloc(3*sizeof(size_t));
// Set size fields
*(size_t *)mem1 = 2;
*(size_t *)mem2 = 2;
// Move pointers to start of body
mem1 = (size_t *)mem1 + 1;
mem2 = (size_t *)mem2 + 1;
// Set data to body of mem1
size_t* mem1_first = (size_t *)mem1;
size_t* mem1_second = (size_t *)mem1 + 1;
*mem1_first = 100;
*mem1_second = 200;
// Set data to body of mem2
size_t* mem2_first = (size_t *)mem2;
size_t* mem2_second = (size_t *)mem2 + 1;
*mem2_first = 300;
*mem2_second = 400;
// Output bodies of mem1 and mem2
printf("mem1=[%zu|%zu|%zu]\n", *((size_t *)mem1-1), *mem1_first, *mem1_second);
printf("mem2=[%zu|%zu|%zu]\n", *((size_t *)mem2 - 1), *mem2_first, *mem2_second);
// We first free mem2 and add it to the seg_list with index 1
size_t *head = seg_lists[1];
seg_lists[1] = mem2;
*(size_t *)mem2 = (size_t)head;
// We now want to free mem1 and add it to the list.
// I.e. we set the head to mem1 and the first 8 bytes of the body of
// mem2 to the address of mem1
head = seg_lists[1];
seg_lists[1] = mem1;
*(size_t *)mem1 = (size_t)head;
// Follow first entry in seg_lists[1] and print the 2nd 8 bytes of it's body
size_t *first = *seg_lists[1];
printf("*first=%zu\n", *(first+1));
}
So first I create two memory blocks of size 2. I.e. they can hold up to 16 bytes of data. The first 8 bytes are used to store the size. So it looks like this:
mem1=[2|100|200]
mem2=[2|300|400]
Next I want to free both memory blocks. The address of the next free block should be saved in the first 8 bytes of the body of previous bloc whereas the last should always point to NULL.
After freeing mem1, we want seg_list[1] point to the address of mem1 and the first 8 bytes of the body of mem1 to hold NULL.
After freeing mem2, we want seg_list[1] to point to the address of mem2 and the first 8 bytes of the body of mem2 should hold the address of mem1.
Now, I did the "save address of X in the first 8 bytes of the body of Y" by actually saving the hex value of the address in those bytes.
Now someone kept trying to tell me that's wrong. I shouldn't do that. I can't safe the address as a value but I can't see why I couldn't. It obviously works and for me, memory just holds data. An address is a hex value which I can store as plain data and then just treat it like however I want.
So is it really that bad what I'm doing here? Shouldn't I safe an address as "plain data"?
So, to start off I've already looked at a few questions including this one and none of them seem to help.
I'm simply trying to write a function that extends the size of an array using realloc().
My code currently looks like this:
unsigned char *xtnd = malloc(4);
xtndc(&xtnd, 4);
// sizeof(*xtnd) should now be 8
void xtndc ( unsigned char ** bytesRef , uint8_t count ) {
*bytesRef = realloc(*bytesRef, (sizeof(**bytesRef)) + count);
}
But no matter what I do it seems that the size of xtnd is always 4. After running xtndc() on it it should now be 8 bytes long.
Any suggestions?
The type of **bytesRef is unsigned char, so sizeof(**bytesRef) is 1. sizeof doesn't keep track of dynamic allocations, it's a compile time tool that gives you the size of a type, in this case unsigned char.
You have to keep track of the array size manually to calculate the new required size.
Your program does in fact change the size of the memory block. It changes the size of your original memory block from 4 bytes to 5 bytes. It changes to 5 bytes because you are essentially doing sizeof(unsigned char) + 4 which 1 + 4 = 5. If you want to double the size instead, do count*sizeof(unsigned char) + count. There are two points to be noted here:
The sizeof function returns the size of the data type, not the size of the allocated bytes. There is no way to know the size of the dynamically allocated memory.
The function realloc (and malloc and calloc as well) is not always guaranteed to return the requested reallocation. It may or may not succeed all the time.
I fixed the problem with the following code.
typedef struct CArrPtr {
unsigned char* ptr;
size_t size;
} CArrPtr;
void xtndc ( CArrPtr *bytesRef, uint8_t count );
. . .
CArrPtr xtnd = { .ptr = malloc(4), .size = 4 };
xtndc( &xtnd, 4 );
// xtnd.size is now 8 bytes
. . .
void xtndc ( CArrPtr *bytesRef, uint8_t count ) {
unsigned char *nptr;
if((nptr = realloc(bytesRef->ptr, bytesRef->size + count)) != 0)
{
bytesRef->ptr = nptr;
bytesRef->size = bytesRef->size + count;
}
}
As I am somewhat new to C, what I learned from this is that malloc specifically creates a pointer to a memory block, but you have no direct access to information about the memory block. Instead, you must store the size of the array that you created with malloc somewhere as well.
Since in the past I'd been initializing arrays with unsigned char arr[size]; and then using sizeof on it, I was under the impression that sizeof returned the size of the array, which is of course wrong as it gives you the size of a type.
Glad I could learn something from this.
sizeof is used to calculate size of data type or array. Pointer and array are very similar, but they are different things. For int *ap, sizeof(ap) will return 4 on x86, sizeof(*ap) will return 4; for int a[10], sizeof(a) will return 40.
sizeof expression is processed at compile time, so it will be a constant written into the executable file before you run the program.
malloc and realloc don't maintain size.
If realloc succeeds, it will reallocate the requested size. So you don't need to check the size after realloc returns, but you should check the return value of realloc to ensure that realloc succeeds.
I would like to allocate memory for a buffer that will contain, via memcpy in the future, a struct that contains a pointer that has been previously dynamically allocated memory.
That is, I have a struct
struct test_struct {
int num;
char *values;
};
Where test_struct.values contains num amount of strings of length LENGTH. I know I can't get the size of memory a pointer has been allocated, so I just keep track of it via num. What is the easiest/cleanest way of getting the size of this struct?
The only solution I can come up with is something like
buf = malloc(sizeof(test_struct) + (num * LENGTH));
But I'm new to this low-level memory management stuff, so there might be something better.
If you would like to memcpy two structs then the memory in both of them must be continuous. But you would have to determine num beforehand.
struct test_struct {
int num;
char ** values;
} * TestStruct;
int _num = 0;
// find _num
TestStruct = malloc (sizeof (struct test_struct) + (sizeof(char*) * _num) + (LENGTH * _num));
TestStruct->num = _num;
TestStruct->values = &TestStruct + sizeof (struct test_struct);
for (int i = 0; i < _num; i++){
TestStruct->values[i] = &TestStruct + sizeof (struct test_struct) + (i * LENGTH);
}
The reason I changed char * to char ** is because using char * it becomes harder to access the strings after the first (I'm assuming they're null terminated). Also, after calling memcpy, you must update all the string pointers in the new struct.
To memcpy you would do this:
memcpy (buf, TestStruct->values[0], LENGTH * TestStruct->num);
But in buf, however, you would only see the first string (unless your strings are not null-terminated). You would have to increment the pointer after every null terminated character until you know, with num, that you've reached the end of the buffer.
Now that I understand more of the context of your request, consider the following.
If you're using UDP packets, you should send the data in one packet so that it arrives in the order you expect. When more than one packet is sent, it may arrive out of order. Because of this, you need to make sure the size of the data is <= 512 bytes - which is the maximum size of a UDP packet. Also, you need to make sure all the data is in contiguous memory. I'm going to assume you have your data already in the struct you've provided in this example:
// this function puts the struct in contiguous memory
int PrepareBuffer (struct test_struct TestStruct, char ** buffer){
char * cast = (char *) &TestStruct->num;
* buffer = malloc ((TestStruct->num * LENGTH) + sizeof (int));
for (int i = 0; i < sizeof (int); i++) *buffer[i] = cast[i];
for (int i = 0; i < (TestStruct->num * LENGTH); i++) *buffer[i + sizeof (int)] = TestStruct->values[i];
return 0;
}
You will have to implement another function on the receiving end that maps the buffer to struct test_struct. Also, I have omitted error checking for clarity. You should check for how big the packet is going to be before to allocate memory (it has to be <= 512). You should also check to make sure malloc returns a none-null pointer.
You should only need to allocate 4 bytes (for the integer on 32 bit linux) and 4 bytes for the char * (in 32 bit. 64 is 8).
What you're really asking though, is how do I know how much memory I need to allocate to the region pointed to by char *value. You figure this out in the wya you're doing. Then set value to the location of buf. There's a comment blow me that is the correct way if you have multiple string, and you don't want to just jam them all together in that region and have to figure out which is which yourself.
I'm assuming that you want to allocate memory for both the structure and the buffer that values points to. If so, this is correct. To point at the extra space, do buf->values = buf + 1; (this is assuming you declare buf as struct test_struct buf;
I'm having a hard time understanding this program to illustrate pointers (from http://theocacao.com/document.page/234):
Below I don't understand why:
int * currentSlot = memoryBlock
isn't using &memoryBlock. I read the comment but don't get it. What is memoryBlock putting in there that &memoryBlock wouldn't? Won't both return the pointer to the set of ints created with calloc (assuming I understand what's been done that is)? What is really in * memoryBlock after calloc?
Then here, *currentSlot = rand();, how does the dereferencing work here? I thought the dereference would stop *currentSlot from giving the value of the memory address (the reference) to the actual value (no longer a reference but the value).
#include <stdio.h>
#include <stdlib.h> // for calloc and free
#include <time.h> // for random seeding
main ()
{
const int count = 10;
int * memoryBlock = calloc ( count, sizeof(int) );
if ( memoryBlock == NULL )
{
// we can't assume the memoryBlock pointer is valid.
// if it's NULL, something's wrong and we just exit
return 1;
}
// currentSlot will hold the current "slot" in the,
// array allowing us to move forward without losing
// track of the beginning. Yes, C arrays are primitive
//
// Note we don't have to do '&memoryBlock' because
// we don't want a pointer to a pointer. All we
// want is a _copy_ of the same memory address
int * currentSlot = memoryBlock;
// seed random number so we can generate values
srand(time(NULL));
int i;
for ( i = 0; i < count; i++ )
{
// use the star to set the value at the slot,
// then advance the pointer to the next slot
*currentSlot = rand();
currentSlot++;
}
// reset the pointer back to the beginning of the
// memory block (slot 0)
currentSlot = memoryBlock;
for ( i = 0; i < count; i++ )
{
// use the star to get the value at this slot,
// then advance the pointer
printf("Value at slot %i: %i\n", i, *currentSlot);
currentSlot++;
}
// we're all done with this memory block so we
// can free it
free( memoryBlock );
}
Thank you for any help.
Below I don't understand why:
int * currentSlot = memoryBlock
isn't using &memoryBlock.
Because both memoryBlock and currentSlot are pointers to int. &memoryBlock would be the address of a pointer to int, i.e. an int **.
What is "in" memoryBlock is a pointer to a block of memory.
Then here, *currentSlot = rand();, how does the dereferencing work here?
This is a rule of C: when a dereferencing expression like this occurs on the left-hand side of an expression, the right-hand side's value is stored in the memory location pointed to by the pointer being dereferenced.
int * memoryBlock;
memoryBlock is a variable which can hold the address of a memory block of integers. The size of the memoryBlock variable is the size of an address. Typically 4 or 8 bytes (sizeof(int*)). Its type is "pointer to int".
memoryBlock = calloc ( 5, sizeof(int) );
the memoryBlock variable is assigned the address of the start of the memory block able to hold 5 integers. The memory block size is 5 * sizeof(int) bytes.
memoryBlock + 1 is the address of the second integer in the block.
memoryBlock + 5 is one passed the address of the last integer in the block.
*memoryBlock is the content of the address (the first integer). type is integer.
*(memmoryBlock + 0) = 0;
*(memmoryBlock + 1) = 1;
*(memmoryBlock + 2) = 2;
*(memmoryBlock + 3) = 3;
*(memmoryBlock + 4) = 4;
// *(memmoryBlock + 5) = 5; illegal
Assigns integers to memory block.
Subscipt form same as above.
memmoryBlock[0] = 0;
memmoryBlock[1] = 1;
memmoryBlock[2] = 2;
memmoryBlock[3] = 3;
memmoryBlock[4] = 4;
// memmoryBlock[5] = 5; illegal
&memoryBlock is the address of the memoryBlock variable. This is not the address of the callocated space. It's type is int** "pointer to pointer to integer" not int*.
int ** pmemoryBlock;
pmemoryBlock is a variable which hold the address of an address of a memory block of integers. The size of pmemoryBlock is the size of an address. Typically 4 or 8 bytes (sizeof(int**)).
pmemoryBlock = &memoryBlock;
pmemoryBlock is assigned the address of a variable which holds the address of the start of the memory block able to hold 5 integers.
*pmemoryBlock is the address of the memory block.
**pmemoryBlock is the first integer in the memory block
*((*pmemoryBlock) + 0) is the first integer in the memory block
*((*pmemoryBlock) + 1) is the seconds integer in the memory block
...
memoryBlock is an array of integers (int*). (technically a pointer to an int but since it was allocated with enough room for 10 integers you can think of it as the start of an array)
*memoryBlock is the integer that memoryBlock is pointing to (the first int in the array). While the notation looks the same as the declariation it is actually dereferencing the value. IMHO it is poorly written as it should be declared
int* currentSlot = memoryBlock;
to make it more clear that it's a pointer to an integer, but that's a style choice.
&memoryBlock is the address of the pointer.
int * currentSlot = memoryBlock;
stores the pointer to the first slot in currentSlot. The program is then generating random numbers and putting them in each of the 10 clost by incrementing currentSlot (which internally is incrementing the pointer by the length of an integer.
Hope that helps.
In the code, memoryBlock is apointer to some memory that stores integers. That is, the actual value of the variable memoryBlock is the address just allocated. If you use &memoryBlock you get the address of where the variable is stored, not what it points to.
Lets take an example:
int foo = 5;
/* the variable "foo" is stored in memory,
and that memory contains the number 5 */
int bar = 7;
/* the variable "foo" is stored in memory,
and that memory contains the number 7 */
int *foo_pointer = &foo;
/* the variable "foo_pointer" is stored in memory,
and that memory contains the address of the variable "foo" */
foo_pointer = &bar;
/* the contents of the variable "foo_pointer" is no longer the address
of where the variable "foo" is in memory, instead it is the address
of where the variable "bar" */
I hope this makes some sense, and it helps a little.
It's not supposed to use &memoryBlock, which is the (int ** (heh!)) address of the the pointer into the memory you are clearing. In other words, memoryBLock (iff it's not NULL) points to (i.e., holds the address of) the first int in the calloc( )'ed memory. To reference that cleared-to-0 memory, you use *memoryBlock.
If you ever find yourself trying to use &memoryBlock, don't: it's never the right thing to do in the code fragment you posted.
HTH. If it doesn't help, go back to K&R and study pointers some more. Maybe a lot more.
int * is a pointer, which can be dereferenced. int ** is a pointer to a pointer, which can be dereferenced twice. So what does this mean? Well, a pointer is nothing more than an integer. Memory addresses just start from zero to its max range. For 32-bit systems, its range of addressable memory is 0 to 2^32-1 (or 4294967295). Each of this address has a byte value. If you have an int *, then it will access the address 4-bytes at a time.
Also, for simplicity, let's assume this is a virtual address, you can't just access all this memory, some will be protected (system), some are not valid (not committed). To gain more memory you can ask the system to allocate more from this range. sbrk in Linux, VirtualAlloc in Windows but you will be accessing them usually through C's malloc or calloc.
Let's say, you have starting from 0x100:
0x100: 'h', 'e', 'l', 'l', 'o', '\0'
So this string, occupies memory from 0x100 to 0x105 (including the null terminator). If you have a pointer:
char *p = 0x100;
Then you have:
p // 0x100
*p // 'h'
p+1 // 0x101
*(p+1) // 'e'
p += 2 // 0x102
*p // 'l'
p = 0x200;
p // now points to 0x200 in memory
*p // contains whatever value is in 0x200
If you have int pointers, then you are accessing memory 4-bytes at a time (or however big an int is on your system).
So with all that background, when you run calloc, it returns the address of the block you've requested.
int *memoryBlock = calloc(count, sizeof(int));
// memoryBlock is an array of int, assuming sizeof(int) == 4, then
// you have 40 bytes of memory starting from the address of what is
// returned by calloc.
memoryBlock++; // now memoryBlock is at base address + 4
*memoryBlock = 10; // now that address contains the value 10
(*memoryBlock)++; // now that address contains the value 11
memoryBlock++; // now memoryBlock is 4 bytes further
I have allocated a chunk of memory of type char and size is say 10 MB (i.e mem_size = 10 ):
int mem_size = 10;
char *start_ptr;
if((start_ptr= malloc(mem_size*1024*1024*sizeof(char)))==NULL) {return -1;}
Now I want to store the size information in the header of the memory chunk.To make myself more clear, let's say: start_ptr = 0xaf868004 (This is the value I got from my execution, it changes every time).
Now I want to put the size information in the start of this pointer, i.e *start_ptr = mem_size*1024*1024;.
But I am not able to put this information in the start_ptr. I think the reason is because my ptr is of type char which only takes one byte but I am trying to store int which takes 4 bytes, is the problem .
I am not sure how to fix this problem..
You'll need to cast your char pointer to an int pointer. In two steps:
int *start_ptr_int = (int*)start_ptr;
*start_ptr_int = mem_size * 1024 * 1024;
In one step:
*((int*)start_ptr) = mem_size * 1024 * 1024;
The (int*) in front of your pointer name tells the compiler: "Yeah, I know this is not actually a pointer to int, but just pretend for the time being, okay?"
*((int*)start_ptr) = mem_size*1024*1024
You could also just memcpy the value in ...
ie
int toCopy = mem_size * 1024 * 1024;
memcpy( start_ptr, &toCopy, 4 );
You'd even be surprised how most compilers won't even make the memcpy call and will just set the value.
One way to do it without casts:
#include <stdlib.h>
struct Block {
size_t size;
char data[];
};
#define SIZE (1024*1024)
int main()
{
struct Block* block = malloc(sizeof(struct Block) + SIZE);
block->size = SIZE;
char* start_ptr = block->data;
// ...
}
Or, to get the effect you want, change one line:
char* start_ptr = (char*)block;
A comment on style: Don't do this:
if ((ptr=malloc()) == NULL)
There is nothing wrong with
ptr = malloc();
if (ptr == NULL) ...
Good programmers know what they could do with the language. Excellent programmers know why they shouldn't do it. ;)
And -1 to all posters who assume an int in C to always be 32 bits, including the OP in the thread title. An int is guaranteed to have at least 16 bits, and on 32 bit machines it is usually a safe assumption to have 32 bits, but your code may fail as soon as you move to a 64 bit machine.