I'm following this tutorial to write my own version of malloc and free. The full source code is here which I'm trying to run on my laptop.
I have 3 files:
mymalloc.h
mymalloc.c
memgrind.c // Where my main method is to test my malloc function
I try to compile it by executing the following on the command line:
gcc -c mymalloc.c
gcc -o memgrind.c memgrind
But I get the following errors:
warning: implicit declaration of function MyMalloc [-Wimplicit-function-declaration]
int *p=(int)MyMalloc(100*sizeof(int));
^~~~~~~~
memgrind.c:5:8: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
int *p=(int)MyMalloc(100*sizeof(int));
Am I compiling my files wrong? Or something wrong with the code? (The code I'm executing & compiling is no different to the source code provided in the link)
Thank you.
EDIT:
Now it is compiling correctly but I get this error:
/tmp/ccKyTOaY.o:(.data.rel.local+0x0): multiple definition of `freeList'
/tmp/cc0jpDeq.o:(.data.rel.local+0x0): first defined here
collect2: error: ld returned 1 exit status
But I'm only declaring it once inside of my mymalloc.h?
For reference, here is the code:
mymalloc.c
#include<stdio.h>
#include<stddef.h>
#include "mymalloc.h"
void initialize(){
freeList->size=20000-sizeof(struct block);
freeList->free=1;
freeList->next=NULL;
}
void split(struct block *fitting_slot,size_t size){
struct block *new=(void*)((void*)fitting_slot+size+sizeof(struct block));
new->size=(fitting_slot->size)-size-sizeof(struct block);
new->free=1;
new->next=fitting_slot->next;
fitting_slot->size=size;
fitting_slot->free=0;
fitting_slot->next=new;
}
void *MyMalloc(size_t noOfBytes){
struct block *curr,*prev;
void *result;
if(!(freeList->size)){
initialize();
printf("Memory initialized\n");
}
curr=freeList;
while((((curr->size)<noOfBytes)||((curr->free)==0))&&(curr->next!=NULL)){
prev=curr;
curr=curr->next;
printf("One block checked\n");
}
if((curr->size)==noOfBytes){
curr->free=0;
result=(void*)(++curr);
printf("Exact fitting block allocated\n");
return result;
}
else if((curr->size)>(noOfBytes+sizeof(struct block))){
split(curr,noOfBytes);
result=(void*)(++curr);
printf("Fitting block allocated with a split\n");
return result;
}
else{
result=NULL;
printf("Sorry. No sufficient memory to allocate\n");
return result;
}
}
void merge(){
struct block *curr,*prev;
curr=freeList;
while((curr->next)!=NULL){
if((curr->free) && (curr->next->free)){
curr->size+=(curr->next->size)+sizeof(struct block);
curr->next=curr->next->next;
}
prev=curr;
curr=curr->next;
}
}
void MyFree(void* ptr){
if(((void*)memory<=ptr)&&(ptr<=(void*)(memory+20000))){
struct block* curr=ptr;
--curr;
curr->free=1;
merge();
}
else printf("Please provide a valid pointer allocated by MyMalloc\n");
}
mymalloc.h
#include<stdio.h>
#include<stddef.h>
char memory[20000];
struct block{
size_t size;
int free;
struct block *next;
};
struct block *freeList=(void*)memory;
void initialize();
void split(struct block *fitting_slot,size_t size);
void *MyMalloc(size_t noOfBytes);
void merge();
void MyFree(void* ptr);
memgrind.c
#include<stdio.h>
#include "mymalloc.h"
int main(){
int *p=(int*)MyMalloc(100*sizeof(int));
char *q=(char*)MyMalloc(250*sizeof(char));
int *r=(int*)MyMalloc(1000*sizeof(int));
MyFree(p);
char *w=(char*)MyMalloc(700);
MyFree(r);
int *k=(int*)MyMalloc(500*sizeof(int));
printf("Allocation and deallocation is done successfully!");
}
the warining says that you try to put int into int * so
try this
int *p=(int*)MyMalloc(100*sizeof(int));
Related
I'm trying to create a stack in C using structures but the push() function I wrote is acting strangely. I'm sure it is something obvious that I'm missing but I just couldn't figure out what.
#include <stdio.h>
#define STACK_SIZE 50
typedef struct stack
{
int top;
int items[STACK_SIZE];
}
STACK;
void push(STACK* st, int newitem)
{
st->top++;
st->items[st->top] = newitem;
printf("%d", st->items[st->top]);
}
int main()
{
int n = 1;
STACK* st;
printf("test 1\n");
st->top = -1;
push(st, n);
printf("test 2\n");
return 0;
}
DevCpp only compiles but doesn't execute the code. OnlineGDB runs it but only prints the first test.
This is because your variable STACK* st; was never initialized properly.
Some Important Points:
Don't assign -1 to the length (top), 0 would be better
STACK* st; should be just STACK st;
Your function void push(STACK* st, int newitem) should be declared with static linkage.
Write st->top++
Pass st variable by address to the push() function
Instead of using bare return 0;, use return EXIT_SUCCESS;, which is defined in the header file stdlib.h.
As your total STACK_SIZE is only 50 so, int will be sufficient. But as your STACK_SIZE grows use size_t for your length(top).
use int main(void) { }, instead of int main() { }
NOTE: If STACK_SIZE and top becomes equal means your array is filled completely then further addition of data will lead to Undefined Behavior.
Final Code
#include <stdio.h>
#include <stdlib.h>
#define STACK_SIZE 50
typedef struct stack
{
int top;
int items[STACK_SIZE];
}
STACK;
static void push(STACK* st, int newitem)
{
if(st->top == STACK_SIZE)
{
fprintf(stderr, "stack size reached maximum length\n");
exit(EXIT_FAILURE);
}
st->items[st->top++] = newitem;
printf("%d\n", st->items[st->top - 1]); // we added +1 to `top` in the above line
}
int main(void)
{
int n = 1;
STACK st;
printf("test 1\n");
st.top = 0;
push(&st, n); //pass by address
return EXIT_SUCCESS;
}
There are three files :
test.c
#include "stack.h"
stackT s2;
StackInit(&s2, 15);
int main(){
stackT s1;
StackInit(&s1, 10);
StackDestroy(&s1);
return 0;
}
stack.h
typedef char stackElementT;
typedef struct {
stackElementT *contents;
int top;
int maxSize;
} stackT;
void StackInit(stackT *stackP, int maxSize);
void StackDestroy(stackT *stackP);
stack.c
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
void StackInit(stackT *stackP, int maxSize)
{
stackElementT *newContents;
newContents = (stackElementT *)malloc(sizeof(stackElementT) * maxSize);
if (newContents == NULL) {
fprintf(stderr, "Insufficient memory to initialize stack.\n");
exit(1);
}
stackP->contents = newContents;
stackP->maxSize = maxSize;
stackP->top = -1;
}
void StackDestroy(stackT *stackP)
{
free(stackP->contents);
stackP->contents = NULL;
stackP->maxSize = 0;
stackP->top = -1;
}
I really need to have an external stack and
stackT s2;
StackInit(&s2, 15);
in test.c is my attempt to declare that but compiler gives the following error.
test.c:4:11: error: expected declaration specifiers or ‘...’ before ‘&’ token
StackInit(&s2, 15);
^
test.c:4:16: error: expected declaration specifiers or ‘...’ before numeric constant
StackInit(&s2, 15);
^~
Here is what I have tried:
I declared stack s1 inside the main function and didn't get any errors for that.
I deleted #include "stack.h" in test.c and I got
the same error for the external stack s2.
So my questions are:
What is the error for? How can I declare the external stack without any errors?
You can't call functions at top-level in C, you can only have declarations and definitions. Move the call to StackInit() into the main() function.
#include "stack.h"
stackT s2;
int main(){
stackT s1;
StackInit(&s1, 10);
StackInit(&s2, 15);
StackDestroy(&s1);
StackDestroy(&s2);
return 0;
}
A function can only be called from another function. Imagine functions call like a tree in which the root node is the main() function.
Anyway, besides moving the initialization inside main(), if you really want the struct variable definition outside main you can statically initialize it, just doing what StackInit() would do: a stackElementT array of size 15, contents field pointing to the first element, and the top index initialized to -1.
#include "stack.h"
stackElementT elements[15];
stackT s2 = { elements, -1, 15};
int main(){
stackT s1;
StackInit(&s1, 10);
StackDestroy(&s1);
return 0;
}
So I have these three files
Main.c
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include "support.h"
int main( void ) {
int* num1 = malloc(100);
printf("num1: %p", &num1);
}
Support.c
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "support.h"
void *malloc(size_t size) {
struct block_meta *block;
if (size <= 0) {
return NULL;
}
if (!global_base) { // First call.
block = request_space(NULL, size);
if (!block) {
return NULL;
}
global_base = block;
} else {
struct block_meta *last = global_base;
block = find_free_block(&last, size);
if (!block) { // Failed to find free block.
block = request_space(last, size);
if (!block) {
return NULL;
}
} else { // Found free block
block->free = 0;
block->magic = 0x77777777;
}
}
return(block+1);
}
void free(void *ptr) {
if (!ptr) {
return;
}
struct block_meta* block_ptr = get_block_ptr(ptr);
assert(block_ptr->free == 0);
assert(block_ptr->magic == 0x77777777 || block_ptr->magic == 0x12345678);
block_ptr->free = 1;
block_ptr->magic = 0x55555555;
}
void *realloc(void *ptr, size_t size) {
if (!ptr) {
// NULL ptr. realloc should act like malloc.
return malloc(size);
}
struct block_meta* block_ptr = get_block_ptr(ptr);
if (block_ptr->size >= size) {
// We have enough space. Could free some once we implement split.
return ptr;
}
// Need to really realloc. Malloc new space and free old space.
// Then copy old data to new space.
void *new_ptr;
new_ptr = malloc(size);
if (!new_ptr) {
return NULL; // TODO: set errno on failure.
}
memcpy(new_ptr, ptr, block_ptr->size);
free(ptr);
return new_ptr;
}
void *calloc(size_t nelem, size_t elsize) {
size_t size = nelem * elsize; // TODO: check for overflow.
void *ptr = malloc(size);
memset(ptr, 0, size);
return ptr;
}
Support.h
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
void *malloc(size_t size);
void free(void *ptr);
void *realloc(void *ptr, size_t size);
struct block_meta {
size_t size;
struct block_meta *next;
int free;
int magic; // For debugging only. TODO: remove this in non-debug mode.
};
#define META_SIZE sizeof(struct block_meta)
void *global_base = NULL;
struct block_meta *find_free_block(struct block_meta **last, size_t size) {
struct block_meta *current = global_base;
while (current && !(current->free && current->size >= size)) {
*last = current;
current = current->next;
}
return current;
}
struct block_meta *request_space(struct block_meta* last, size_t size) {
struct block_meta *block;
block = sbrk(0);
void *request = sbrk(size + META_SIZE);
assert((void*)block == request); // Not thread safe.
if (request == (void*) -1) {
return NULL; // sbrk failed.
}
if (last) { // NULL on first request.
last->next = block;
}
block->size = size;
block->next = NULL;
block->free = 0;
block->magic = 0x12345678;
return block;
}
struct block_meta *get_block_ptr(void *ptr) {
return (struct block_meta*)ptr - 1;
}
However when I attempt to compile using
gcc -o asgn2 main.c support.c
I get the error
/tmp/ccscmcbS.o:(.bss+0x0): multiple definition of `global_base'
/tmp/ccyjhjQC.o:(.bss+0x0): first defined here
/tmp/ccscmcbS.o: In function `find_free_block':
support.c:(.text+0x0): multiple definition of `find_free_block'
/tmp/ccyjhjQC.o:main.c:(.text+0x0): first defined here
/tmp/ccscmcbS.o: In function `request_space':
support.c:(.text+0x55): multiple definition of `request_space'
/tmp/ccyjhjQC.o:main.c:(.text+0x55): first defined here
/tmp/ccscmcbS.o: In function `get_block_ptr':
support.c:(.text+0xfe): multiple definition of `get_block_ptr'
/tmp/ccyjhjQC.o:main.c:(.text+0xfe): first defined here
collect2: error: ld returned 1 exit status
I dont believe that I declared those methods more than once, also it is in a much different format than I am usually given. Not quite sure what it means.
The problem is that you have functions and globals defined (as opposed to declared) in your header file. Therefore, those functions are pulled into both main.c and support.c when they are compiled. Then during the linking phase, the linker sees multiple definitions.
Even if you had include guards, it wouldn't help in this case because that only defends against multiple definitions in a single compilation unit, not across multiple units.
Take the definitions of those function out of the header file, replace them with declarations, and put them either in support.c or in a separate .c file.
You can use the -fcommon option for gcc.
Make sure that the header is included only once, so add something like the following to the headers source code:
#ifndef _HAVE_SUPPORT_H
#define _HAVE_SUPPORT_H
// ...
// YOUR HEADER SOURCE CODE
// ...
#endif //_HAVE_SUPPORT_H
As I said this makes sure that the header is included only once, because then it defines _HAVE_SUPPORT_H. If now another source tries to include it, it will not do anything because _HAVE_SUPPRORT_H is already defined.
It also helps if you have only function declarations in the header and your 'real' functions will be in another *.c file.
Edit:
The second parts is the most important for your problem as #kaylum noticed
For me the solution was simple, downgrade to previous GCC version.
Here is comparison gcc installed on two different Ubuntu version.
GCC for ubuntu 20.04: https://packages.ubuntu.com/focal/gcc (gcc 9)
GCC for ubuntu 22.04: https://packages.ubuntu.com/jammy/gcc (gcc 11)
Because on my case, code was legacy code from about 20 years ago, then it makes sense for me to keep using old compiler.
I need to write a program using C and CUnit to test some simple stack functions and using "Makefile" but when I try to compile it, I always get the same errors. The terminal on ubuntu show this when I write the "make" command:
gcc -o Pilhaa_teste.o Pilhaa_teste.c -lcunit
/tmp/ccLqNqAx.o: In function `main':
Pilhaa_teste.c:(.text+0x21): undefined reference to `clean_suite1'
Pilhaa_teste.c:(.text+0x26): undefined reference to `init_suite1'
Pilhaa_teste.c:(.text+0x50): undefined reference to `testaTOP'
The .h that I wrote is:
typedef struct No {
struct No *prox;
int info;
}no;
typedef struct pilha {
no *topo;
}Pilha;
int init_suite1(void);
int clean_suite1(void);
void testaTOP(void);
/*create empty stack*/
Pilha *cria_pilha(void);
/*add one element to the stack*/
void push (Pilha *p, int valor);
/*free first element of stack*/
void pop (Pilha *p);
/*print and find first element*/
int top (Pilha *p);
/*free stack*/
void libera(Pilha *p);
/*print stack*/
void imprime(Pilha *p);
the .c with the main code:
#include <stdlib.h>
#include <stdio.h>
#include "pilha.h"
#include "CUnit/Basic.h"
int main(){
CU_pSuite pSuite = NULL;
if (CUE_SUCCESS != CU_initialize_registry())
return CU_get_error();
pSuite = CU_add_suite("Suite_1", init_suite1, clean_suite1);
if(NULL == pSuite){
CU_cleanup_registry();
return CU_get_error();
}
if(NULL == CU_add_test(pSuite, "test of top()", testaTOP)){
CU_cleanup_registry();
return CU_get_error();
}
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
CU_cleanup_registry();
return CU_get_error();
}
and the clean_suite1, init_suite1 and testaTOP functions:
static Pilha *p = NULL;
int init_suite1(void){
push(p, 6);
if(p!=NULL)
return 0;
else
return 1;
}
int clean_suite1(void){
pop(p);
if (p == NULL)
return 0;
else
return 1;
}
void testaTOP(void){
Pilha *p = NULL;
push (p, 6);
if (p != NULL){
CU_ASSERT(top(p) == 6);
push (p, 7);
if (p != NULL)
CU_ASSERT(top(p) ==7 );
}
no *aux = p->topo->prox;
free(p);
free(aux);
}
the basic functions, push, pop and others are written but there are no problems with them. They were previously used in another program of mine.
gcc -o compiles and links your sources, so either add the .c where functions are implemented or compile separately with gcc -c, which doesn't link source files.
I am a beginner of c programming. I can to write my own malloc function and I put main method code one. It gives following error.
test.c: In function ‘main’:
test.c:38:30: error: ‘size’ undeclared (first use in this function)
test.c:38:30: note: each undeclared identifier is reported only once for each function it appears in
code
/*An horrible dummy malloc*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void *malloc(size_t size);
void *malloc(size_t size){
void *p;
p = sbrk(0);
//if sbrk dails , we return null
if(sbrk(size)==(void*)-1){
return NULL;
}
printf("wada\n");
return p;
}
typedef struct s_block *t_block;
struct s_block{
size_t size;
t_block next;
int free;
};
int main(){
malloc(50);
malloc(100);
t_block b;
b = sbrk(0);
sbrk(sizeof(struct s_block)+size);//Error line (code 1)
b->size = size; //Error Line
return 0;
}
In this line: sbrk(sizeof(struct s_block)+size) you use a variable size that you have not defined anywhere. This is clearly stated in the error message.
BTW you should call your function something instead of malloc.