C assign value to double pointer - c

I am working on some C code on micro processor stm32f103. Since allocating memory from the heap isn't stable, I am not encouraged to use the C library functions malloc() and free() etc. Instead, I thought of declaring a large chunk of static memory in advance during compilation time, and reallocating the memory to suit my pseudo dynamic memory allocation purposes. My new malloc implementation works fine when testing on my computer, but crashes on the stm32 when I do malloc for double data type.
Here is my malloc implementation. I know it is not a real dynamic memory allocation, but i do it just to practice using pointers.
pk_malloc.c
#include "pk_malloc.h"
char pool[RESERVE];
void* alloc[RESERVE];
void mem_init()
{
for (int i = 0; i != RESERVE; i++)
{
alloc[i] = NULL;
}
}
void* mem_malloc(size_t size)
{
if (size > 0)
{
for (int i = 0; i != RESERVE; i++)
{
if (alloc[i] == NULL)
{
int end;
for (end = i; end != RESERVE; end++)
{
if (alloc[end] != NULL || end - i == size + 1)
{
break;
}
}
if (end - i == size + 1)
{
for (int k = i + 1; k != end; k++)
{
alloc[k] = &pool[k];
}
return alloc[i + 1];
}
}
}
}
return NULL;
}
void* mem_realloc(void* mem, size_t new_size)
{
if (mem == NULL)
{
return mem_malloc(new_size);
}
int old_size = 0;
void** alloc_t = &alloc[(char*)(mem) - pool];
while (*alloc_t != NULL)
{
old_size++;
alloc_t++;
}
if (new_size <= old_size)
{
mem_free((char*)mem + new_size);
return mem;
}
else
{
int i = alloc_t - alloc;
int size = new_size - old_size;
int end;
for (end = i; end != RESERVE; end++)
{
if (alloc[end] != NULL || end - i == size + 1)
{
break;
}
}
if (end - i == size + 1)
{
for (int k = i; k != end - 1; k++)
{
alloc[k] = &pool[k];
}
return alloc[i];
}
else
{
void* realloc_t = mem_malloc(new_size);
if (realloc_t == NULL)
{
return mem;
}
else
{
mem_copy(realloc_t, mem);
mem_free(mem);
return realloc_t;
}
}
}
}
void mem_copy(void* dest, void* source)
{
int dest_index = (char*)(dest) - pool;
int source_index = (char*)(source) - pool;
char* writer = (char*)(source);
while (alloc[source_index] != NULL && alloc[dest_index] != NULL)
{
pool[dest_index] = pool[source_index];
dest_index++;
source_index++;
}
}
void mem_free(void* mem)
{
if (mem != NULL)
{
void** alloc_t = &alloc[(char*)(mem) - pool];
while (*alloc_t != NULL)
{
*alloc_t = NULL;
alloc_t++;
}
}
}
pk_malloc.h
#ifndef _PK_MALLOC
#define _PK_MALLOC
#include <stdlib.h>
#define RESERVE 64
void mem_init();
void* mem_malloc(size_t size);
void* mem_realloc(void* mem, size_t new_size);
void mem_copy(void* dest, void* source);
void mem_free(void* mem);
#endif
main.c
int main()
{
mem_init();
int* hoho = (int*)(mem_malloc(sizeof(int)));
*hoho = 123;
printf("%d", *hoho);
mem_free(hoho);
}
The code works on my computer, and also works on the STM32. However when I change my datatype to a double:
int main()
{
mem_init();
double* hoho = (double*)(mem_malloc(sizeof(double)));
*hoho = 0.618;
printf("%f", *hoho);
mem_free(hoho);
}
It only works on my computer, while it crashed on the STM32.
I did some testing and debugs, I find that this line works, the pointer is not NULL and it has a valid address.
double* hoho = (double*)(mem_malloc(sizeof(double)));
However this line crashed.
*hoho = 0.618;
After more testing, I find any data types occupying more than 4 bytes crashes the same way, including long long etc.
Strangely, I made some user defined structs with lots of int, float data types etc, which definitely occupies more than 4 bytes, the code works fine on the STM32.
struct ABC
{
int a;
float b;
};
This line works no problems.
struct ABC* hoho = (struct ABC*)(mem_malloc(sizeof(struct ABC)));
The variable hoho can be assigned, and its members can be accessed without ease, working both on my computer and the STM32.
Please note that all the code works on my laptop, and most data types work for the STM32 too.
I have been stuck with the problem for hours, any help appreciated.

The core in STM32F1 is a Cortex-M3. This QA here points out that while unaligned word access is allowed by Cortex-M3 for simple instructions, not all instructions support unaligned access. In your case, the C compiler uses an instruction that doesn't support an unaligned address with double.
Notice that
the standard library malloc returns a pointer that is "suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated" (C11 7.22.3)
while a pointer may be converted to another pointer, "if the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined" (C11 6.3.2.3p7).
Thus the behaviour of a program is undefined already at these lines
int *hoho = mem_malloc(sizeof(int));
double *hoho = mem_malloc(sizeof(double));
if the pointer returned is not suitably aligned for int and double respectively.
To fix the code, change it so that it always returns pointers of proper alignment. The official ARM compilers maintain an 8-byte aligned heap.

Related

Why does this code segfault on one machine but run fine on another?

This code segfaults on line 97 (according to gdb) on one machine (Linode) yet runs just fine on a different machine (personal) and I haven't really been able to figure out why. I tried ensuring that the heap was extended properly via sbrk but that still didn't seem to fix the issue. If anyone wouldn't mind explaining what I did wrong, I'd really appreciate it.
`
#define _DEFAULT_SOURCE
#define _BSD_SOURCE
#include <stdio.h>
#include <math.h>
typedef struct block // This is a node in a linked list representing various sections of memory
{
int size; // size of the block of allocated memory
int free; // whether the block is free and can be reallocated
struct block* next; // pointer to the next block in the linked list
char end[1]; // end represents the end of the header block struct
} block_t;
#define STRUCT_SIZE sizeof(block_t)
// --- Global variables
block_t* head = NULL; // Pointer to head of the linked list
block_t* lastVisited = NULL; // Pointer to the last visited node
void* brkPoint = NULL; // This is a pointer to the empty space on heap
// findBlock: Iterates through all blocks of memory until it is able to return a block able to contain a node of size size.
// headptr: Head of the linked list of blocks
// size: Size of the memory section being claimed
block_t* findBlock(block_t* headptr, unsigned int size) {
block_t* ptr = headptr;
while (ptr != NULL) {
if (ptr->size >= (size + STRUCT_SIZE) && ptr->free == 1) {
return ptr;
}
lastVisited = ptr;
ptr = ptr->next;
}
return ptr;
}
// splitBlock: Given a block ptr, split it into two blocks of size of size and ptr->size - size
// ptr: Pointer to the block being split
// size: Size of the first one of the two blocks
void splitBlock(block_t* ptr, unsigned int size) {
block_t* newBlock;
newBlock = ptr->end + size;
newBlock->size = ptr->size - size - STRUCT_SIZE;
newBlock->free = 1;
newBlock->next = ptr->next;
ptr->size = size;
ptr->free = 0;
ptr->next = newBlock;
}
// Increase amount of memory the program uses from the heap
// lastVisitedPtr: Pointer to the beginning of free heap (end of the program heap)
// size: The amount that you want to increase
block_t* increaseAllocation(block_t* lastVisitedPtr, unsigned int size) {
brkPoint = sbrk(0);
block_t* curBreak = brkPoint; //Current breakpoint of the heap
if (sbrk(size + STRUCT_SIZE) == (void*)-1) {
return NULL;
}
curBreak->size = (size + STRUCT_SIZE) - STRUCT_SIZE;
curBreak->free = 0;
curBreak->next = NULL;
lastVisitedPtr->next = curBreak;
if (curBreak->size > size)
splitBlock(curBreak, size);
return curBreak;
}
// malloc: A custom implementation of malloc, behaves exactly as expected
// _size: the amount of memory to be allocated into a block
// returns void*, a pointer to the block
void* mymalloc(size_t _size) {
void* brkPoint1; // New heap breakpoint
unsigned int size = _size;
int memoryNeed = size + STRUCT_SIZE; // Total size needed, including metadata
block_t* ptr; // ptr to new block
brkPoint = sbrk(0); // Set breakpoint to heap
if (head == NULL) { // If being run for the first time
if (sbrk(memoryNeed) == (void*)-1) { // If you cannot allocate enough memory, return null
return NULL;
}
brkPoint1 = sbrk(0); // Set new breakpoint to heap
head = brkPoint; // Head is at heap
head->size = memoryNeed - STRUCT_SIZE;
head->free = 0; // Head is no longer free
head->next = NULL; // No next
ptr = head; // Return pointer is head
printf("Malloc %zu bytes\n", size);
return ptr->end; // Return end of the metadata pointer (AKA beginning of allocated memory)
}
else { // Head exists
block_t* freeBlock = NULL;
freeBlock = findBlock(head, size); // Find a block that can fit size
if (freeBlock == NULL) {
freeBlock = increaseAllocation(lastVisited, size); // Increase heap and create new block
if (freeBlock == NULL) {
return NULL;
}
printf("Malloc %zu bytes\n", size);
return freeBlock->end;
}
else { // Free block with size > _size exists, claim it
if (freeBlock->size > size) { // If block's size is > size, split it down to size
splitBlock(freeBlock, size);
}
}
printf("Malloc %zu bytes\n", size);
return freeBlock->end;
}
}
// myfree: Sets block referenced by pointer to be free and merges consecutive blocks
void myfree(void* ptr) {
block_t* toFree;
toFree = ptr - STRUCT_SIZE;
if (toFree >= head && toFree <= brkPoint) {
toFree->free = 1;
printf("Freed %zu bytes\n", toFree->size);
}
}
#define ARRAY_ELEMENTS 1024
int main() {
// Allocate some data
int *data = (int *) mymalloc(ARRAY_ELEMENTS * sizeof(int));
// Do something with the data
int i = 0;
for (i = 0; i < ARRAY_ELEMENTS; i++) {
data[i] = i;
}
// Free the data
myfree(data);
return 0;
}
`
As mentioned above, I tried debugging with gdb and expanding the heap with sbrk, but that didn't fix the issue. I have no idea why it would run fine on my personal machine but not on a machine hosted elsewhere. Thanks a lot for checking this out
There is a ton of warnings which you should fix.
This one in particular is likely to cause crashes:
t.c:61:16: warning: implicit declaration of function ‘sbrk’.
Why is this likely to cause a crash?
Without a prototype, the C compiler is required (by the standard) to assume that the function returns an int.
On 32-bit platforms, this typically doesn't cause a problem because sizeof(int) == sizeof(void*) == 4.
But on 64-bit platforms sizeof(int) == 4 and sizeof(void*) == 8. Thus assigning void *p = sbrk(0); without a prototype may result in the pointer having only the low 4 bytes of the returned address; and that is likely to produce a crash when that pointer is dereferenced.
When I add missing #include <unistd.h> (where the prototype for sbrk is), the crash goes away.
In general you should always compile with -Wall -Wextra and fix resulting warnings. The compiler will often tell you about bugs, and save you a lot of debugging time.

C: using realloc for high performance with an array of structs

I am using realloc to adjust the size of an array of structs containing 3 points x, y and z. This struct is encapsulated inside another struct that contains the array, the length of the array and a "reserved" value that is used for a pre-allocation strategy for even faster performance when it is evident that more structs of points will be appended to the struct array.
I am compiling with a Makefile that looks like this:
CFLAGS = -g -Wall
LIBS = -lm
default: echo "You must specify a target, e.g. file1, file2"
file2:
gcc $(CFLAGS) -o $# test.c file2.c $(LIBS)
I have a function to initialize an empty array structure, one to reset the array to be empty and free any dynamically allocated memory, one to append a point to the end of the array and one to remove a point designated by the index value.
I am getting two errors that I cannot find the cause of. One is that my code returns a non-zero status code of 1 and the other is the length seems to be off by one when I append a few thousand points.
I am letting the append function do all the work but if I should be allocating dynamic memory in initialization, please tell me so. I am pretty sure that my reset and remove functions are working as they are supposed to. Please take a look at append as well.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <assert.h>
typedef struct point
{
int x, y, z;
} point_t;
typedef struct
{
// number of points in the array
size_t len;
// pointer to an array of point_t structs
point_t* points;
size_t reserved;
} point_array_t;
void point_array_initial( point_array_t* pa )
{
assert(pa);
pa->len = 0;
pa->reserved = 0;
pa->points=NULL;
}
void point_array_reset( point_array_t* pa )
{//just free the array and set pa to NULL
assert(pa);
pa->points = memset(pa->points, 0, sizeof(point_t)*(pa->len));
pa->len = 0;
pa->reserved=0;
free(pa->points);
pa->points=NULL;
}
int point_array_append( point_array_t* pa, point_t* p )
{
assert(pa);
assert(p);
if(pa == NULL)//something wrong with intialization or reset
{
return 1;
}
if(p == NULL)//nothing to append
{
return 1;
}
//append the first point
if(pa->len == 0)
{
pa->len=1;
pa->reserved=pa->len*2;
pa->points = malloc(sizeof(point_t)* (pa->reserved));
if(pa->points == NULL)//malloc failed
{
return 1;
}
pa->points[pa->len-1].x = p->x;
pa->points[pa->len-1].y = p->y;
pa->points[pa->len-1].z = p->z;
}
if (pa->reserved > pa->len )
{
pa->len+=1;
pa->points[pa->len-1].x = p->x;//insert at index 0
pa->points[pa->len-1].y = p->y;
pa->points[pa->len-1].z = p->z;
}
//when we run out of space in reserved (len has caught up)
else if(pa->reserved == pa->len)
{
pa->len+=1;
pa->reserved=pa->len*2;
pa->points=realloc(pa->points, sizeof(point_t)*(pa->reserved));//doubling size of array
pa->points[pa->len-1].x = p->x;//TODO: change formula to find insertion point
pa->points[pa->len-1].y = p->y;
pa->points[pa->len-1].z = p->z;
}
return 0;
}
int point_array_remove( point_array_t* pa, unsigned int i )
{
assert(pa);
if (i >= pa->len)//out of bounds
{
return 1;
}
if(pa->len==0)//0 elements trying to remove from empty array
{
//pa->len=0;
//free(pa->points);
//pa->points=NULL;
return 1;
}
else if(pa->len ==1)//remove only element
{
pa->len-=1;//no copying required, just shorten
pa->points=realloc(pa->points, sizeof(point_t)*(pa->len));
//free(pa->points);
//pa->points=NULL;
}
else//array size is longer than 1 or 0
{
pa->points[i].x = pa->points[pa->len-1].x;
pa->points[i].y = pa->points[pa->len-1].y;
pa->points[i].z = pa->points[pa->len-1].z;
pa->len-= 1;//shorten array size
pa->reserved = pa->len*2;
pa->points=realloc(pa->points, sizeof(point_t)*(pa->len));//could reallocate for reserve here to increase speed.
}
return 0;
}
an else is missing after the if(pa->len == 0) body in the append function: the first point is appended twice.
Note that you have too many special cases in this function. It can be simplified into just a one test: if the array is too small, reallocate it, and append the point.
Other simplifications are possible:
the test if (pa->len == 0)//0 elements trying to remove from empty array is redundant with the previous one.
take advantage of the fact that realloc(NULL, size) is equivalent to malloc(size) and realloc(p, 0) to free(p), and free(NULL) is OK.
beware that realloc() may fail, even when shrinking the block.
you should only shrink the array when it becomes too sparse, not for every call to point_array_remove.
Here is a simpler version:
#include <assert.h>
#include <stdlib.h>
typedef struct point {
int x, y, z;
} point_t;
typedef struct {
size_t len; // number of valid points in the array
size_t reserved; // allocated number of points in the array
point_t *points; // pointer to an array of point_t structs
} point_array_t;
void point_array_initial(point_array_t *pa) {
assert(pa);
pa->len = 0;
pa->reserved = 0;
pa->points = NULL;
}
void point_array_reset(point_array_t *pa) {
assert(pa);
free(pa->points);
pa->len = 0;
pa->reserved = 0;
pa->points = NULL;
}
int point_array_append(point_array_t *pa, const point_t *p) {
point_t *points;
assert(pa);
assert(p);
// no need to test pa nor p, asserts would already abort
points = pa->points;
if (pa->len >= pa->reserved || points == NULL) {
// reallocate of points array is too small
size_t newsize = pa->reserved;
if (newsize < pa->len)
newsize = pa->len;
if (newsize < 1)
newsize = 1;
newsize += newsize;
points = realloc(points, newsize * sizeof(*points);
if (points == NULL)
return 1;
pa->points = points;
pa->reserved = newsize;
}
// append point structure
points[pa->len++] = *p;
return 0;
}
int point_array_remove(point_array_t *pa, unsigned int i) {
point_t *points;
assert(pa);
if (i >= pa->len || pa->points == NULL) { //out of bounds or invalid array
return 1;
}
if (pa->len - i > 1) {
memmove(&pa->points + i, &pa->points + i + 1,
sizeof(*pa->points) * (pa->len - i - 1));
}
pa->len--;
if (pa->reserved >= pa->len * 3) {
size_t newsize = pa->len * 2;
// shorten the array with care.
// note that the array will be freed when it becomes empty
// no special case needed.
points = realloc(pa->points, sizeof(*points) * newsize);
if (points != NULL) {
pa->points = points;
pa->reserved = newsize;
}
}
return 0;
}
In addition to the error pointed out by chqrlie, here are a few additional thoughts on your code.
A better choice of CFLAGS for non-debug builds would be
-Wall -Wextra -O3
add -pedantic for a few additional warnings and you can use -Ofast with gcc >= 4.6.
Never realloc the pointer itself, If realloc fails, NULL is returned and you have lost the reference to your original memory block -- and created a memory leak because you no longer have the beginning address of the block to free. Don't increment len or reserved until you validate realloc succeeded. Instead, always use a temporary pointer and increment values only on success, e.g.
else if(pa->reserved == pa->len)
{
void *tmp = realloc(pa->points, sizeof(point_t)*(pa->len + 1) * 2);
if (!tmp) {
/* handle error - exit or return */
}
pa->points = tmp;
pa->len+=1;
pa->reserved=pa->len*2;
}
The following looks like a problem if you are simply wanting to shorten the array by one:
else if(pa->len ==1)//remove only element
{
pa->len-=1;//no copying required, just shorten
pa->points=realloc(pa->points, sizeof(point_t)*(pa->len));
//free(pa->points);
//pa->points=NULL;
}
else//array size is longer than 1 or 0
{
pa->points[i].x = pa->points[pa->len-1].x;
pa->points[i].y = pa->points[pa->len-1].y;
pa->points[i].z = pa->points[pa->len-1].z;
pa->len-= 1;//shorten array size
pa->reserved = pa->len*2;
pa->points=realloc(pa->points, sizeof(point_t)*(pa->len));//could reallocate for reserve here to increase speed.
}
In the else above you are assigning the previous point to the last, then chopping off the last -- either I don't understand what you are trying to accomplish, or it's not doing what you think it is. In either case, unless you have some compelling reason for wanting to realloc to shorten the array by one (I'd wait until all add/remove operations are done and then call a final realloc on len element to exactly size your memory use). Instead, I would replace the entirety of the above with:
else
pa->len -= 1;
No need to mess with anything else. You effectively ignore the data in the last row -- which isn't hurting anything, until your next add overwrites the values.

how to use a static struc into a static function ? ( like a global )

for the need of my project i need to handle a global (representing the heap ). It's a C project, i don't have any errors at the compilation.
but when i try to use a member of struct -> segfault.
if someone could tell me where is the point ?
thanks
static t_meta *init_get_meta()
{
static t_meta *allineed = NULL;
int i;
i = 0;
if (allineed == NULL)
{
//allineed->pagesize = getpagesize();
//allineed->pagesize = 4096;
allineed->pagesize = 0; --> segfault right here
printf("LOVE\n");
while (i < 8)
{
allineed->listfree[i++] = NULL;
}
allineed->last = extend_heap(allineed);
}
return (allineed);
}
You are de-referencing a NULL pointer.
Here in this line of code you check for NULL and go ahead and access that memory which is illegal.
if (allineed == NULL)
allineed->pagesize = 0; // incorrect at this time allineed is pointing to 0x0
What you need to do is malloc the structure and than check if malloc returned with not a NULL value. something on the lines of
static t_meta *allineed = malloc(sizeof(t_meta));
if (allineed)
{
//do something
}
else
//return error
You might want to look at these questions if you are trying to implement a basic malloc yourself
How do malloc() and free() work?
How is malloc() implemented internally?
A very basic malloc would do these basic steps
void * my_malloc(size_t size)
{
size_t headersize = 1; // 1 byte header
uint8_t alignment = 8; // 8 byte alignment
// the block should be 8 bytes align
size_t alloc_size = ((size+1)+(alignment-1))&~(alignment-1);
//use system call
void *head = sbrk(alloc_size );
if(head == (void *)(-1))
return NULL;
//update the header here to mark the size and other bits depending upon req
char *header_val = (char *)head;
*header_val = (alloc_size/2) | ( 1 << 7);//only support power 2 sizes
//return updated pointer location to point to ahead of header
// after changing the pointer to char type as pointer arithmetic is not allowed on void pointers
//printf("allocated size is %d with first byte %p\n",alloc_size,header_val);
//printf(" %02x\n",(unsigned char)*(char *)header_val);
return (char *)head + headersize;
}

Initializing pointers in a struct in a minimum of source lines

I'm currently new to C programming, and appreciate for any tip.
Is there a shorter way to initialize struct pointers in C without removing the pointer tags?
typedef struct {
int x, y, z;
} Point3;
typedef struct {
Point3 *pos, *direction;
} Vector;
int main() {
Vector *p;
p = malloc(sizeof(Vector));
p->pos = malloc(sizeof(Point3));
p->direction = malloc(sizeof(Point3));
return 0;
}
Yes, there is a shorter way — one which is one malloc() call shorter.
Vector *p = malloc(sizeof(Vector));
if (p != 0)
{
p->pos = malloc(2 * sizeof(Point3));
if (p->pos != 0)
p->direction = &p->pos[1];
}
Allocate an array of 2 Point3 values. p->pos points to the first, and p->direction points to the second (or vice versa).
It is still 3 statements (plus error checking) and two calls to malloc(), though.
In practice, you could almost certainly get away with:
Vector *p = malloc(sizeof(Vector) + 2 * sizeof(Point3));
if (p != 0)
{
p->pos = (void *)((char *)p + sizeof(Vector));
p->direction = (void *)((char *)p + sizeof(Vector) + sizeof(Point3));
}
I am not sure that is sanctioned by the C standard, but I can't immediately think of a plausible platform configuration where it would actually fail to work correctly. It would fail if you found some bizarre platform where addresses were 16-bits each but int was 8 bytes and had to be 8-byte aligned, but that's hardly plausible.
To me, it makes far more sense to put the Point3 members directly in the Vector, instead of pointers. Fewer allocations, less memory fragmentation, fewer de-references, fewer cache-misses.
typedef struct {
int x, y, z;
} Point3;
typedef struct {
Point3 pos, direction;
} Vector;
int main(void) {
/* Local (stack) allocation of a Vector, initialized to all zeros */
Vector v = {};
/* Dynamic (heap) allocation of a Vector, initialized to all zeros */
Vector *p;
p = malloc(sizeof(Vector));
if (!p) {
return 1; // failure
}
*p = (Vector){};
return 0;
}
Unfortunately, there is no other way. You can simplify memory allocation with another function, like this
Vector* allocate_vector( ) {
Vector* v = (Vector*)malloc( sizeof(Vector) );
if( v == NULL ) {
/**/
}
v->pos = (Point3*)malloc( sizeof(Point3) );
if( v->pos == NULL ) {
/**/
}
v->direction = (Point3*)malloc( sizeof(Point3) );
if( v->direction == NULL ) {
/**/
}
return v;
}
And then use it, when you need new Vector.
Vector* v = allocate_vector( );

making your own malloc function in C

I need your help in this. I have an average knowledge of C and here is the problem. I am about to use some benchmarks to test some computer architecture stuff (branch misses, cache misses) on a new processor. The thing about it is that benchmarks are in C but I must not include any library calls. For example, I cannot use malloc because I am getting the error
"undefined reference to malloc"
even if I have included the library. So I have to write my own malloc. I do not want it to be super efficient - just do the basics. As I am thinking it I must have an address in memory and everytime a malloc happens, I return a pointer to that address and increment the counter by that size. Malloc happens twice in my program so I do not even need large memory.
Can you help me on that? I have designed a Verilog and do not have so much experience in C.
I have seen previous answers but all seem too complicated for me. Besides, I do not have access to K-R book.
Cheers!
EDIT: maybe this can help you more:
I am not using gcc but the sde-gcc compiler. Does it make any difference? Maybe that's why I am getting an undefined reference to malloc?
EDIT2:
I am testing a MIPS architecture:
I have included:
#include <stdlib.h>
and the errors are:
undefined reference to malloc
relocation truncated to fit: R_MIPS_26 against malloc
and the compiler command id:
test.o: test.c cap.h
sde-gcc -c -o test.s test.c -EB -march=mips64 -mabi=64 -G -O -ggdb -O2 -S
sde-as -o test.o test.s EB -march=mips64 -mabi=64 -G -O -ggdb
as_objects:=test.o init.o
EDIT 3:
ok, I used implementation above and it runs without any problems. The problem is that when doing embedded programming, you just have to define everything you are using so I defined my own malloc. sde-gcc didn't recognize the malloc function.
This is a very simple approach, which may get you past your 2 mallocs:
static unsigned char our_memory[1024 * 1024]; //reserve 1 MB for malloc
static size_t next_index = 0;
void *malloc(size_t sz)
{
void *mem;
if(sizeof our_memory - next_index < sz)
return NULL;
mem = &our_memory[next_index];
next_index += sz;
return mem;
}
void free(void *mem)
{
//we cheat, and don't free anything.
}
If required, you might need to align the memory piece you hand back, so e.g. you always
give back memory addresses that's on an address that's a multiple of 4, 8, 16 or whatever you require.
Trying a thread safe nos answer given above, I am referring his code with some changes as below:
static unsigned char our_memory[1024 * 1024]; //reserve 1 MB for malloc
static size_t next_index = 0;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void *malloc(size_t sz)
{
void *mem;
pthread_mutex_lock(&lock);
if(sizeof our_memory - next_index < sz){
pthread_mutex_unlock(&lock);
return NULL;
}
mem = &our_memory[next_index];
next_index += sz;
pthread_mutex_unlock(&lock);
return mem;
}
void free(void *mem)
{
//we cheat, and don't free anything.
}
You need to link against libc.a or the equivilent for your system. If you don't use the standard C lib you won't get any of the startup code that runs before the main function either. Your program will never run....
You could either allocate a block of static data and use that in the place of malloc, like:
// char* fred = malloc(10000);
// equals
static char [100000] fred;
or call the standard malloc for a large block of continuous memory on startup and write yr own malloc type function to divide that down. In the 2nd case you would start benchmarking after the calling the system's malloc as to not effect the benchmarks.
I am sharing the complete approach for Malloc and free it works on every scenario. This is complimented using array. We can also implement using link list for metadata.
There are three Scenarios We have to Cover
Continuous Memory allocation: Allocate memory in continuous manner
Allocated memory between two allocated memory: When Memory is free to allocate in between two allocated memory block. we have to use that memory chunk for allocation.
Allocated from Initial block When Initial block is free.
for detailed You can see in diagram. Diagram for allocating algo of memory
Source code for malloc
#define TRUE 1
#define FALSE 0
#define MAX_ALOCATION_ALLOWED 20
static unsigned char our_memory[1024 * 1024];
static int g_allocted_number = 0;
static int g_heap_base_address = 0;
typedef struct malloc_info
{
int address;
int size;
}malloc_info_t;
malloc_info_t metadata_info[MAX_ALOCATION_ALLOWED] ={0};
void* my_malloc(int size)
{
int j =0;
int index = 0 ;
int initial_gap =0;
int gap =0;
int flag = FALSE;
int initial_flag = FALSE;
void *address = NULL;
int heap_index = 0;
malloc_info_t temp_info = {0};
if(g_allocted_number >= MAX_ALOCATION_ALLOWED)
{
return NULL;
}
for(index = 0; index < g_allocted_number; index++)
{
if(metadata_info[index+1].address != 0 )
{
initial_gap = metadata_info[0].address - g_heap_base_address; /*Checked Initial Block (Case 3)*/
if(initial_gap >= size)
{
initial_flag = TRUE;
break;
}
else
{
gap = metadata_info[index+1].address - (metadata_info[index].address + metadata_info[index].size); /*Check Gap Between two allocated memory (Case 2)*/
if(gap >= size)
{
flag = TRUE;
break;
}
}
}
}
if(flag == TRUE) /*Get Index for allocating memory for case 2*/
{
heap_index = ((metadata_info[index].address + metadata_info[index].size) - g_heap_base_address);
for(j = MAX_ALOCATION_ALLOWED -1; j > index+1; j--)
{
memcpy(&metadata_info[j], &metadata_info[j-1], sizeof(malloc_info_t));
}
}
else if (initial_flag == TRUE) /*Get Index for allocating memory for case 3*/
{
heap_index = 0;
for(j = MAX_ALOCATION_ALLOWED -1; j > index+1; j--)
{
memcpy(&metadata_info[j], &metadata_info[j-1], sizeof(malloc_info_t));
}
}
else /*Get Index for allocating memory for case 1*/
{
if(g_allocted_number != 0)
{
heap_index = ((metadata_info[index -1].address + metadata_info[index-1].size) - g_heap_base_address);
}
else /* 0 th Location of Metadata for First time allocation*/
heap_index = 0;
}
address = &our_memory[heap_index];
metadata_info[index].address = g_heap_base_address + heap_index;
metadata_info[index].size = size;
g_allocted_number += 1;
return address;
}
Now Code for Free
void my_free(int address)
{
int i =0;
int copy_meta_data = FALSE;
for(i = 0; i < g_allocted_number; i++)
{
if(address == metadata_info[i].address)
{
// memset(&our_memory[metadata_info[i].address], 0, metadata_info[i].size);
g_allocted_number -= 1;
copy_meta_data = TRUE;
printf("g_allocted_number in free = %d %d\n", g_allocted_number, address);
break;
}
}
if(copy_meta_data == TRUE)
{
if(i == MAX_ALOCATION_ALLOWED -1)
{
metadata_info[i].address = 0;
metadata_info[i].size = 0;
}
else
memcpy(&metadata_info[i], &metadata_info[i+1], sizeof(malloc_info_t));
}
}
For testing Now Test code is
int main()
{
int *ptr =NULL;
int *ptr1 =NULL;
int *ptr2 =NULL;
int *ptr3 =NULL;
int *ptr4 =NULL;
int *ptr5 =NULL;
int *ptr6 =NULL;
g_heap_base_address = &our_memory[0];
ptr = my_malloc(20);
ptr1 = my_malloc(20);
ptr2 = my_malloc(20);
my_free(ptr);
ptr3 = my_malloc(10);
ptr4 = my_malloc(20);
ptr5 = my_malloc(20);
ptr6 = my_malloc(10);
printf("Addresses are: %d, %d, %d, %d, %d, %d, %d\n", ptr, ptr1, ptr2, ptr3, ptr4, ptr5, ptr6);
return 0;
}

Resources