I have to implement a contructor function in c based upon this struct:
struct Node {
char name[MAX_NAME_LEN + 1];
NodeType type;
union {
struct {
Entry* entries; // list of directory entries
} dir;
struct {
void* contents; // any binary data of the given length
int length;
} file;
};
};
Now I want to build a constructor function to file, point to the contents and save the length in bytes but somehow I don't know how to do it...
Here is my Attempt:
i KNOW that i have to allocate space for this but how do i make this pointer stuff?
Node* new_file(char* name) {
Node* ptr_file = xmalloc(sizeof(Node));
ptr_file->name;
return NULL;
}
You need to typedef struct { ... } Node for your code to compile.
When using anonymous structs/unions you simply don't give a name for the anonymous member. ptr_file->dir.entries or ptr_file->file.contents.
Should you ditch the internal struct names and make those anonymous as well you would only need to type ptr_file->entries;.
Please note that anonymous structs/unions were added to the C language in the ISO 9899:2011 version of the language, so you need to use a fairly modern compiler to use them.
As a side note, the void* probably doesn't make any sense. What I think that you are trying to do is this:
#include <stdint.h>
typedef struct {
char name[MAX_NAME_LEN + 1];
NodeType type;
union {
struct {
Entry* entries; // list of directory entries
};
struct {
uint8_t contents [sizeof(Entry)]; // use to inspect raw data
int length; // probably not needed
};
};
} Node;
With Node* new_file(char* name), Node is not yet defined. Code needs typedef struct Node Node; or the like.
A big challenge to this task is the many potential errors that could creep in: file name too long, memory allocation failure, fopen open failure, read failure, file too long, ...
int length; should be size_t length; as files may be longer than INT_MAX, yet fit in an allocation.
new_file(char* name) looks like it should read a file. Let's make a helper function as there are various degrees of robustness needed. The below commonly "works" yet is technical UB (seeking to the end of a binary file). Adjust as needed.
Illustrative, untested code:
// The below does _not_ return a null character appended string,
// just the data in the file.
void *alloc_file(const char *file_name, size_t *size) {
*size = 0;
FILE *binary_stream = fopen(file_name, "rb");
if (binary_stream == NULL) {
return NULL;
}
long offset = fseek(binary_stream, SEEK_END);
rewind(binary_stream);
if (offset == -1 || (unsigned long) offset > SIZE_MAX) {
fclose(binary_stream); // Trouble or file too long
return NULL;
}
size_t file_size = (size_t) offset;
void *buf = malloc(file_size) {
fclose(binary_stream);
return NULL;
}
if (fread(buf, 1, file_size, binary_stream) != file_szie) {
fclose(binary_stream);
free(buf);
return NULL;
}
*size = file_size;
fclose(binary_stream);
return buf;
}
Now new_file is easier.
// Better as: Node* new_file(const char* name)
Node* new_file(char* name) {
if (strlen(name) >= MAX_NAME_LEN) {
return NULL // name too long
}
// Allocate to the size of the referenced object, not type.
Node* ptr_file = malloc(sizeof ptr_file[0]);
if (ptr_file == NULL) {
return NULL;
}
strcpy(ptr_file->name, name);
ptr_file->type = NodeType_file; // Some constant (OP has not shown yet).
size_t size = 0;
ptr_file->file.contents = alloc_file(name, &size);
if (ptr_file->file.contents == NULL || size > INT_MAX) {
free(ptr_file->file.contents);
free(ptr_file);
return NULL;
}
ptr_file->length = (int) size;
return ptr_file;
}
Related
I have an ArrayList struct and Department struct that go as follows:
typedef struct ArrayList {
void** elements;
int size;
int length;
} ArrayList;
typedef struct Department {
char* name;
ArrayList* courses;
} Department;
To print my list, I'm using these two methods:
void* get(ArrayList* arraylist, int i) {
if (i < 0 || i >= arraylist -> size) {
return (void*) NULL;
}
return arraylist -> elements[i];
}
void printAL(ArrayList* arraylist) {
for (int i = 0; i < arraylist -> size; i++) {
printf("%s\n", (char*) get(arraylist, i));
}
}
The issue I'm facing, however, is that when I add a Department to my ArrayList, the line 'return arraylist -> elements[i];' returns the address of that struct. I'm trying to get it to print the name of the struct using 'return arraylist -> elements[i] -> name' but I keep getting a warning that I'm dereferencing a void* pointer, followed by an error that says 'request for member ‘name’ in something not a structure'. This obviously means that 'arraylist -> elements[i]' isn't a struct but rather an address. How can I reference the name of the struct at that address then? I'm quite confused because of the double pointer in the ArrayList struct.
TIA!
You need different printing functions for each different type of data element that could be in the ArrayList. You need one function to print departments; you need a different function to print courses. You pass the function pointer to the printing function — printAL() — along with a pointer to other data (which in this case is probably just a FILE *, but could be a more general structure).
This is analogous to the qsort() function in standard C. It can sort any data type; you just need to pass it a different comparator function for different data types.
Like this:
#include <stdio.h>
#include <stdlib.h>
typedef struct ArrayList
{
void **elements;
int size; /* Allocated size */
int length; /* Space in use */
} ArrayList;
typedef struct Department
{
char *name;
ArrayList *courses;
} Department;
static void *get(ArrayList *arraylist, int i)
{
if (i < 0 || i >= arraylist->size)
return NULL;
return arraylist->elements[i];
}
static void printAL(ArrayList *arraylist, void (*function)(const void *data, void *thunk), void *thunk)
{
for (int i = 0; i < arraylist->length; i++)
{
(*function)(get(arraylist, i), thunk);
}
}
static void put(ArrayList *al, void *data)
{
if (al->length >= al->size)
{
size_t new_size = (al->size + 2) * 2;
void *new_data = realloc(al->elements, new_size * sizeof(void *));
if (new_data == 0)
{
fprintf(stderr, "Failed to allocate %zu bytes memory\n", new_size * sizeof(void *));
exit(1);
}
al->elements = new_data;
al->size = new_size;
}
al->elements[al->length++] = data;
}
/*
typedef struct Course
{
const char *name;
const char *code;
// ...
} Course;
static void print_courseinfo(const void *data, void *thunk)
{
FILE *fp = thunk;
const Course *cp = data;
fprintf(fp, " - %s (%s)\n", cp->name, cp->code);
}
*/
static void print_deptname(const void *data, void *thunk)
{
FILE *fp = thunk;
const Department *dp = data;
fprintf(fp, "Name: %s\n", dp->name);
/*
if (dp->courses != 0)
printAL(dp->courses, print_courseinfo, thunk);
*/
}
int main(void)
{
ArrayList al = { 0, 0, 0 };
Department dl[] =
{
{ "Engineering", 0 },
{ "Physics", 0 },
{ "Mathematics", 0 },
{ "Chemistry", 0 },
{ "Biology", 0 },
{ "English", 0 },
{ "Computational Astronomy and Universe-Scale Data Modelling", 0 },
{ "Economics", 0 },
};
enum { DL_SIZE = sizeof(dl) / sizeof(dl[0]) };
for (size_t i = 0; i < DL_SIZE; i++)
put(&al, &dl[i]);
printAL(&al, print_deptname, stdout);
return 0;
}
Sample output:
Name: Engineering
Name: Physics
Name: Mathematics
Name: Chemistry
Name: Biology
Name: English
Name: Computational Astronomy and Universe-Scale Data Modelling
Name: Economics
You didn't document what the length and size members of the ArrayList represent. I've annotated what I've assumed, but I had to change the printAL() function to iterate over length elements instead of size elements, so I may have inverted the meaning you intended. It's easy to reverse them. I tend to use names like max_elements and num_elements for the job; it is more obvious what they're for, perhaps, since length and size are ambiguous or even equivalent in many contexts.
There's skeletal code in there to show how to handle the ArrayList of courses offered by each department. I couldn't be bothered to write code to initialize a separate ArrayList for each department, though it wouldn't be particularly hard to do.
I still prefer the pre-standard notation (*funcptr)(arg1, arg2) notation for invoking a function designated by a function pointer — it was necessary when I learned C, and I still find it clearer than the alternative. You're excused if you prefer funcptr(arg1, arg2) instead, though that can leave me wondering where funcptr is defined.
You can also find some code closely related to what you're doing in my SOQ (Stack Overflow Questions) repository on GitHub as files aomcopy.c, aomcopy.h, aommngd.c, aommngd.h, aomptr.c, aomptr.h, aoscopy.c, aoscopy.h, aosptr.c and aosptr.h in the src/libsoq sub-directory.
aomcopy.c, aomcopy.h: array of memory blocks, copied.
aommngd.c, aommngd.h: array of memory blocks, managed.
aomptr.c, aomptr.h: array of memory blocks, 'raw'.
aoscopy.c, aoscopy.h: array of strings, copied.
aosptr.c. aosptr.h: array of strings, 'raw'.
The 'raw' versions simply take the pointer passed and store it. The onus is on the user to ensure the data pointed at remains valid while the array lasts. The 'copied' versions allocate a simple copy of the data passed to it; it doesn't matter if the data passed is reused to store the next value. The 'managed' version calls user-defined functions to create copies of the data structures. This would be necessary if you have a complex structure (like a department) where you need a 'deep copy' of the data.
Hi I am attempting to implement a really simple hashmap in regular C with a string as key and a void pointer as value as I wish to use the map for multiple data types.
So far I have this
struct node{
void * value;
char * key;
};
unsigned long strhash(char *string)
{
unsigned long hash = 5381;
int c;
while ((c = *string++))
{
hash = ((hash << 5) + hash) + c;
}
return hash;
}
map_t *map_create(int maxSize){
map_t *map = malloc(sizeof(map_t));
map->curSize = 0;
map->maxSize = maxSize;
map->nodes = calloc(map->maxSize, sizeof(node_t *));
return map;
}
node_t *node_create(char *key, void *value){
node_t *node = malloc(sizeof(node_t));
node->key = key;
node->value = value;
return node;
}
void map_insert(map_t *map, char *key, void *value){
node_t *node = node_create(key, value);
int idx = strhash(key) % map->maxSize;
if(map->nodes[idx] == NULL){
map->nodes[idx] = node;
}else{
while(map->nodes[idx] != NULL){
idx++%map->maxSize;
}
map->nodes[idx] = node;
}
return;
}
void map_print(map_t *map){
for(int i = 0; i < map->maxSize; i++){
if(map->nodes[i] != NULL){
printf("index: %d\t value: %d\n",i, *(int*)map->nodes[i]->value);
}
}
return;
}
void map_destroy(map_t *map){
for(int i = 0; i < map->maxSize; i++){
if(map->nodes[i] != NULL){
free(map->nodes[i]);
}
}
free(map->nodes);
free(map);
return;
}
int main(){
map_t *map = map_create(32);
for(int i = 0; i < 30; i++){
map_insert(map, (char*)&i, &i);
}
map_print(map);
map_destroy(map);
return 0;
}
The problem is the output is not as I'd expect when the map gets printed all that is retrieved is the value "30" on all indexes which is the last number inserted into the map. If I change the value to type int the map works as expected, so is there must be something crucial I am missing in regards to pointers.
I am not the greatest at C so any light which could be shed on this would be most appreciated.
The problem is that you're using the same pointer every time you call map_insert(). It just stores the pointer, it doesn't copy the data. Each time through the loop you change the contents of that memory, so all the hash map elements point to that same value.
There are two ways you can fix it. One way is to always make a dynamically-allocated copy of the data before calling map_insert():
for (int i = 0; i < 30; i++) {
int *i_copy = malloc(sizeof *i_copy);
*i_copy = i;
map_insert(map, (char *)i_copy, (char *)i_copy);
}
The other option is to add the size of the value to the map_insert() and node_create() arguments. Then node_create call malloc() and memcpy() to copy the value to dynamic memory.
BTW, there's another problem. The key is supposed to be a null-terminated string (strhash() depends on this), but you're using &i, which is a pointer to an integer. Casting a pointer to an integer to char* doesn't return a string, it just returns a pointer to the same location with a different data type. I haven't fixed this above.
OP stores a reference to the same value, so of course all lookups yield the same value (which is not even a string, but whatever the storage representation of the value of the variable i happens to be).
I prefer chaining the hash map entries, and keeping a copy of the hash in the entry:
struct entry {
struct entry *next;
size_t hash;
void *data;
size_t data_size;
int data_type;
unsigned char name[];
};
typedef struct {
size_t size;
size_t used; /* Number of entries, total */
struct entry **slot; /* Array of entry pointers */
size_t (*hash)(const unsigned char *, size_t);
} hashmap;
int hashmap_new(hashmap *hmap, const size_t size,
size_t (*hash)(const unsigned char *, size_t))
{
if (!hmap)
return -1; /* No hashmap specified */
hmap->size = 0;
hmap->used = 0;
hmap->slot = NULL;
hmap->hash = NULL;
if (size < 1)
return -1; /* Invalid size */
if (!hash)
return -1; /* No hash function specified. */
hmap->slot = calloc(size, sizeof hmap->slot[0]);
if (!hmap->slot)
return -1; /* Not enough memory */
hmap->size = size;
hmap->hash = hash;
return 0;
}
void hashmap_free(hashmap *hmap)
{
if (hmap) {
size_t i = hmap->size;
while (i-->0) {
struct entry *next = hmap->slot[i];
struct entry *curr;
while (next) {
curr = next;
next = next->next;
free(curr->data);
/* Poison the entry, to help detect use-after-free bugs. */
curr->next = NULL;
curr->data = NULL;
curr->hash = 0;
curr->data_size = 0;
curr->data_type = 0;
curr->name[0] = '\0';
free(curr);
}
}
}
free(hmap->slot);
hmap->size = 0;
hmap->used = 0;
hmap->slot = NULL;
hmap->hash = NULL;
}
To insert a key-value pair, the function either uses the data specified as-is, in which case it's the caller's responsibility to ensure each key has their own unique data not overwritten later; or we copy the user data. In the above hashmap_free() function, you'll see free(curr->data);; it assumes we allocated memory dynamically, and copied the user data there. So:
int hashmap_add(hashmap *hmap, const unsigned char *name,
const void *data, const size_t data_size,
const int data_type)
{
const size_t namelen = (name) ? strlen(name) : 0;
struct entry *curr;
size_t i;
if (!hmap)
return -1; /* No hashmap specified. */
if (name_len < 1)
return -1; /* NULL or empty name. */
/* Allocate memory for the hashmap entry,
including enough room for the name, and end of string '\0'. */
curr = malloc(sizeof (struct entry) + namelen + 1;
if (!curr)
return -1; /* Out of memory. */
/* Copy data, if any. */
if (data_size > 0) {
curr->data = malloc(data_size);
if (!curr->data) {
free(curr);
return -1; /* Out of memory. */
}
memcpy(curr->data, data, data_size);
} else {
curr->data = NULL;
curr->data_size = 0;
}
curr->data_type = data_type;
/* Calculate the hash of the name. */
curr->hash = hmap->hash(name, namelen);
/* Copy name, including the trailing '\0'. */
memcpy(curr->name, name, namelen + 1);
/* Slot to prepend to. */
i = curr->hash % hmap->size;
curr->next = hmap->slot[i];
hmap->slot[i] = curr;
/* An additional node added. */
hmap->used++;
return 0;
}
The meaning of data_type is completely up to the user of the code.
Lookup can be made based on the hash and the data type:
/* Returns 0 if found. */
int hashmap_find(hashmap *hmap, const unsigned char *name,
const int data_type,
void **dataptr_to, size_t *size_to)
{
struct entry *curr;
size_t hash;
if (size_to)
*size_to = 0;
if (dataptr_to)
*dataptr_to = NULL;
if (!hmap)
return -1; /* No hashmap specified. */
if (!name || !*name)
return -1; /* NULL or empty name. */
hash = hmap->hash(name, strlen(name));
curr = hmap->slot[hash % hmap->size];
for (curr = hmap->slot[hash % hmap->size]; curr != NULL; curr = curr->next) {
if (curr->data_type == data_type && curr->hash == hash &&
!strcmp(curr->name, name)) {
/* Data type an name matches. Save size if requested. */
if (size_to)
*size_to = curr->data_size;
if (dataptr_to)
*dataptr_to = curr->data;
return 0; /* Found. */
}
}
return -1; /* Not found. */
}
The above lookup returns 0 if found, and nonzero if error or not found. (This way, even zero-size NULL data can be stored in the hash map.)
If the number of data types supported is small, say 32, then using an unsigned int with each bit (1U<<0 == 1, 1U<<1 == 2, 1U<<2 == 4, and so on) reserved for a specific type, you can do the lookup using a mask, allowing only the specified types. Similarly, the data_type can be a mask, describing which types the value can be interpreted as (almost always will have just one bit set).
This scheme also allows one to dynamically resize the hashmap, by allocating a new slot array of pointers, and moving each old entry to the new one. The keys don't need to be rehashed, because the original hash is stored in each entry. For lookup efficiency, the chains (hanging off each slot) should be as short as possible. A common "rule of thumb" is that hashmap->size should be between hashmap->used and 2 * hashmap->used.
When you call map_insert(map, (char*)&i, &i); the value inserted into hasmap is the pointer to i variable, i.e. its address in memory, and not the value of i.
So when you change i value inside the for loop there is the side-effect to all entries into the hashmap, and at the end of the loop you only see the last value assigned.
i have a task in class to the return an array of struck Symbol from huffman tree.
the function getSL get a huffman tree(only) and return struck of Symbol.
each spot in the array contain a char from the "leaf" of the tree and the
length of his code(how many cross section till the leaf).
my main problem was to find how i advance the cnt of the arry that it will not overright the arry.
thank you.
typedef struct HNode {
char chr;
struct HNode *left, *right;
} HNode;
typedef struct {
char chr;
int counter;
}Symbol;
this is what i did till now.
Symbol * getSL(HNode *root) {
if (root->left == NULL && root->right == NULL) {
Symbol* b = (Symbol*)malloc(100);
b->counter=0;
b->chr = root->chr;
return b;
}
Symbol* a = (Symbol*)malloc(100);
if (root->left != NULL) {
a= getSL(root->left);
a->counter++;
}
if (root->right != NULL) {
a= getSL(root->right);
a->counter++;
}
return a;
}
Apart from the malloc problem (see the comments already), you have a fundamental problem: You allocate a new struct, but then replace it with the one returned from the recursive call. So you lose the one created before (actually, memory leaking!).
Easiest variant would now be converting your Symbol to linked list nodes; then you simply could do:
Symbol* lastLeafFound; // probaly a function parameter!
if(!(root->left || root->right))
{
// leaf found:
Symbol* a = (Symbol*)malloc(sizeof(Symbol));
a->chr = root->chr;
a->counter = /* ... */;
a->next = NULL;
lastLeafFound->next = a;
// you might return a now as last leaf found, using it in the next recursive call
}
Sure, above code is incomplete, but should give you the idea...
If you cannot modify your struct, then you need to create an array and pass it on to every new recursive call (prefer not to use global variables instead):
void doGetSL
(
HNode* root,
Symbol** symbols, // your array to be used
unsigned int* count, // number of symbols contained so far
unsigned int* capacity // maximum possible symbols
)
Passing all data as pointers allows the function to modify them as needed and they are still available from outside...
Symbol* getSL(HNode* root)
{
if(!root)
return NULL;
unsigned int count = 0;
unsigned int capacity = 128;
// allocate a whole array:
Symbol* array = malloc(capacity*sizeof(Symbol));
if(array) // malloc could fail...
{
doGetSL(root, &array, &count, &capacity);
// as you cannot return the number of leaves together with
// the array itself, you will need a sentinel:
array[count].chr = 0;
// obvious enough, I'd say, alternatively you could
// set counter to 0 or -1 (or set both chr and counter)
}
return array;
}
doGetSL will now use above set up "infrastructure":
{
if(!(root->left || root->right))
{
if(*count == *capacity)
{
// no memory left -> we need a larger array!
// store in separate variables:
unsigned int c = *capacity * 2;
Symbol* s = realloc(symbols, c * sizeof(Symbol));
// now we can check, if reallocation was successful
// (on failure, s will be NULL!!!):
if(s)
{
// OK, we can use them...
*symbols = s; // <- need a pointer for (pointer to pointer)!
*capacity = c;
}
else
{
// re-allocation failed!
// -> need appropriate error handling!
}
}
(*symbols)[count].chr = root->chr;
(*symbols)[count].counter = /*...*/;
++*count;
}
else
{
if(root->left)
{
doGetSL(root->left, symbols, count, capacity);
}
if(root->right)
{
doGetSL(root->right, symbols, count, capacity);
}
}
}
One thing yet omitted: setting the counter. That would be quite easy: add another parameter to doGetSL indicating the current depth, which you increment right when entering doGetSL, you can then just assign this value when needed.
You can further improve above variant (especially readability), if you introduce a new struct:
struct SLData
{
Symbol* symbols, // your array to be used
unsigned int count, // number of symbols contained so far
unsigned int capacity // maximum possible symbols
};
and pass this one instead of the three pointers:
doGetSL(HNode*, struct SLData*, unsigned int depth);
struct SLData data =
{
.count = 0;
.capacity = 128;
.array = malloc(capacity*sizeof(Symbol));
};
if(data.array)
doGetSL(root, &data, 0); // again passed as pointer!
I am trying to build a program which will function as an assembler, it will be getting file name as command line arguments and translate them to machine code.
The program compiles just fine and runs OK with 1 file name, but when I try to run with several, the error appears after the first iteration.
I think there might be something withe the Clear() function (which flushes out all the data allocated in the previous iteration), but not sure why. Note that this is partial, but as I said, the program will run unless several files are used.
struct symbolStruct { // a structure which is used to absorb info about a tag, its place in memory and related flags
char *name;
int place;
unsigned int isEntry : 1;
unsigned int isData : 1;
unsigned int isExternal : 1;
struct symbolStruct *next;
};
typedef struct { // a structure which is used to absorb info about the operand structure of an instruction line
unsigned int numOfOperands : 2;
unsigned int addrMethSou : 2;
unsigned int addrMethDest : 2;
unsigned int operation : 4;
unsigned int extraWords : 2;
char *firstOperand;
char *secondOperand;
} OperandType;
typedef struct {
unsigned int row : WORD_SIZE;
} int15;
struct MachineCode { // a structure which is used to absorb machine code lines, and their location in the assembly file
unsigned int row : WORD_SIZE;
unsigned int line;
OperandType *structure;
struct MachineCode *next;
};
struct DataCode { // a structure which is used to absorb data and string elements (signed numbers and ascii characters)
unsigned int row : WORD_SIZE;
struct DataCode *next;
};
struct Operation { /* the main operation structure, contains pointers to all used lists, the ic and dc counters, the
current line number which is dealt with and the error flag. */
unsigned int ic;
unsigned int dc;
struct symbolStruct *externHead; // a pointer to a linked list of extern tags used in the assembly file, and their locations
struct symbolStruct *symbolHead; // a pointer to a linked list of all tags
struct DataCode *dataHead; // a pointer to a linked list of all data/string elements
struct MachineCode *machineHead; // a pointer to a linked list of all machine code rows
int linenumber;
unsigned int errorflag : 1; // raised in case of an error which triggered a warning
};
#include "header.h"
void FirstRun(struct Operation*, char *);
void DataUpdate(struct symbolStruct*,int);
void SecondRun(struct Operation *, char *);
void Clear(struct Operation *);
int main(int argc, char *argv[]) {
int i;
struct Operation programCore = {0,0,NULL,NULL,NULL,NULL,0,0};
for(i=1;i<argc;i++) {
char *fn = argv[i];
FirstRun(&programCore,fn);
DataUpdate(programCore.symbolHead,programCore.ic+INSTRUCTION_OFFSET);
SecondRun(&programCore,fn);
Clear(&programCore);
programCore.symbolHead = programCore.externHead = programCore.dataHead = programCore.machineHead = NULL;
}
if(argc < 2) {
fprintf(stderr,"No files selected.\n");
}
return 0;
}
/*Used to empty the linked lists and allocated memory after the program has finished one iteration. */
void Clear(struct Operation *programCore) {
/*f(pointer name) is there to hold a pointer to the allocated memory which is about to be flushed. */
struct MachineCode *machineHead = programCore->machineHead, *fMachineHead;
struct DataCode *dataHead = programCore->dataHead, *fDataHead;
struct symbolStruct *externHead = programCore->externHead, *fExternHead;
struct symbolStruct *symbolHead = programCore->symbolHead, *fSymbolHead;
while(machineHead != NULL) {
fMachineHead = machineHead;
machineHead = machineHead->next;
if(fMachineHead->structure != NULL) {
if(fMachineHead->structure->numOfOperands == 2)
free(fMachineHead->structure->secondOperand);
if(fMachineHead->structure->numOfOperands > 0)
free(fMachineHead->structure->firstOperand);
free(fMachineHead->structure);
}
free(fMachineHead);
}
while(dataHead != NULL) {
fDataHead = dataHead;
dataHead = dataHead->next;
free(fDataHead);
}
while(externHead != NULL) {
fExternHead = externHead;
externHead = externHead->next;
free(fExternHead->name);
free(fExternHead);
}
while(symbolHead != NULL) {
fSymbolHead = symbolHead;
symbolHead = symbolHead->next;
free(fSymbolHead->name);
free(fSymbolHead);
}
programCore->ic = programCore->dc = programCore->linenumber = programCore->errorflag = 0;
}
You do not free and nullifying the linked lists in the context struct (programCore). I suspect you are then using pointers to freed memory blocks.
This line only copies the pointer:
struct MachineCode *machineHead = programCore->machineHead;
The while() loop is not clearing programCore->machineHead
To fix it, run directly on the head:
while(programCore->machineHead != NULL)
{
...
}
Well, by getting rid of
if(fMachineHead->structure->numOfOperands == 2)
free(fMachineHead->structure->secondOperand);
if(fMachineHead->structure->numOfOperands > 0)
free(fMachineHead->structure->firstOperand);
I have managed to solve the error, but now I am getting a new one -
main.c:242:13: error: request for member ‘symbolHead’ in something not a structure or union
main.c:242:38: error: request for member ‘externHead’ in something not a structure or union
main.c:243:13: error: request for member ‘dataHead’ in something not a structure or union
main.c:244:13: error: request for member ‘machineHead’ in something not a structure or union
Referring to the next line -
programCore.symbolHead = programCore.externHead = programCore.dataHead = programCore.machineHead = NULL;
Is there a problem with the way I wrote that? (Obviously yes, but I just don't see it).
Changed the clear() function again and it seems to be working fine now.
/*Used to empty the linked lists and allocated memory after the program has finished one iteration. */
void Clear(struct Operation *programCore) {
/*f(pointer name) is there to hold a pointer to the allocated memory which is about to be flushed. */
struct MachineCode *machineRowPointer = programCore->machineHead, *fMachineRow;
struct DataCode *dataRowPointer = programCore->dataHead, *fDataRow;
struct symbolStruct *externSymbolPointer = programCore->externHead, *fExtern;
struct symbolStruct *symbolPointer = programCore->symbolHead, *fSymbol;
if(machineRowPointer != NULL) {
while(machineRowPointer != NULL) {
if(machineRowPointer->structure != NULL)
free(machineRowPointer->structure);
fMachineRow = machineRowPointer;
machineRowPointer = machineRowPointer->next;
free(fMachineRow);
}
programCore->machineHead = NULL;
}
if(dataRowPointer != NULL) {
while(dataRowPointer != NULL) {
fDataRow = dataRowPointer;
dataRowPointer = dataRowPointer->next;
free(fDataRow);
}
programCore->dataHead = NULL;
}
if(externSymbolPointer != NULL) {
while(externSymbolPointer != NULL) {
fExtern = externSymbolPointer;
externSymbolPointer = externSymbolPointer->next;
free(fExtern->name);
free(fExtern);
}
programCore->externHead = NULL;
}
if(symbolPointer != NULL) {
while(symbolPointer != NULL) {
fSymbol = symbolPointer;
symbolPointer = symbolPointer->next;
free(fSymbol->name);
free(fSymbol);
}
programCore->symbolHead = NULL;
}
programCore->ic = programCore->dc = programCore->linenumber = programCore->errorflag = 0;
}
I am getting a really strange error in my C program and therefore I need your help guys! So I have a recursive structure called path, where sometimes I store the address of the "parent" path in the structure field mother:
typedef struct path{
struct path* mother;
struct path** children;
int length;
uint8_t* inf;
} path;
So in my example I just generate one path like this:
int child_num=2;
int bytes=10;
path* my_path=malloc(sizeof(path));
if (path==NULL) throw error...
my_path->inf=malloc(sizeof(uint8_t)*bytes);
memset(my_path->inf, 4, bytes);
my_path->children=malloc(sizeof(path*)*child_num);
for(int i=0; i<child_num; i++){
my_path->children[i]->mother=my_path;
my_path->children[i]->inf=malloc(sizeof(uint8_t)*bytes);
memset(my_path->children[i]->inf, 5, bytes);
}
So now since I stored the link to the parent structure, I want to use another helping pointer to get access to its information:
path* my_pointer=my_path->children[0]->mother; //this is just for the example
So i checked the addresses and everything seems to be alright, but if I know use the pointer in another method, pointing to the field "inf", it works if I use the variable "path" so:
method(path->inf, bytes);
it is fine, but as soon as I do:
method(my_pointer->inf, bytes);
the method crashes at the marked line:
void method(uint8_t* element, int bytes) {
if (element==NULL) ... //<=== here it crashes
//do something
}
I really dont get what I am doing wrong, I printed the addresses and everything seems to be good, even if I access a certain byte over the variable "my_pointer", so like
my_pointer->inf[1]
it returns me the corresponding value, but in the separate method it doesnt work.
Like the comments indicate we can't exactly answer your question with the information provided, but we can point you in the right direction.
First, I noticed in your examples that you're using path as a variable name to a typedef'd path structure. You need to either be more verbose with your variable names or actually copy paste some code to make sure that we can look at the actual problem, because it could simply be an issue with naming.
All in all I think it would do you a world of good to employ a bit of code hygiene. Organize some of the functions you use for data structure overhead at file scope:
static int path_alloc(path* p);
static int path_alloc_kids(path* p, int num);
static int path_alloc(path* p) {
if(p == NULL) { return -1; }
p = (path*)malloc(sizeof(path));
if(p == NULL) { return -2; }
return 0;
}
static int path_alloc_kids(path* p, int num) {
if(p == NULL || num <= 0) { return -1; }
if(!path_alloc(p)) { /* Easier to read and understand, no error handling here to muddle things up */
/* You don't actually need a path**, do you? Think of char *argv[] a.k.a. char **argv, is that what you're actually going for? */
p->children = (path*)malloc(sizeof(path) * num);
if(p->children == NULL) { return -2; }
p->length = num;
} else { return -1; } /* Simple */
return 0;
}
This makes it a LOT easier to understand your code, which is the main issue with pointers. Add in some methods to free the allocated children and roots and you're set to use this path structure in a relatively abstracted way. You may want to consider using a path and a path_node in a linked-list fashion, that way you only allocate what you need.
struct spath_node; /* So it knows of itself */
typedef struct spath_node {
struct spath_node *parent;
struct spath_node *next;
uint8_t *data;
int data_size;
} path_node;
Then allocate by passing in a data size and parent, a NULL parent could mean it's a root node.
static int path_alloc_node(path_node *parent, int data_size, uint8_t *data);
This makes for relatively slow insert/traversal, but easier to understand where you went wrong.
EDIT: To be clear, this is how we would add children to the linked-list example:
static int path_alloc_node(path_node *parent, int data_size, uint8_t *data) {
path_node *tmp;
if(parent == NULL || data_size <= 0) { return -1; }
if(parent->next != NULL) { return -3; }
tmp = (path_node*)malloc(sizeof(path_node));
if(tmp == NULL) { return -2; }
else parent->next = tmp;
if(data == NULL) { /* Assume the caller is requesting a new data block of the given size */
data = (uint8_t*)malloc((size_t)data_size);
if(data == NULL) { return -2; }
}
parent->next->data = data;
parent->next->data_size = data_size;
parent->next->next = NULL;
parent->next->parent = parent;
return 0;
}