Usage of Structures in C - c

I am reading the script on the implementation of malloc (first-fit), and I am a little confused about the value assignment of metadata structure. Could anyone give some explanations why the malloc returns flag_block->ptr (as a pointer to the allocated memory)? As far as I can see, there is no specific assignment to it.
typedef struct _metadata {
size_t size;
char free;
struct _metadata* next;
struct _metadata* prev;
char ptr[];
} metadata;
metadata* flag_block = NULL;
void *malloc(size_t size)
{
if (size==0) {
return NULL;
}
if (flag_block == NULL) {
flag_block = sbrk(size);
sbrk(sizeof(metadata));
if (flag_block == (void *)-1) {
return NULL;
}
flag_block->free = 0;
flag_block->next=NULL;
flag_block->prev=NULL;
flag_block->size = size;
return flag_block->ptr;
} else {
/*
....
*/
}
}

The ptr is called a flexible array member; it's an array without a size, and can only appear at the end of a struct.
So basically this:
return flag_block->ptr;
is equivalent to
return &flag_block->ptr[0];
So it's returning the address of the first byte after the rest of the members in the struct.

Related

How to check if a list is empty? If I do "if (ptr!=NULL)" it doesn't work [duplicate]

Usually, when I use linked lists, I write:
struct node *startPtr = NULL;
so I check later if is it NULL, and if it is, it means that the list is empty.
But in this code:
struct card{
char face[3];
char suit[4];
};
typedef struct card Card;
struct stack{
Card cardd;
struct stack *nextPtr;
};
typedef struct stack Stack;
int main(){
/*
creation of *stacks also with calloc
*/
Stack *topstacks = calloc(4,sizeof(Stack)); // array of lists initialized by calloc
/*
scanf pos1, pos2 to switch
*/
move_card(stacks, topstacks, pos1, pos2);
}
int move_card(Stack *stacks, Stack *topstacks, unsigned int pos1, unsigned int pos2){
Stack *prevfromPtr;
Stack *fromPtr = &(stacks[pos1]);
Stack *toPtr = &(topstacks[pos2]);
while(fromPtr->nextPtr!=NULL){
prevfromPtr = fromPtr;
fromPtr = fromPtr->nextPtr;
}
Stack *newmovingcard = calloc(1,sizeof(Stack));
newmovingcard->cardd = fromPtr->cardd;
newmovingcard->nextPtr = NULL;
if (toPtr!=NULL){ // here I'd like to check if the list is empty and has not any item. This way it does not work because toPtr can't be NULL, it's a pointer
while(toPtr->nextPtr!=NULL){
toPtr = toPtr->nextPtr;
}
toPtr->nextPtr = newmovingcard;
free(fromPtr);
prevfromPtr->nextPtr = NULL;
return 0;
} else {
toPtr->cardd = newmovingcard->cardd;
toPtr->nextPtr = NULL;
free(fromPtr);
prevfromPtr->nextPtr = NULL;
return 0;
}
}
I have an array of lists (topstacks), initialized with calloc. And in the commented line inside move_card, I need to check if the single list of the array of lists is empty. But I don't know how to do that.
Here is the full code, but some parts with printf are in italian, so sorry for that: https://wtools.io/paste-code/b2gz
You can try to assign nextPtr to the same element or you can introduce a special global item which will mean an empty list.
If you use malloc with memset instead of calloc you can set your value as your own "void" value.
I mean this kind of thing :
int* example;
example=malloc(100*sizeof(int)); // allocate memory to store 100 int
if(example){
memset(example,1,100*sizeof(int)); // initialize it with value 1
}
Working with two linked lists simultaneously is kind of fussy and annoying, but it is doable:
int move_card(Stack **source, Stack **target, int source_pos, int target_pos) {
// Walk through the linked list, but in every case stop one short of the
// insertion point
// Walk through the source chain and identify which pointer needs
// to be manipulated.
for (int i = 0; i < source_pos; ++i) {
if (*source == NULL) {
return -1;
}
source = &((*source)->nextPtr);
}
// Walk through the target chain and identify the insertion point.
for (int i = 0; i < target_pos - 1; ++i) {
if (*target == NULL) {
return 1;
}
target = &((*target)->nextPtr);
}
// Capture the pointer we're actually moving
Stack* moving = *source;
// Skip this link in the chain by reassigning source
*source = moving->nextPtr;
// Capture the record that's being bumped
Stack* bumped = *target;
// Reassign the target
*target = moving;
// Re-link the bumped entry back in the chain
moving->nextPtr = bumped;
return 0;
}
Where I've taken the liberty of renaming a few things to make this easier to understand. Notice how it uses a double pointer so it can manipulate the original pointers if necessary. When removing the first card from a linked list, the pointer to the "head" entry must change.
Here's a more complete "demo" harness for that code:
#include <stdio.h>
#include <stdlib.h>
struct stack {
char card[2];
struct stack *nextPtr;
};
typedef struct stack Stack;
Stack* make_stack(char face, char suit, Stack* nextPtr) {
Stack* stack = calloc(1, sizeof(Stack));
stack->card[0] = face;
stack->card[1] = suit;
stack->nextPtr = nextPtr;
return stack;
}
void print_stack(Stack* stack) {
while (stack) {
printf("%c%c ", stack->card[0], stack->card[1]);
stack = stack->nextPtr;
}
printf("\n");
}
int main(int argc, char** argv) {
Stack* source = make_stack('A', 'S', make_stack('2', 'S', make_stack('3', 'S', NULL)));
Stack* target = NULL;
print_stack(source);
move_card(&source, &target, 2, 0);
print_stack(source);
print_stack(target);
return 0;
}
Where that uses a simplified Card model.

custom malloc function for c

I try to write my own custom malloc and free function in c. I worked around 12 hours on this and tried lots of things. But it doesn't work.
Maybe you guys can figure out the error. Allocated memory gets removed from the list with a next pointer to a specific address to identify it later in the free function. The current error is a segmentation fault 11 in the split method.
C-File:
Head:
#define MAGIC ((void*)0xbaadf00d)
#define SIZE (1024*1024*1)
typedef struct mblock {
struct mblock *next;
size_t size;
char memory[];
}mblock;
char memory[SIZE];
static struct mblock *head;
malloc:
void *halde_malloc (size_t size) {
printf("Starting\n");
printf("%zu\n",size);
if(size <= 0) {return NULL;}
if(head == NULL){
initializeBlock();
printf("Memory initialized\n");
}
mblock *temp_block = head;
while(temp_block != NULL) {
printf("IN\n");
if(temp_block->size == size) {
list_remove(temp_block);
temp_block->next = MAGIC;
return (void*)(temp_block);
} else if(temp_block->size > size) {
size_t temp_size = temp_block->size;
printf("size IS more than equal\n");
list_split_AND_Remove(temp_size - size, temp_block);
temp_block->size = size;
temp_block->next = MAGIC;
return (void*)(temp_block);
}
temp_block = temp_block->next;
printf("One block checked\n");
}
errno = ENOMEM;
return NULL;
}
Initialize:
void initializeBlock(){
printf("Initializing\n");
head = (mblock*)memory;
head->size=sizeof(memory)-sizeof(mblock);
head->next=NULL;
}
Split:
void list_split_AND_Remove(size_t size, mblock *lastBlock) {
printf("Split\n");
mblock *new = (void*)((mblock*)lastBlock+size+sizeof(mblock));
new->size = size - sizeof(mblock);
new->next = lastBlock->next;
lastBlock->next = new;
printf("START REMOVE");
list_remove(lastBlock);
}
Remove:
void list_remove(mblock *p) {
printf("Remove\n");
mblock *temp_block = head;
if(p == head) {
if(head->next == NULL) {
head = NULL;
return;
} else {
head = p->next;
return;
}
}
while(temp_block->next != NULL) {
if(temp_block->next == p) {
printf("Found P:");
temp_block = p->next;
return;
}
temp_block = temp_block->next;
}
}
Free:
void halde_free (void *ptr) {
printf("FREE\n");
mblock *new_block = ptr;
if(new_block->next == MAGIC) {
new_block->next = head;
head = new_block;
} else {abort();}
}
Issues with your code include, but are not necessarily limited to:
list_remove() does not actually remove the specified block from the list unless it happens to be the current list head. In every other case, therefore, halde_malloc() corrupts the list after calling list_remove() when it modifies the node's next pointer.
list_split_AND_Remove() performs incorrect pointer arithmetic. Specifically, mblock *new = (void*)((mblock*)lastBlock+size+sizeof(mblock)); does not do what you appear to want to do, because pointer arithmetic operates in units the size of the pointed-to type, whereas the size argument and the result of the sizeof operator have units of individual bytes. (Also, both casts are useless, albeit not harmful in themselves.)
Your allocator returns a pointer to the block header, not to its data. As a result, the user will very likely overwrite the block header's contents, leading to havoc when you later try to free that block.
You seem to assume that mblock objects have an alignment requirement of 1. That might not be true.

Passing a struct to multiple other functions

I'm relatively new to programming and I am having some issues passing my struct to other functions. Here is what my actual code looks like:
typedef struct Memcheck {
char *memoryAdd;
char *file;
int line;
struct Memcheck_struct *next;
} Memcheck;
char *strdup2( char *str )
{
char *new;
new = malloc( strlen(str)+1 );
if (new)
strcpy( new, str );
return new;
}
/*Allocate memory for a ptr, and add it to the top of the linked list*/
void *memcheck_malloc(size_t size, char *file, int line){
Memcheck * new_memoryCheck = NULL;
Memcheck * head = NULL;
head = malloc(sizeof(Memcheck));
new_memoryCheck = malloc(sizeof(Memcheck));
new_memoryCheck->memoryAdd = malloc(sizeof(new_memoryCheck->memoryAdd));
new_memoryCheck->file = malloc(sizeof(new_memoryCheck->file));
new_memoryCheck->file = strdup2(file);
new_memoryCheck->line = line;
new_memoryCheck->next = head;
return new_memoryCheck;
}
/*Prints the error messages*/
void printList(Memcheck *new_memoryCheck) {
Memcheck * head = NULL;
Memcheck * current = head;
head = malloc(sizeof(Memcheck));
current = malloc(sizeof(Memcheck));
printf("new_mem file: %s\n", new_memoryCheck->file);
printf("current file: %s\n", current->file);
while (current != NULL) {
printf("in loop\n");
printf("memcheck error: memory address %p which was allocated in file \"%s\", line %d, was never freed\n", current, current->file, current->line);
current = current->next;
}
}
int memcheck_main(Memcheck new_memoryCheck){
printf("newmem file: %s\n", new_memoryCheck.file);
printf("Entering printList\n");
printList(&new_memoryCheck);
return 0;
}
I have strdup2 because apparently ansi doesn't have stdrup.
I know to use pass by reference to some degree but I'm not exactly sure where to use the * and & operators
Since it appears that you are writing a surrogate for malloc() that records which memory was allocated where, you probably need code similar to:
typedef struct Memcheck Memcheck;
struct Memcheck
{
void *data;
size_t size;
const char *file;
int line;
Memcheck *next;
};
static Memcheck *memcheck_list = 0;
/* Allocate memory and record the allocation in the linked list */
void *memcheck_malloc(size_t size, const char *file, int line)
{
Memcheck *node = malloc(sizeof(*node));
void *data = malloc(size);
if (node == 0 || data == 0)
{
free(node);
free(data);
return 0;
}
node->data = data;
node->size = size;
node->file = file;
node->line = line;
node->next = memcheck_list;
memcheck_list = node;
return data;
}
Note that if either (or both) memory allocations fails, the memory is all freed before returning. Using free() on a null (0) pointer is a no-op. Thus the clean-up is safe. The information can simply be copied into the structure as shown; no need for extra memory allocations for the file name, for example, as long as you pass __FILE__ to the function (which is a string literal, and therefore has a lifetime as long as the rest of the program).

How to allocate memory for a structure inside another structure?

I have 2 structures in my C code. I want to write a hash function with these 2 structures. So I want to initialize my data null in first case. My code is
struct HashNode
{
char username[20];
char password[20];
};
struct HashTable
{
int size;
struct HashNode *table;
};
HashTable *initializeTable(int size)
{
HashTable *htable;
if (size < MIN_TABLE_SIZE)
{
printf("Table Size Small\n");
return NULL;
}
htable = (HashTable *)malloc(sizeof(Hashtable));
if (htable == NULL)
{
printf("memory allocation pblm\n");
return NULL;
}
htable->size = size;
}
How can I allocate memory for htable->table with that size? I have code in C++ like htable->table = new HashNode [htable->size];. How can I write this in C using malloc?
You can allocate the memory in this way
htable->table = malloc(size*sizeof(HashNode))

initialization of flexible array of struct pointers in a struct in c

I'm learning hashtable data structures and I want to make a hashtable with a flexible length array of pointers to struct Link (linked list pieces), so that hashtable initialization will set the array to be a length input into the initialization function.
At first I was getting the error "flexible array not at the end of struct". When its at the end (as shown) the program crashes (but it still compiles). This is my code:
typedef struct Link{
int key;
char *name;
struct Link *next;
} Link;
typedef struct HashTable{
int numberOfEntries;
int numberOfBuckets;
Link *Table[];
} HashTable;
HashTable *hashtableInit(int size){
HashTable *newHT = malloc(sizeof(HashTable));
if (newHT != NULL){
newHT->numberOfEntries = 0;
newHT->numberOfBuckets = size;
for (int i = 0; i < newHT->numberOfBuckets; i += 1){
newHT->Table[i] = NULL;
}
return newHT;
} else {
printf("Error in memory allocation.\n");
fflush(stdout);
return NULL;
}
}
}
It works if I set the array to a constant and input the same value into the init function:
#define SIZE 11
typedef struct Link{
int key;
char *name;
struct Link *next;
} Link;
typedef struct HashTable{
Link *Table[SIZE];
int numberOfEntries;
int numberOfBuckets;
} HashTable;
HashTable *hashtableInit(int size){ // works if SIZE is passed into function as size parameter
HashTable *newHT = malloc(sizeof(HashTable));
if (newHT != NULL){
newHT->numberOfEntries = 0;
newHT->numberOfBuckets = size;
for (int i = 0; i < newHT->numberOfBuckets; i += 1){
newHT->Table[i] = NULL;
}
return newHT;
} else {
printf("Error in memory allocation.\n");
fflush(stdout);
return NULL;
}
}
}
The second code block works perfectly. Any insights would be greatly appreciated. Thanks for your time.
Chris
You should allocate memory as
HashTable *newHT = malloc(sizeof *newHT + size * sizeof newHT->Table[0]);
Your
HashTable *newHT = malloc(sizeof(HashTable));
is wrong, because no space is given for the flexible array member. Should probably be
HashTable *newHT = malloc(sizeof(HashTable)+size*sizeof(Link*));

Resources