Reputation: 463
Look at the second edit part.
I'm beginner of C (since I almost always use Python). So my question is (I can say) simple about malloc and memory...
// where the built-in malloc declared
#include <stdlib.h>
int main() {
char* data = malloc(13); // with standard malloc
}
Let say I don't want to use stdlib.h
and instead I make my own code for malloc which return ONLY the memory address in a file called memory.h
void* malloc(int size) {
return (__malloc_memory += size);
}
This function malloc
returns the address, where __malloc_memory
is basically 6487580 [__malloc_memory is basically memory address] (tested by declaring some stuff). So, it is okay to do like this? If not, then why?
// my declaration of new malloc
#include <memory.h>
int main() {
char* data = malloc(14); // This is the new defined malloc, not the built-in one
data[0] = 'H';
// some stuff
data[12] = '!';
data[13] = '\0'; // Null terminate
printf("%s", data);
}
Output
Hello, world!
The output will return the same everytime.
EDIT 1:
// memory.h
static int __malloc_memory = 6487580;
void* malloc(int size) {
return (__malloc_memory += size);
}
And main.c
int main() {
double* name = (char*)malloc(1);
name[0] = 3.4555;
printf("%lf", name[0]);
}
OUTPUT
3.455500
EDIT 2:
This question sucks. Now I understand what I made is a very basic mistake, since now I understand how an Operating System work (and of course how to make one using Assembly, but not fully). I will not delete this question, since that is very disrespectful. [And why the heck I cast malloc [in C]...? For what I know, I never do that.] [Now (as per 07-07-2021), I would call myself a C intermediate (not expert yet).]
Upvotes: 0
Views: 167
Reputation: 148880
Unless you know the reason, avoid playing with magic addresses. So this terrible code:
// memory.h
static int __malloc_memory = 6487580;
void* malloc(int size) {
return (__malloc_memory += size);
}
When you use a magic address, you should always add a comment explaining where it came from (physical io port in real or kernel mode, etc.)
But in the old times where the OS did not know about virtual memory or multi-processing, it was common to use a pre-allocated compile-time defined memory zone as a local heap and allocate from there. If you want to learn about the allocation internal details, you can try something like that:
HEAPSIZE = 65536;
char heap[HEAPSIZE];
char *cur_heap = heap;
char *malloc(int size) {
char *ret = cur_heap;
if (cur_heap + size > heap + HEAPSIZE) { // no more memory to allocate
return NULL;
}
cur_heap += size;
return ret;
}
From that point you will soon realize that with such a simple malloc
there is no way to free anything, and next that free blocks should be managed in a list or some other container structure. If you reach that point, and before trying to invent an oval wheel when round wheels exist, you should have a look to the sources of malloc in any C library implementation. And after you will have builded a functional malloc
free
pair, you will have learned a lot...
BTW: 65535 was the size of a segment for the old 80x86 architectures...
Upvotes: 2
Reputation: 612
Basically, you want to allocate memory, but not with malloc()
, but your own way. Fine. There are many things in play here, but I will try not to leave out or include too much.
When your program starts (when enters main()
) function it already has some memory to work with. How come? When OS creates a new process it allocates a bit of memory for it. How much is needed can be figured out from the executable file which consists of several parts: code (.text
segment), static data, etc. Now you're left on your own to allocate memory if you need it.
Well, not really. Program doesn't really start with main()
. If you put a break at the start of main()
and run your program in debugger you will see that you are not at the top (or bottom, depending on representation) of the stack. Some things were called before. One of those things is initialization of libc
and very likely that has already done some allocating using malloc()
and other means.
When you figured out that using 6487580 == 0x62fe1c
was OK you just managed to find a location that was mapped to your process and very likely allocated by someone else. C standard library is capable of many things and it is very possible that by using this location, while corrupting something, you stepped on a part that you will not be using in your program, so things will seem just fine. In a way they are, but your approach is neither very portable (on a different OS, or even with a different compiler things would not be OK).
But I get your point -- you want to do your own thing. Ultimately, if libc
can, why not you, right?
Here is one way you could do it bypassing libc
: use sbrk().
static const unsigned int my_total_needs = 100;
static void *__malloc_memory = sbrk(my_total_needs);
if ( __malloc_memory == (void *)-1 )
perror("Couldn't allocate memory.\n");
else {
/* Do your thing. */
}
You asked OS for 100 bytes and if you got them then it is up to you to do with them as you please. You can now write your own malloc()
that will use smaller c hunks out of these 100 bytes to give to whoever calls it. You can also write your own free()
that will mark no longer needed chunks as available. Basically, you will write your own memory manager that will manage those 100 bytes. If you need more you can either ask for more at the start or call sbrk()
again and ask for increase.
This is fun exercise, but good luck doing it better than experts. libc
and other libraries are optimized for regular use which means that if you have a very special case you can maybe do better.
Upvotes: 4