Ok quick intro. I'm doing a homework on dynamically allocated memory. We need to simulate a CPU using structs and dyn. al. memory. I was testing if my stack functions properly and doesn't overflow. The stack is supposed to be 2 KiB, didn't overflow, but while printing the numbers, few addresses contain other numbers that i didn't put in. Ill just copy it here, and get rid of instruction lists, registers and such, that are not a problem and would make this long.
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
struct cpu {
struct stack* memory;
};
struct stack {
int32_t* values;
int32_t* top;
};
void stackInit(struct stack* stack)
{
stack->values = malloc(2048);
stack->top = NULL;
}
void cpuInit (struct cpu* cpu)
{
stackInit(cpu->memory); //initialize stack
}
void stackPush(struct stack* stack, int32_t value)
{
if (stack->top == NULL){
stack->top = stack->values;
*(stack->top) = value;
}
else if (stack->top + sizeof(int32_t) < stack->values + 2048){
stack->top += sizeof(int32_t);
*(stack->top) = value;
}
}
void cpuDebug(const struct cpu* cpu)
{
int32_t* auxpt = cpu->memory->top;
if (cpu->memory->top != NULL)
for (int32_t i = 0; auxpt >= cpu->memory->values; i++){
printf("Value on the addr %d\n", *auxpt);
printf("Address of auxpt: %p\n", ( void * )auxpt );
auxpt -= sizeof(int32_t);
}
printf("\n");
}
int main()
{
struct cpu Cpu;
cpuInit(&Cpu);
for (int32_t i = 0; i < 550; i++){
stackPush(Cpu.memory,i);
}
cpuDebug(&Cpu);
return 0;
}
And the output looks like this :
Value on the addr 133
Address of auxpt: 0x562640529880
Value on the addr 10
Address of auxpt: 0x562640529870
Value on the addr 544108298
Address of auxpt: 0x562640529860
Value on the addr 2016419898
Address of auxpt: 0x562640529850
Value on the addr 1919181889
Address of auxpt: 0x562640529840
Value on the addr 128
Address of auxpt: 0x562640529830
Value on the addr 127
Any ideas why is this happening?
Thanks in advance
Man, you must allocate struct stack before access their members (values and top). You are accessing a non mallocated memory.
void stackInit(struct stack* stack)
{
stack = malloc(sizeof(struct stack));
stack->values = malloc(2048);
stack->top = NULL;
}
Following the tricks pointed in the comments, a better solution could be:
void stackInit(struct stack** stack)
{
(*stack) = (struct stack*)malloc(sizeof(struct stack));
(*stack)->values = (int32_t*)malloc(2048);
(*stack)->top = NULL;
}
void cpuInit(struct cpu* cpu)
{
stackInit(&cpu->memory); //initialize stack
}
In this way, the caller will see the allocated memory in the context of Cpu.memory.
Your struct cpu has an associated struct stack, but that stack is not part of the struct cpu; the cpu merely holds a pointer to a separate stack. You never initialize that pointer, nor indeed reserve any memory for the wanted stack. In particular, your cpuInit() function does not do this, and your stackInit() function depends on it already having been done.
Overall, supposing that each cpu requires only one stack for its lifetime, you would be better off making the stack an integral part of the cpu, so that you don't need to worry about such allocation issues:
struct cpu {
struct stack memory; // not a pointer
};
Having done that, you'll need to change the syntax with which you access the stack's members via the cpu, and you'll need to watch out for other semantic differences, but you can always get a pointer to the stack where needed (such as to pass to stackInit()) via the & operator.
Related
So for my C assignment, I need to implement a dynamic memory allocator with a similar interface to the standard library like malloc, free, realloc. I'm implementing the allocator as a library of functions that can be called by other programs. Virtual heap will be managed by a simple buddy allocation algorithm.
My functions given are:
void * virtual_sbrk(int32_t increment);
pretty much the same as the real-world sbrk and brk syscalls. I don't need to implement this.
void init_allocator(void * heapstart, uint8_t initial_size, uint8_t min_size);
This function will be called once at the beginning and initialise the virtual heap.
void * virtual_malloc(void * heapstart, uint32_t size);
mallocs memory
int virtual_free(void * heapstart, void * ptr);
frees memory
void * virtual_realloc(void * heapstart, void * ptr, uint32_t size);
reallocates memory
void virtual_info(void * heapstart);
prints the current state of the buddy allocator to standard output.
This is my current problem:
How do you initialise the heap and implement malloc without anything in the first place? Like I can't use malloc or any of the pre existing allocator functions. So far I've tried to use a linked list with nodes containing the memory as a value. Eg if initial size is 3 and min size is 1, I'd have 5 nodes with the root containing 8 bytes, two more containing 4 bytes each , and lastly 2 more contining 2 bytes each. But I'm still confused on how to use sbrk or how the heap is structured in the first place. I've browsed online resources but still confused on how to construct the heap memory.
Following is my code so far:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
struct node{
size_t memory;
struct node *nextInLine;
};
void printNode(const struct node *nd, const char *comment){
if(nd == NULL){
printf("%s is null\n", comment);
}
else{
printf("%s: memory:%d address:%p nextInLine:%p\n",
comment,
nd->memory,
nd,
nd->nextInLine);
}
}
void printList(const struct node *list){
printf("Printing List:\n");
const struct node *t;
t = list;
if(t == NULL){
printf("current node is empty\n");
}
else{
while(t){
printNode(t, "node");
t = t->nextInLine;
}
}
}
void * virtual_sbrk(int32_t increment) {
void *p = malloc(increment);
return p;
}
uint8_t return_init_size(uint8_t size){
return size;
}
struct node *getNewNode(const uint8_t memory_size){
struct node *newNode = NULL;
double two = 2;
size_t m_size = memory_size;
double result = pow(two, m_size);
newNode = virtual_sbrk(result);
if(newNode != NULL){
newNode->memory = result;
newNode->nextInLine = NULL;
}
else{
printf("Allocation error: newNode is still NULL\n");
}
return newNode;
}
void init_allocator(void * heapstart, uint8_t initial_size, uint8_t min_size) {
//error catchers
if(initial_size == 0){
printf("Initial size is 0\n");
}
if(initial_size < min_size){
printf("initial_size is smaller than min_size\n");
}
//initialising the virtual heap using a linked array with nodes the memory size of 2^some_size
uint8_t i = initial_size;
struct node *first = heapstart;
heapstart = first;
struct node *tail = NULL;
while(i >= min_size){
if(first == NULL){
first = getNewNode(i);
if(first != NULL){
tail = first;
}
}
else{
tail->nextInLine = getNewNode(i);
if(tail->nextInLine != NULL){
tail = tail->nextInLine;
}
tail->nextInLine = getNewNode(i);
if(tail->nextInLine != NULL){
tail = tail->nextInLine;
}
}
i -= 1;
}
printList(first);
}
void * virtual_malloc(void * heapstart, uint32_t size) {
if(size == 0){
return NULL;
}
return NULL;
}
int virtual_free(void * heapstart, void * ptr) {
return 1;
}
void * virtual_realloc(void * heapstart, void * ptr, uint32_t size) {
return NULL;
}
void virtual_info(void * heapstart) {
}
It would be great if someone could help explain how I would go about doing this, as in the structure I need to follow, if that makes sense.
You can use both sbrk and mmap as glibc malloc does.
glibc malloc works with threads, with something called arenas.
When malloc is initialized it calls sbrk to extend the mapped memory.
When big allocations happen, or new threads are created malloc ends up calling mmap.
mmap allocates a new mapping in the address space of the process.
sbrk extends the current mapping to make it bigger.
Simple example of sbrk:
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#define HEAP_SZ 0x8000
int main(void) {
void *p = sbrk(0);
printf("current break addr = %p\n", p);
sbrk(HEAP_SZ);
void *n = sbrk(0);
printf("new break addr = %p\n", n);
return 0;
}
The first call (with argument 0) returns the current program break.
When specifying a size greater than 0, program break is extended, so on the next call with argument 0, the new program break will be returned.
You can do then something like this:
unsigned long heap_mem_sz = 0;
void *heap_start_addr = NULL;
void init_heap(void) {
void *p = sbrk(0);
#if DEBUG
printf("current break addr = %p\n", p);
#endif
sbrk(HEAP_SZ);
heap_mem_sz = (unsigned long)HEAP_SZ;
void *n = sbrk(0);
#if DEBUG
printf("new break addr = %p\n", n);
#endif
heap_start_addr = (void *)n;
return;
}
Having that information on globals allows you to continue the development of the allocator implementation.
You can call init_heap() the first time an allocation is requested.
Now you can return that allocation and craft a "top chunk".
It will be a chunk with the same structure than the others but containing all the memory from which allocations take memory, and it gets shrinked on allocations.
Also, you will need to do something once the heap memory is full, so consider calling syscalls like mmap or sbrk again.
Linked lists on malloc are used for bins. They are used for searching freed chunks that can satisfy new allocations so you reuse chunks that are not used anymore.
For such linked list, you can create a global:
struct heap_chunk *freed_chain = NULL
When memory is requested, you first check if freed_chain is NULL, if not, traverse the linked list until a block compatible with the user request is found, or the next pointer is NULL.
If any of those chunks is valid, you will need to unlink that chunk from the linked list, and make the previous chunk point to the next one, so no more memory requests access to it as now it is allocated and not freed.
On freeing memory, you would need to link a new chunk to that linked list.
Obviously on malloc, for optimization purposes this is more complex, and some different bins with different size requirements and different properties exist to speed up allocations.
This question already has answers here:
Difference between null pointers and uninitialized pointers?
(5 answers)
Closed 1 year ago.
I am trying to implement stack in C. I am not getting any compilation error but I am getting the return value as 322122547 without any error. What should I do ?
Here is my code
#include <stdio.h>
#include <stdlib.h>
struct stack
{
int size;
int top;
int *arr;
};
int isEmpty(struct stack * ptr)
{
if (ptr->top == -1)
{
return 1;
}
else
{
return 0;
}
}
int isFull(struct stack * ptr)
{
if (ptr->top == ptr->size - 1)
{
return 1;
}
else
{
return 0;
}
}
int main()
{
struct stack *s;
s->size = 10;
s->top = -1;
s->arr = (int *)malloc(s->size * sizeof(int));
if(isEmpty(s)){
printf("The stack is empty");
}
else{
printf("The stack is not empty");
}
return 0;
}
If I use a struct stack pointer I do not get any output. Should I consider changing the pointer part
Turn on your compiler errors and it will tell you right away what's wrong. For example if I compile your code with gcc -Wall -Werror it says:
error: 's' is used uninitialized [-Werror=uninitialized]
s->size = 10;
| ~~~~~~~~^~~~
Problem origin
struct stack *s; is defining a pointer that is expecting an instance of your structure. Now by default, that expected structure is not initialized and therefore the pointer points to a random location in memory.
You can visualize this error by using gcc -Wall -Werror the compiling and you get:
error: 's' is used uninitialized [-Werror=uninitialized]
s->size = 10;
| ~~~~~~~~^~~~
Since the location the pointer is pointing to is random, you will get random values from your pointer depending on what that memory location contains.
A solution
A way to fix this is to initialize the structure your pointer is expecting to point to in order to allocate this structure. You can do this in two way:
Static allocation: you can create a structure and then point to it using:
struct stack s_static;
struct stack *s = &s_static;
The final code would be:
int main()
{
struct stack s_static;
struct stack *s = &s_static;
s->size = 10;
s->top = -1;
s->arr = (int *)malloc(s->size * sizeof(int));
if(isEmpty(s)){
printf("The stack is empty");
}
else{
printf("The stack is not empty");
}
return 0;
}
Dynamic allocation: you can dynamically allocate your structure in memory by using malloc. You can allocate your stack instance s by doing struct stack* s = (struct stack*) malloc(sizeof(struct stack));. This is a big line. What's happening? struct stack* s tells the compiler this is a pointer that is pointing to a memory location. (struct stack*) is telling the malloc that the new memory location we're about to allocate has type struct stack. Finally, malloc creates some space on the heap for our instance and sizeof(struct stack) simply tells the malloc command how much memory we need to allocate. After putting this line, the code will compile without errors.
BUT WAIT! If you use dynamic allocation, you need to also free the heap once you finish, otherwise the memory location will leak. Therefore, before your return 0, you need to free that memory location. You can do so by using free(s)
The final dynamic allocation approach will look something like this:
int main()
{
struct stack* s = (struct stack*) malloc(sizeof(struct stack));
s->size = 10;
s->top = -1;
s->arr = (int *)malloc(s->size * sizeof(int));
if(isEmpty(s)){
printf("The stack is empty");
}
else{
printf("The stack is not empty");
}
free(s);
return 0;
}
I'm trying to implement stack in C.
What I'm going for:
Design a Stack structure with push and pop functions for the implementation.
Create a Memory structure owns number of block, block size, and stack attributes.
Stack attribute represents memory blocks. Number of block attribute represents the length of the stack. Block size represents the maximum value that each element in the stack can get.
Write an allocate function that takes a size parameter. If the given size is bigger than block size of the Memory, the allocation will be distributed to the different blocks in the stack attribute.
For example, calling allocate(27) updates the stack as:
allocate(27) = [10, 10, 7, 0, 0]
for a Memory with number of block = 5, block size = 10. The remaining of the elements which don't have maximum value can be sealed until the element is flushed. Therefore, the next allocation can start from next element position after 7 given above.
Write a deallocate function that flushes the last used block.
My Work:
First, created the structs:
stack attribute represents memory blocks.
number of block attribute represents the length of the stack.
Block size represents the maximum value that each element in the stack can get.
#include <stdio.h>
#include <stdlib.h> // Provides function For memory locating. allocate & deallocate.
struct Stack {
int top;
};
struct Memory{
int stack;
int number_of_block; // 5
int block_size; // 10
};
Then I have tried to create allocate & push function but they are not working.
int main(){
allocate(30);
return 0;
}
int allocate(int size){
struct Stack* stack = (struct Stack*)malloc(sizeof(struct Stack));
struct Memory* memory = (struct Memory*)malloc(sizeof(struct Memory));
memory->block_size = 10;
stack->top = -1;
memory->stack = (int*)malloc(memory->block_size * sizeof(int));
struct Memory memory = {1, 5, 10};
for(int i = 0; i < 5; i++){
if(size > 10){
size = size - 10; //27 - 10 = 17 -> 17 - 10 = 7
push(stack, 10);
}
}
if(size % 10 != 0){
int size_mod = size % 10; //27 % 10 = 7
push(stack, size_mod);
}
}
void push(struct Stack* stack, struct Memory* memory, int item){
if(stack->top == memory->block_size - 1){
return;
}
memory->stack[++stack->top] = item;
printf("%d ", item);
}
The Memory structure contains a pointer to the first block, as well as the number of blocks and the maximum size of each block. Each block then contains the data and a pointer to the next block, meaning all the blocks are stored in a linked list.
The function allocate returns a pointer to the Memory structure created.
#include <stdio.h>
#include <stdlib.h>
struct Block {
int data;
struct Block *next;
};
struct Memory {
int block_count;
int block_size;
struct Block *head;
};
/* Push a new block onto the stack */
void push(struct Block **head, int data)
{
struct Block *new = malloc(sizeof *new);
if (!new) {
printf("Error: memory allocation failed");
exit(EXIT_FAILURE);
}
new->data = data;
*head = new;
/* `printf` is not needed */
printf("%d\n", data);
}
/* Returns a pointer to the `Memory` structure */
struct Memory *allocate(int size)
{
struct Memory *memory = malloc(sizeof *memory);
if (!memory) {
printf("Error: memory allocation failed");
exit(EXIT_FAILURE);
}
memory->block_count = 5;
memory->block_size = 10;
struct Block *head = NULL;
for (int i = 0; i < memory->block_count; ++i) {
int data = 0;
if (size > 10)
data = 10;
else if (size > 0)
data = size;
size -= data;
push(&head, data);
}
memory->head = head;
return memory;
}
int main(void)
{
struct Memory *memory = allocate(27);
return EXIT_SUCCESS;
}
And as you can see, you don't need to cast malloc, because it returns void *, which is automatically and safely promoted to any other pointer.
I'm doing an exercise, and want support about it. The problem is this: I have two structures (1 for the nodes of the stack, 1 for the stack). In the node structure, there is a void* data field.
I've tried to push a value on the stack but, because of void* data instead of simple data, I failed.
This is the code about the structures and the push() function.
struct upo_stack_node_s
{
void *data;
struct upo_stack_node_s *next;
};
typedef struct upo_stack_node_s upo_stack_node_t;
struct upo_stack_s
{
upo_stack_node_t *top;
size_t size;
};
/*Function for create the stack*/
upo_stack_t upo_stack_create()
{
upo_stack_t stack = malloc(sizeof(struct upo_stack_s));
if (stack == NULL)
{
fprintf(stderr, "Unable to create a stack!\n");
abort();
}
stack->top = NULL;
stack->size = 0;
return stack;
}
/*Push() function:*/
void upo_stack_push(upo_stack_t stack, void *data)
{
/* TO STUDENTS:
* Remove the following two lines and put here your implementation
*/
upo_stack_node_t *node = malloc(sizeof(struct upo_stack_node_s));
node->data = data; /*<-- Here's the problem */
node->next = stack->top;
stack->top = node;
++stack->size;
}
/*Top() function*/
void* upo_stack_top(const upo_stack_t stack)
{
/* TO STUDENTS:
* Remove the following two lines and put here your implementation
*/
return (void *)(stack->top); //<---
}
/*Function for testing (there are other functions in the code)*/
void test_top()
{
int value1 = 1;
int value2 = 2;
upo_stack_t stack;
stack = upo_stack_create();
upo_stack_push(stack, &value1); //<----
upo_stack_push(stack, &value2); //<----
assert( upo_stack_top(stack) != NULL );
assert( *((int*) upo_stack_top(stack)) == value2 ); <-- Here's the error
upo_stack_pop(stack, 0);
assert( upo_stack_top(stack) != NULL );
assert( *((int*) upo_stack_top(stack)) == value1 );
upo_stack_pop(stack, 0);
assert( upo_stack_top(stack) == NULL );
upo_stack_destroy(stack, 0);
}
You always have to pass a void pointer. That means if you want to pass a simple value, like 1, what you need to do is, is to allocate an integer value, and pass the pointer to it (as a void pointer).
Thus something like:
int x = 4;
upo_stack_push(upo_stack, &x);
Of course you have to make sure the int variable x does not go out of scope, otherwise the pointer will point to freed memory, which results in nasty memory problems.
Update
It is assumed above, that the void pointer you pass is stored already in memory for the scope of the stack. In case, you want the stack itself to copy the data, you have also to malloc space for that, thus not only mallocing the node, but also mallocing and copy the data type passed. Also to know the size of the data (since it is a void pointer, which is unaware of its type), you have to add an int size parameter to the push function.
For an integer value to be stored, pass it as a pointer, with size: sizeof(int). Than for copying the data structure, use memcpy. This only works for simple types and structures without pointers. If you have to copy structures with pointers (thus you need so called deep-copying), than it is more tricky.
I have been doing excercises from a book. And I am stuck on the meaning of this qustion. Assuming that you store integer values on the stac and that using a static array to store data provide a createStack() deleteStack(stack) methods.
My interpretation is
typedef struct {
int values;
char data[50];
} StackData;
typedef struct n {
StackData d; // store some data in node
struct n *successor; // store successor of node
// as typedef is not yet completed
// name StackNode cannot be used
} SatckNode;
typedef struct {
StackNode *head;
StackNode *current;
} Stacklist;
I know these arent the methods. But i want to know if I am going about it the right way
If you're using a static array for the values, then you don't technically need createStack() and deleteStack() functions, because you can just create a struct stack or whatever on the stack (pun intended) and you're done.
If you do want to, though, (and you might legitimately want to, e.g. to avoid having to explicitly initialize top, or to hide the implementation behind an opaque type, or to be able to return one from a function without copying a potentially large array) this'll do it:
#include <stdio.h>
#include <stdlib.h>
#define STACKSIZE 50
typedef struct stack * Stack;
struct stack {
size_t top;
int values[STACKSIZE];
};
Stack createStack(void)
{
Stack new_stack = malloc(sizeof *new_stack);
if ( !new_stack ) {
perror("couldn't allocate memory");
exit(EXIT_FAILURE);
}
new_stack->top = 0;
return new_stack;
}
void deleteStack(Stack stack)
{
free(stack);
}
void push(Stack stack, const int n)
{
if ( stack->top < STACKSIZE ) {
stack->values[stack->top++] = n;
}
else {
fprintf(stderr, "Stack full - exiting.\n");
exit(EXIT_FAILURE);
}
}
int pop(Stack stack)
{
if ( stack->top > 0 ) {
return stack->values[--stack->top];
}
else {
fprintf(stderr, "Stack empty - exiting.\n");
exit(EXIT_FAILURE);
}
}
int main(void)
{
Stack mystack = createStack();
push(mystack, 3);
push(mystack, 1);
push(mystack, 4);
push(mystack, 1);
push(mystack, 5);
for ( size_t i = 0; i < 5; ++i ) {
printf("Popped %d from stack.\n", pop(mystack));
}
deleteStack(mystack);
return 0;
}
Right now you seem to want a stack with values in a static array, but then you start defining structs for nodes and lists, as if you want a linked list implementation. The two implementations are obviously pretty different.
I think you're on the right way - just a couple of comments.
In Stacklist, I don't get why you have pointers to two of the nodes in the stack.
Usually, stacks only keep a reference to the item on the top of the stack.
In addition, they either keep a counter of how big is the stack, or a pointer to the node on the bottom of the stack (which is what you probably mean by head, and reference the head node by current?).
And don't forget to initialize everything whenever you create any of those structures :P usually ends up in endless hours of headache.
Keep up the good work.