typedef struct cache_line {
char valid;
mem_addr_t tag;
struct cache_line* next;
} cache_line_t;
typedef cache_line_t* cache_set_t;
typedef cache_set_t* cache_t;
/* The cache we are simulating */
cache_t cache;
void initCache()
{
cache = malloc (S * sizeof(cache_set_t));
for (int i = 0; i < S; i ++ ){
cache[i]= malloc(sizeof(cache_line_t));
cache_line_t *temp = *(cache+i);
temp -> valid = 0;
temp -> tag = 0;
cache_line_t* curr = *(cache+ i );
for (int j = 1; j < E; j++){
curr.next = malloc(sizeof(cache_line_t));
curr = curr.next;
curr.valid=0;
curr.tag=0;
}
curr.next = NULL;
}
}
So my head is swimming trying to remember all the details of pointers and structs and I've been up for a while trying to finish this project. What I'm trying to do here is allocate an array of this structure (a linked list) on the heap and I keep having issues with type mismatches and whatnot (sorry if its messy I keep on trying new things and recompiling). Any help on where I'm going wrong would be appreciated.
Well, the fact the code is terribly obfuscated with abuse of typedef probably goes a long way towards both yours and the compilers problems. I wouldn't have a single typedef in this program myself. It serves no real abstraction here. Here's what I'd suggest (with some omission of error checking):
struct cache_line {
char valid;
mem_addr_t tag;
struct cache_line* next;
};
struct cache_line** cache;
void initCache()
{
cache = malloc (sizeof(*cache) * S);
for (int i = 0; i < S; i ++ ){
struct cache_line** curr_p = &cache[i];
for (int j = 1; j < E; j++){
*curr_p = malloc(sizeof(**curr_p));
(*curr_p)->valid = 0;
(*curr_p)->tag = 0;
(*curr_p)->next = NULL;
curr_p = &(*curr_p)->next;
}
}
}
Key things to note:
I removed all the typedefs. They served no real purpose here but an attempt to save typing. And they did it at the cost of code quality. I also removed it from the struct, since I believe the previous statement applies to it as well.
I allocated memory canonically. By writing malloc(sizeof(*pointer_variable)), you allocate enough memory regardless of what pointer_variable points at. It's somewhat type agnostic.
I traverse the linked list with the "link traversal" idiom. Instead of keeping track of the "node", I keep track of the pointer that is pointing at the node. In the beginning it's cache[i], and at every iteration it becomes the pointer inside the newly allocated node.
Related
I don't understand why my program seg faults at this line: if ((**table->table).link == NULL){ I seem to have malloc-ed memory for it, and I tried looking at it with gdb. *table->table was accessible and not NULL, but **table->table was not accessible.
Definition of hash_t:
struct table_s {
struct node_s **table;
size_t bins;
size_t size;
};
typedef struct table_s *hash_t;
void set(hash_t table, char *key, int value){
unsigned int hashnum = hash(key)%table->bins;
printf("%d \n", hashnum);
unsigned int i;
for (i = 0; i<hashnum; i++){
(table->table)++;
}
if (*(table->table) == NULL){
struct node_s n = {key, value, NULL};
struct node_s *np = &n;
*(table->table) = malloc(sizeof(struct node_s));
*(table->table) = np;
}else{
while ( *(table->table) != NULL){
if ((**table->table).link == NULL){
struct node_s n = {key, value, NULL};
struct node_s *np = &n;
(**table->table).link = malloc(sizeof(struct node_s));
(**table->table).link = np;
break;
}else if (strcmp((**table->table).key, key) == 0){
break;
}
*table->table = (**(table->table)).link;
}
if (table->size/table->bins > 1){
rehash(table);
}
}
}
I'm calling set from here:
for (int i = 0; i < trials; i++) {
int sample = rand() % max_num;
sprintf(key, "%d", sample);
set(table, key, sample);
}
Your hashtable works like this: You have bins bins and each bin is a linked list of key / value pairs. All items in a bin share the same hash code modulo the number of bins.
You have probably created the table of bins when you created or initialised the hash table, something like this:
table->table = malloc(table->bins * sizeof(*table->table);
for (size_t i = 0; i < table->bins; i++) table->table[i] = NULL;
Now why does the member table have two stars?
The "inner" star means that the table stores pointers to nodes, not the nodes themselves.
The "outer" start is a handle to allocated memory. If your hash table were of a fixed size, for example always with 256 bins, you could define it as:
struct node_s *table[256];
If you passed this array around, it would become (or "decay into") a pointer to its first element, a struct node_s **, just as the array you got from malloc.
You access the contents of the l´bins via the linked lists and the head of linked list i is table->table[i].
You code has other problems:
What did you want to achieve with (table->table)++? This will make the handle to the allocated memory point not to the first element but tho the next one. After doing that hashnum times, *table->table will now be at the right node, but you will have lost the original handle, which you must retain, because you must pass it to free later when you clean up your hash table. Don't lose the handle to allocated memory! Use another local pointer instead.
You create a local node n and then make a link in your linked list with a pointer to that node. But the node n will be gone after you leave the function and the link will be "stale": It will point to invalid memory. You must also create memory for the node with malloc.
A simple implementation of your has table might be:
void set(hash_t table, char *key, int value)
{
unsigned int hashnum = hash(key) % table->bins;
// create (uninitialised) new node
struct node_s *nnew = malloc(sizeof(*nnew));
// initialise new node, point it to old head
nnew->key = strdup(key);
nnew->value = value;
nnew->link = table->table[hashnum];
// make the new node the new head
table->table[hashnum] = nnew;
}
This makes the new node the head of the linked list. This is not ideal, because if you overwrite items, the new ones will be found (which is good), but the old ones will still be in the table (which isn't good). But that, as they say, is left as an exercise to the reader.
(The strdup function isn't standard, but widely available. It also creates new memory, which you must free later, but it ensures, that the string "lives" (is still valid) after you have ceated the hash table.)
Please not how few stars there are in the code. If there is one star too few, it is in hash_t, where you have typecasted away the pointer nature.
I have an issue freeing my array of struct pointers for a priority queue that I am implementing. I create two dynamic arrays of node pointers with a fixed size from client c program. The array heapMap contains node pointers that map to each created node with a specific ID integer value and the array heap is the heap array that contains the nodes with respect to their current values.
Everything seems to work, however, my pq_free function seems to cause errors or doesn't properly deallocate the arrays. Any help would be appreciated
Structures
typedef struct node_struct{
int ID;
double val;
}NODE;
struct pq_struct {
char heapType;
int max;
int inUse;
NODE ** heap; //BOTH have a specific capacity
NODE **heapMap; //array of pointers to each
};
This is the function I use to allocate memory for the structure.
PQ * pq_create(int capacity, int min_heap){
PQ * newQueue = (PQ*) malloc(sizeof(PQ)); //Allocate memory for a new heap
newQueue->max = capacity;
newQueue->inUse = 0;
int inUse = 1;//1 in use by default, the 0th point in the array is left alone intentionally
//If min_heap == 0, it it is a max heap, any other value is a min heap.
if(min_heap != 0){
newQueue->heapType = 'm';
}else{
newQueue->heapType = 'M';
}
//Allocate memory for heapMap and heap..
newQueue->heap = (NODE**) malloc(sizeof(NODE*)*capacity); //array of nodes, the heap
newQueue->heapMap = (NODE**) malloc(sizeof(NODE*) * capacity);//array of node pointers, the HEAPMAP
int i = 0;
for (i = 0; i < capacity + 1;i++) {
newQueue->heapMap[i] = NULL;
}
//return PQ pointer
return newQueue;
}
This is my pq_free function that doesn't seem to work properly. Thanks for help in advance.
void pq_free(PQ * pq){
//free all nodes
NODE * temp;
NODE ** temp2;
int i;
for (i = 0; i < pq->inUse; i++) {
if (pq->heapMap[i] != NULL) {
temp = pq->heapMap[i];
free(temp);
}
}
//pq->heapMap = NULL;
free(pq->heap);
free(pq->heapMap);
free(pq);
}
As I was once railed on this site for doing this, I feel obligated to do the same to you. You shouldn't cast malloc because it is automatically cast to the assigned data type and can lead to some bad situations.
Other than that how are the individual nodes allocated? What errors specifically are given? I think you are also walking off your heapMap as you allocate capacity but iterate over capacity + 1 elements.
Here is the code for a bucket sort program.
typedef struct node_struct {
double d;
struct node_struct *next;
} node;
I'm using insertion sort to sort the values
void insert(double value, int index, node *B[]) {
node *t;
if (B[index] == NULL) {
t = (node *)malloc(sizeof(node));
t->d = value;
t->next = NULL;
B[index] = t;
} else {
node *p0, *p1;
p0 = B[index];
p1 = p0 -> next;
while(p1 != NULL) {
if (p1 -> d > value) {
break;
}
p1 = p1->next;
p0 = p0->next;
}
t = (node *)malloc(sizeof(node));
t->d = value;
t->next = p1;
p0->next = t;
}
void Bucket_Sort(double A[], int n) {
int j, index;
double B[n];
node *B1;
B1 = (node *)malloc(sizeof(node));
for (int i = 0; i < n; i++) {
B[i] = 0;
}
B1->d = A[0];
B1->next = NULL;
for (int i = 1; i <= n; i++) {
index = (int) floor(n * A[i]);
insert(A[i], index, B1); // This part of the program is where I'm going wrong
}
for (int = 0; i < n; i++) {
printf("%f \n", B[i]);
}
}
When I try calling the insert function, an error occurs saying "expecting struct node ** but the argument is of type struct node *"
But if I call insert function as follows:
insert(A[i],index,&B1);
Then no error is given while compiling but when I run the program it leads to a segmentation fault. Can someone help me with the confusion?
Your insert function is indicating b is an array of pointers to node objects.
But you're not passing in an array of pointers, you're calling it with &b1, which is a pointer to a single node (not an array). And when you uses arrays like that generally you need to pass a count of elements, whereas with pointers to linked list elements you usually use null to indicate the end of the list.
If I were you I would just pass pointers around to deal with everything, and get rid of the [] since you're really not passing things properly for an array. E.g. Rather than passing in an index, just pass a pointer to the object of interest. In more tricky cases you can use ** pointer to pointer but that requires a very solid understand of what you're doing.
Google linked-list example to get ideas how to deal with that properly with pointers. You'll get the idea.
Otherwise be consistent in the way you pass an interpret arrays and pass a count in, and use the count variable in your loops. I'd advise not to try to mix the [] form and * or ** paradigms until you get really comfortable with each separately.
typedef struct node_struct {
double d;
struct node_struct *next;
} node;
void insert(double value, int index, node *b[]) {
node *t;
if (b[index] == NULL) {
t = (node *)malloc(sizeof(node));
t->d = value;
t->next = NULL;
b[index] = t;
} else {
node *p0, *p1;
p0 = b[index];
p1 = p0 -> next;
while (p1 != NULL) {
if (p1 -> d > value) {
break;
}
p1 = p1->next;
p0 = p0->next;
}
t = (node *)calloc(sizeof(node), 1);
t->d = value;
t->next = p1;
p0->next = t;
}
void Bucket_Sort(double a[], int n) {
int j, index;
double b[n];
node *b1 = (node *)calloc(sizeof(node), 1);
a1->d = a[0];
b1->next = NULL;
for (int i = 1; i <= n; i++) {
index = (int) floor(n * a[i]);
insert(a[i], index, b1);
}
for (int = 0; i < n; i++) {
printf("%f \n", b[i]);
}
}
I formatted the program in your question, and went further below. This is more how I see code written in professional code bases and when I do peer code reviews, etc...
Some notes:
• If you use calloc() instead of malloc, and your buffer is automatically zeroed. People usually use bzero(), or memset() to zero arrays rather than a for() loop.
• You can declare an assign a variable such as B1 at the same time and save space/clutter;
• You can declare the variable type inside a for-loop and it will be scoped to just that for-loop. Makes it clear and saves vertical space.
• Don't get too idiosyncratic with your formatting. The programming community is just frustrated by it. There are coding standards at just about any respectable C coding place, and very strict so the code looks clean, readable, easy to understand and maintain, and consistent. If everyone applies their own twist a large coding base becomes an ugly maintenance nightmare.
• Don't add spaces before and after pointers -> no one does it and it's harder to read by experienced programmers. Leave spaces after commas, for the same reason you do when writing - separates items visually better - easier to debug, etc...
• Capitals are used for constants. Camel-case (first letter lower-case and subsequent words first letter capital for example thisIsMyVariable), for variables, or underscores this_is_my_variable, in C. Naming arrays with capital letters is tacky and you almost never see it in professional code.
I wrote a hashtable and it basically consists of these two structures:
typedef struct dictEntry {
void *key;
void *value;
struct dictEntry *next;
} dictEntry;
typedef struct dict {
dictEntry **table;
unsigned long size;
unsigned long items;
} dict;
dict.table is a multidimensional array, which contains all the stored key/value pair, which again are a linked list.
If half of the hashtable is full, I expand it by doubling the size and rehashing it:
dict *_dictRehash(dict *d) {
int i;
dict *_d;
dictEntry *dit;
_d = dictCreate(d->size * 2);
for (i = 0; i < d->size; i++) {
for (dit = d->table[i]; dit != NULL; dit = dit->next) {
_dictAddRaw(_d, dit);
}
}
/* FIXME memory leak because the old dict can never be freed */
free(d); // seg fault
return _d;
}
The function above uses the pointers from the old hash table and stores it in the newly created one. When freeing the old dict d a Segmentation Fault occurs.
How am I able to free the old hashtable struct without having to allocate the memory for the key/value pairs again?
Edit, for completness:
dict *dictCreate(unsigned long size) {
dict *d;
d = malloc(sizeof(dict));
d->size = size;
d->items = 0;
d->table = calloc(size, sizeof(dictEntry*));
return d;
}
void dictAdd(dict *d, void *key, void *value) {
dictEntry *entry;
entry = malloc(sizeof *entry);
entry->key = key;
entry->value = value;
entry->next = '\0';
if ((((float)d->items) / d->size) > 0.5) d = _dictRehash(d);
_dictAddRaw(d, entry);
}
void _dictAddRaw(dict *d, dictEntry *entry) {
int index = (hash(entry->key) & (d->size - 1));
if (d->table[index]) {
dictEntry *next, *prev;
for (next = d->table[index]; next != NULL; next = next->next) {
prev = next;
}
prev->next = entry;
} else {
d->table[index] = entry;
}
d->items++;
}
best way to debug this is to run your code against valgrind .
But to you give some perspective :
when you free(d) you are expecting more of a destructor call on your struct dict which would internally free the memory allocated to the pointer to pointer to dictEntry
why do you have to delete the entire has table to expand it ? you have a next pointer anyways why not just append new hash entries to it ?
Solution is not to free the d rather just expand the d by allocating more struct dictEntry and assigning them to appropriate next.
When contracting the d you will have to iterate over next to reach the end and then start freeing the memory for struct dictEntrys inside of your d.
To clarify Graham's point, you need to pay attention to how memory is being accessed in this library. The user has one pointer to their dictionary. When you rehash, you free the memory referenced by that pointer. Although you allocated a new dictionary for them, the new pointer is never returned to them, so they don't know not to use the old one. When they try to access their dictionary again, it's pointing to freed memory.
One possibility is not to throw away the old dictionary entirely, but only the dictEntry table you allocated within the dictionary. That way your users will never have to update their pointer, but you can rescale the table to accomodate more efficient access. Try something like this:
void _dictRehash(dict *d) {
printf("rehashing!\n");
int i;
dictEntry *dit;
int old_size = d->size;
dictEntry** old_table = d->table;
int size = old_size * 2;
d->table = calloc(size, sizeof(dictEntry*));
d->size = size;
d->items = 0;
for (i = 0; i < old_size; i++) {
for (dit = old_table[i]; dit != NULL; dit = dit->next) {
_dictAddRaw(d, dit);
}
}
free(old_table);
return;
}
As a side note, I'm not sure what your hash function does, but it seems to me that the line
int index = (hash(entry->key) & (d->size - 1));
is a little unorthodox. You get a hash value and do a bitwise and with the size of the table, which I guess works in the sense that it will be guaranteed to be within (I think?) [0, max_size), I think you might mean % for modulus.
You are freeing a pointer which is passed in to your function. This is only safe if you know that whoever's calling your function isn't still trying to use the old value of d. Check all the code which calls _dictRehash() and make sure nothing's hanging on to the old pointer.
What does dictCreate actually do?
I think you're getting confused between the (fixed size) dict object, and the (presumably variable sized) array of pointers to dictEntries in dict.table.
Maybe you could just realloc() the memory pointed to by dict.table, rather than creating a new 'dict' object and freeing the old one (which incidentally, isn't freeing the table of dictentries anyway!)
Can anyone please explain why the 1st method of accessing a nested struct element inside an union in a struct works and the 2nd does not?
typedef struct element Node;
struct element
{
int type;
union
{
int value;
Node *child[2];
} u;
};
int main()
{
Node n;
Node *p;
n.type = 0;
p = n.u.child[0];
p->type = 10; // 1st method
(n.u.child[1])->type = 24; // 2nd method
return 0;
}
Try the following:
int main()
{
Node n;
Node *p;
n.type = 0;
// allocate memory for child nodes
n.u.child[0] = (Node *)malloc(sizeof(Node));
if (n.u.child[0] == NULL)
{
return 1;
}
n.u.child[1] = (Node *)malloc(sizeof(Node));
if (n.u.child[1] == NULL)
{
free(n.u.child[0]);
return 1;
}
p = n.u.child[0];
p->type = 10; // 1st method
(n.u.child[1])->type = 24; // 2nd method
// release dynamically allocated memory
free(n.u.child[0]);
free(n.u.child[1]);
return 0;
}
NOTE: Don't modify n.u.value of a Node if you've already assigned its child[] pointers. You will overwrite one of the pointers and leak that memory as well as crash if you try to access the child[] array after that. Unions are tricky -- best to avoid this sort of arrangement.
Either of those methods should be fine for accessing a nested struct element inside a union, the issue here is that you haven't allocated memory for the nodes referred to by child[0] or child[1]. (I'm surprised your "1st method" doesn't fail, too.)
Your problem has not much to do with the fact that there are unions involved.
Accessing uninitialized pointers just gives you random behavior. Sometimes it does work sometimes not. For your first access probably something just luckily happened to be in the place that you access.
Just initialize, à la C99:
Node n = { .type = 0 };
or
Node n = { 0 };
à la C89,
instead of your assignment statement. This has the advantage to initialize all components that are not mentioned to 0, thus your pointers. Then your test code should segfault happily ever after.