I have an array of structs that is declared as such
typedef struct bucket{
char * value;
char * key;
}BUCKET;
typedef struct item{
struct bucket * data;
struct item * next;
struct item * prev;
}ITEM;
typedef struct base{
struct item * first;
}BASE;
typedef BASE *SPACE;
It works perfectly for everything that I had to do with it. Basically I have to do an implementation of a hashmap in C. I managed to do it, but I am completely stuck on this one task. I need to make the hashmap resizable by the user.
If I want a hashmap of size 5, I do so:
SPACE *hashmap = malloc(sizeof(SPACE *) * 5);
and it works perfectly for the purpose of the program.
However, if I try to resize it using the following block of code:
void expandHashspace(SPACE *hashmap){
printf("Please enter how large you want the hashspace to be.\n");
printf("Enter a number between %d and 100. Enter any other number to exit.\n>",hashSpaceSize);
int temp = 0;
scanf("%d",&temp);
if(temp>100 || temp<hashSpaceSize){
printf("Exiting...\n");
}
else {
SPACE *nw = NULL;
nw = realloc(hashmap, sizeof(SPACE *) * temp);
hashmap = nw;
hashSpaceSize = temp;
printf("Your hashspace is now %d rows long.\n", hashSpaceSize);
}
}
It also works properly. However, when I go to utilise the hashmap itself, it ends up with a segmentation fault. Or SIGSEGV Signal 11.
For example, I have the following display function.
void displayHashspace(SPACE *hashmap){
printf("\n");
int j = 0;
for(int i = 0; i < hashSpaceSize && hashmap; i++){
BASE *linkedList = hashmap[i];
if(linkedList) {
ITEM *node = linkedList->first;
printf("\n[HASH %d]\n", i);
while (node) {
printf("\t[BUCKET %d]\n\t[VALUE] : %s\n\t[KEY] : %s\n\n",j, node->data->value, node->data->key);
node = node->next;
j++;
etc...
Using CLion's debugging, I realised this:
Let's say the hashmap size is 3. That would mean that only hashmap[0-2] exist.
If I resize the hashmap to, let's say 10, it allows me to resize.
However, while displaying, the address of hashmap[3] is really weird.
Whereas every other address is pretty long, with almost 8 digits or more, the address of hashmap[3] is always 0x21.
After this, once it reaches ITEM *node = linkedList->first; with linkedList being hashmap[3], the segmentation fault occurs.
Here's another example. Here's my saving function:
void saveHash(SPACE *hashmap){
FILE *f = fopen("hashmap.hsh","w");
fprintf(f,"%d\n",hashSpaceSize);
for(int i = 0; i < hashSpaceSize;i++){
if(hashmap[i]){
ITEM *save = hashmap[i]->first;
do{
fprintf(f,"---\n%s\n%s\n",save->data->value,save->data->key);
save = save->next;
}while(save);
etc...
Here, the story is different. It can only reach hashmap[0] before crashing after the resizing. Using the debugger, I found that somehow, the save, which is set to hashmap[0]->first (which normally works before expanding), has a BUCKET whose VALUE variable is suddenly set to NULL for some reason, hence the crash.
I tried setting every "new" BASE after expansion to NULL, but the save function still breaks after using expandHashspace().
What am I doing wrong?
Reallocating memory to hashmap wasn't working because hashmap was being a local variable in that method. Meaning everything just became a confusing nightmare.
Returning the hashmap itself instead of returning nothing solved every problem.
Related
I have a code that sorts a list, I can get it to sort when the list is hardcoded. I am now attempting to implement getting the list from an input file and running it the same way through the code then printing it to an output file. I am trying to get a scanned list from an input file to go through what I have (that is working) for sorting and for the result to be printed to an output file.
You have assigned *tmp to head. But I can see that head had always been NULL. So the loop is never entered, and nothing is being inserted to the list.
So what we'd need to do it first initialize head to a node instance
typdef struct node
{
char* data;
struct node *prev;
struct node *next;
}node;
head = malloc(sizeof(node));
then we assign it data.
head->attribute = value;
finally we set this pointer location value to our tmp pointer as well.
tmp = head;
no we can proceed with our loop
strings in C are represented as an array of chars, whose stored location points to the first element of the char array. the array must also end with a NULL chat '\0'. note that strlen(str) will return length of string without the NULL char so you must add 1 while mallocing to take this into sconsideration. i would advise not messing with strings unless absolutely necessary. by that I mean trying to manually manipulate them. this will introduce another set of problems not related to what we're working on in general. we should just use strncar(), strncpy() methods until c style strings become completely intuitive.
I hope I understood right your question. I tried to fix the program like it will read a file and make a list of the data in the file.
I fixed some issues;
For the transverse function, i added a for loop and printed the data using %c.
while (temp != NULL) {
for(i=0; temp->data[i]!='\0'; i++) {
printf("%c\n", temp->data[i]);
}
temp = temp->next;
}
I changed the insertAtEnd function like this;
void insertAtEnd(FILE* f, char* data)
And naturally, in main function, calling this function changed like;
insertAtEnd(ifp, result[i]);
By the way for the following statement, my complier wanted me to express the temp as char, it said it was the first use of this. It also seems like you entered a space after &.
insertAtEnd(ofp, &temp);
I added the following statements to the main function;
argc -= optind;
argv += optind;
I also changed this ifp= fopen(ifilename, "r"); statement with this ifp= fopen("ifilename.txt", "r");statement. I opened a text file named ifilename.txt and wrote some data there.
EDIT:
Ok so if you want to print the strings to an output file and you want to print the words in the lines individually, you will change the code doing the following things:
I changed the struct's data with an array, gave it an expected maximum line length with a sharp defined MAX_LEN;
struct node
{
char* data[MAX_LEN];
struct node *prev;
struct node *next;
};
I changed the insertAtEnd function again because I scanned the file in main function, made an array of the strings, sent it to this function and added it to the end of the list. I used this piece of code in main fuction:
char* result[count];
char* temp = (char*)malloc(sizeof(char));
while (fgets(temp, sizeof(temp), ifp))
{
result[count] = (char*)malloc(sizeof(char)*20);
strcpy(result[count], temp);
insertAtEnd(result, count);
count++;
}
count is the number of strings in the file. I also sent this number to insertAtEnd function;
void insertAtEnd(char* data[], int size)
{
//Create a new node
struct node *newnode = (struct node*)malloc(sizeof(struct node));
newnode->data[size] = data[size];
if (newnode->data[size] != NULL) {
...
I wanted to use the output file you opened in the main function, so I sent this file and sent the count -number of strings- to the printing function transverse like this;
void traverse(FILE *of, int size)
{
int i;
// List is empty
if (head == NULL) {
printf("\nList is empty\n");
return;
};
// Else print the Data
struct node* temp;
temp = head;
while (temp != NULL) {
for(i=0; i<size; i++) {
fputs(temp->data[i], of);
temp = temp->next;
}
fprintf(of, "\n");
}
}
Also in main function, calling this function will be changing like;
traverse(ofp, count);
This question already has answers here:
How to access a local variable from a different function using pointers?
(10 answers)
Closed 5 years ago.
I am writing a program that, given a set of inputs and outputs, figures out what the equation is. The way the program works is by randomly generating binary trees and putting them through a genetic algorithm to see which is the best.
All the functions I have written work individually, but there is either one or two that do not.
In the program I use two structs, one for a node in the binary tree and the other to keep track of how accurate each tree is given the data (its fitness):
struct node {
char value;
struct node *left, *right;
};
struct individual {
struct node *genome;
double fitness;
};
One function I use to randomly create trees is a subtree crossover function, which randomly merges two trees, returning two trees that are sort of a mixture of each other. The function is as follows:
struct node **subtree_crossover(struct node parent1, struct node parent2) {
struct node *xo_nodes[2];
for (int i = 0; i < 2; i++) {
struct node *parent = (i ? &parent2 : &parent1);
// Find the subtree at the crossover point
xo_nodes[i] = get_node_at_index(&parent, random_index);
}
else {
// Swap the nodes
struct node tmp = *xo_nodes[0];
*xo_nodes[0] = *xo_nodes[1];
*xo_nodes[1] = tmp;
}
struct node **parents = malloc(sizeof(struct node *) * 2);
parents[0] = &parent1;
parents[1] = &parent2;
return parents;
}
Another function used one that takes two populations (list of individuals) and selects the best from both, returning the next population. It is as follows:
struct individual *generational_replacement(struct individual *new_population,
int size, struct individual *old_population) {
int elite_size = 3;
struct individual *population = malloc(sizeof(struct individual) * (elite_size + size));
int i;
for (i = 0; i < size; i++) {
population[i] = new_population[i];
}
for (i; i < elite_size; i++) {
population[i] = old_population[i];
}
sort_population(population);
population = realloc(population, sizeof(struct individual) * size);
return population;
}
Then there is the function that essentially is the main part of the program. This functions loops through a population, randomly modifies them and chooses the best among them across multiple generations. From this, it selects the best individual (the highest fitness) and returns it. It is as follows:
struct individual *search_loop(struct individual *population) {
int pop_size = 10;
int tourn_size = 3;
int new_pop_i = 0;
int generation = 1
struct individual *new_population = malloc(sizeof(struct individual) * pop_size);
while (generation < 10) {
while (new_pop_i < pop_size) {
// Insert code where random subtrees are chosen
struct node **nodes = subtree_crossover(random_subtree_1, random_subtree_2);
// Insert code to add the trees to new_population
}
population = generational_replacement(new_population, pop_size, population);
// Insert code to sort population by fitness value
}
return &population[0];
}
The issue I am having is that the search_loop function returns a pointer to an individual that is filled with garbage values. To narrow down the causes, I began to comment out code. By commenting out either subtree_crossover() or generational_replacement() the function returns a valid individual. Based on this, my guess is that the error is caused by either subtree_crossover() or generational_replacement().
Obviously, this is a heavily reduced version of the code I am using, but I believe it still will show the error that I am getting. If you would like to view the full source code, look in the development branch of this project: https://github.com/dyingpie1/pony_gp_c/tree/Development
Any help would be greatly appreciated. I have been trying to figure this out for multiple days.
Your subtree_crossover() function is taking two nodes as values. The function will receive copies, which will then live on the stack until the function exits, at which point they will become invalid. Unfortunately, the function later sticks their addresses into an array that it returns. Therefore, the result of subtree_crossover() is going to contain two invalid pointers to garbage data.
You could initialize parents as a struct node * instead of a struct node **, and make it twice the size of a struct node. Then, you could just copy the nodes into the array. This would avoid the issue. Alternatively, you could copy the nodes onto the heap, so that you could return a struct node **. You'd then have to remember to eventually free the copies, though.
I am trying to copy strings from a field in one struct to another struct (a node), so that I can ultimately create a hashtable. However, I seem to be having some issues in the actual string copying. I've created a for loop to iterate over the strings in the source stuct, and I know the iteration is working fine, because if I printf the source strings (data[i].c_name), they print out fine. Unfortunately, when I try to printf the destination (class_id), it seems to be empty (and thus of course my hash function isn't doing much). Any insights into the potential problem here would be greatly appreciated. Please let me know if I haven't given enough context.
#define LENGTH 30
#define MAX_OBS 80000
typedef struct
{
char c_name[LENGTH];
char s_name[LENGTH];
double value[MAX_OBS];
}
sample;
typedef struct node
{
char class_id[LENGTH];
struct node *next;
}
node;
{
char class_id[LENGTH];
for (int i = 0; i < total_columns; i++)
{
// malloc a new node pointer for each new class label
node *new_node = malloc(sizeof(node));
// check that there was sufficient memory
if (new_node == NULL)
{
return 6;
}
// copy c_name into node -- failing - class_id is empty
strcpy(new_node->class_id, data[i].c_name);
printf("%s\n", class_id);
}
}
Drop the last char class_id[LENGTH]; that you print as it was never initialized. Then switch your printf() to use the actual target of the strcpy.
strncpy(new_node->class_id, data[i].c_name, LENGTH);
printf("%.*s\n", LENGTH, new_node->class_id);
I've also put a few LENGTH limits in my code to assure you don't do bad things on bad input without a terminal \0. Never blindly trust your C input unless you generated it in a fail-safe manner.
Disclaimer: desktop inspection changes. Actual debugging is left as an exercise to the student.
I wrote a quick generic linked list, simple stuff. But I have a bug and I cannot spot what it is complaining about. Pertinent code:
typedef struct _node {
void *data;
struct _node *next;
} node;
typedef struct _queue {
node *root;
node *last;
unsigned int length;
} queue;
node * find_node(void *data, int size, queue *q)
{
node *n;
for(n=q->root;n;n=n->next)
if(memcmp(data, n->data, size)==0)
return (n);
return (NULL);
}
Testing it:
queue q = {NULL, NULL, 0};
node *n;
int data[QUEUEMAX];
int i;
/* insert bunch of ints into queue */
for(i=0;i<QUEUEMAX;i++) {
data[i] = give_me_a_number();
n = alloc_node();
n->data = data[i];
insert_into(n, &q);
}
printf("list size = %d.\n", q.length);
/* print out, make sure they're there */
for(n=q.root;n;n=n->next)
printf("data = %d\n", (int)n->data); //*(int *)n->data didn't work, segfault?
/* find a specific node */
node *nd = find_node(&data[10], sizeof(int), &q);
/* remove it */
rm_node(nd, &q);
Running it:
$ ./test
list size = 256.
data = 10
data = 11
data = 12
data = 13
data = 14
data = 15
data = 16
... blah blah (256 lines)
Segmentation Fault
gdb says the problem is the memcmp() in find_node(). I think gcc is whining about the n->data being passed to memcmp(). Any ideas? Also, I was getting a segfault trying to do int x = *(int *)n->data but this seems valid to me, non?
In this code:
n->data = data[i];
You are currently setting the void* data pointer to be data[i] but you really want to set it to the address of data[i] so you need to do:
n->data = &data[i];
That is also why you got a segfault on your cast.
Segmentation Fault happens when you try to dereference NULL pointer. If you know the line where it happens verify that there no NULL there, example int x = *(int *)n->data will generate SEGFAULT if n is NULL or n->data is NULL
Assuming that your memory allocation functions are working, most likely n->data is NULL, and therefore you can't access it. Also, why are you passing the data array as &data[10]? Why not just use data since the identifier of an array is a pointer to its first location?
It looks like you are being inconsistent in whether your data is a pointer or if its a pointer thats being casted to an int. You are passing a int (since the pointer is basically a int cause of the cast).
memcpy naturally wants a void *, not an int.
So the solution really is to pass a pointer to your int in data and make everything else work with that.
Also, the memcmp call in find_node will sometimes compare too much data. You're using memcmp with the size of the data you're searching for. If the data in the current node is shorter than that, memcmp will go beyond it, into forbidden territory. (The test code you posted won't usually trip this bug, because most of the data fields have the same length.) You need to add a length field to each node, and use the minimum of both lengths in memcmp.
You're assigning an int variable
n->data = data[i];
To what it is supposed to be a pointer
typedef struct _node {
void *data;
struct _node *next;
} node;
Hey guys. This is a very simple question, I'm sure, but I'm getting myself tangled up in C references/pointers as per usual. I am trying to build a... sort-of-queue, using a sort-of-linked list. Basically, I have a struct which has contents and a pointer to the next element. I also have a pointer to the first and last elements. I then have a loop that will be building the 'sort-of-queue'. My problem is that either my logic is failing and I'm not initialising the queue right, or my knowledge of C structs is failing (which is very probable) and I'm ending up just creating one struct and constantly referring to it.
My test code is as follows:
#include <stdio.h>
struct test {
int contents;
struct test *next;
};
main() {
struct test *first = NULL;
struct test *last = NULL;
int i;
for (i = 0; i < 2; i++) {
struct test tmp;
if (first == NULL) {
first = &tmp;
last = &tmp;
} else {
last->next = &tmp;
last = &tmp;
}
tmp.x = i;
tmp.next = NULL;
}
while (first != NULL) {
printf("%d\n", first->x);
first = first->next;
}
return 0;
}
Running this, I get the output that first seems to point to a test struct that has the value of '1' as it's 'x' variable - so not the initial one like I intended. So, am I failing at logic here, or am I failing at understanding how to declare new separate structs in a loop? Or maybe both? I'm very tired... >_<.
Thanks.
The problem you have is that you are taking the address of a temporary variable, tmp, and assigning it to a pointer which lives much longer than teh temporary, first and last. After every iteration of the loop the temporary is gone and continuing to access it via first and last results in undefined behavior.
You need to create a value on the heap in order to build up the list like so (error checking omitted for brevity)
struct test* tmp = malloc(sizeof(struct test));
Later though you'll need to go through and free all of the allocated nodes.