I have an array which has a key and info for each index in the array.
This builds the array
table_t *table_construct (int table_size, int probe_type)
{
int i;
table_t *hash;
if(table_size < 1) return NULL;
hash = malloc(sizeof(table_t));
hash->table = malloc(sizeof(list_t*) * table_size);
for(i=0; i < table_size - 1; i++)
{
hash->table[i] = NULL;
//hash->table[i]->next = NULL;
}
hash->size = table_size;
hash->probing_type = probe_type;
return hash;
}
So I have the list_t and the table_t structures. I have the following line in my code that is not working correctly:
hash->table[item]->K = K;
It can be seen in this part of my code:
int dec, item, hold;
item = hashing(hash,K);
hold = item;
if(hash->table[item] == NULL)
{
hash->table[item]->K = K;
hash->table[item]->I = I;
return 0;
}
When I GDB it, K is a number.
So what is happening here is, I have my table which is indexed with item. Then I add K to the key of the index. When ever this line comes up anywhere in my program I get a seg Fault.
Can you see anything Ive done wrong here?
You verified your pointer is null, so before you can reference off it you need to assign it something:
if(hash->table[item] == NULL)
{
hash->table[item] = malloc(sizeof(list_t)); // you were missing this.
hash->table[item]->K = K;
hash->table[item]->I = I;
return 0;
}
According to what you posted in your table_construct function, the elements of table array are null pointers. You are not allowed to perform any kind of access through null pointers.
And this just doesn't make sense
if(hash->table[item] == NULL)
{
hash->table[item]->K = K;
hash->table[item]->I = I;
return 0;
}
Here you make an explicit attempt to write data through a null pointer.
You have to make sure a pointer points to a valid object before you make any attempts to access anything (write or read) through that pointer.
In your function table_construct,when you malloc hash->table,you should do it like this.
hash->table = (list_t **)malloc(sizeof(list_t*) * table_size);
for (i=0;i<table_size;i++)
{
hash->table[i] = (list_t *)malloc(sizeof(list_t));
}
You do that made then null,if you want to do like this.
memset(hash->table[i],0,sizeof(list_t));
Then you can use this judgment statement.
if(hash->table[item] != NULL)
{
hash->table[item]->K = K;
hash->table[item]->I = I;
return 0;
}
Related
I wanted to add values into my. array
typedef struct teleporter {
int start;
int end;
}teleporters;
int main(int argc, char **argv) {
int lenght = 2;
teleporters *teleportPlaces;
teleporters mytele;
mytele.start = 0;
mytele.end = 0;
teleportPlaces = calloc(2, sizeof(teleporters));//malloc (sizeof(teleporters) * (lenght));
if (teleportPlaces != NULL) {
teleportPlaces = NULL;
}
for (int i = 0; i < lenght; i++) {
teleportPlaces[i] = mytele;
}
printf("Teleport END[0] = %d",teleportPlaces[0].end);
free(teleportPlaces);
return 0;
}
but everytime i add it, it gave me an segmentation error,
how do i solve this error? it'll be great if there's an article or answer about it, thanks
The problem is that you are literally throwing away the address to your teleportPlaces right after allocating it.
Remove the if statement in which you point teleportPlaces to NULL.
In the for loop, the address teleportPlaces[i] is supposed to be the address to the beginning of your array (teleportPlaces) and an offset (i). But when you reassign it to rather point to NULL, the actual address to the array is lost, leaving you with memory leakage (since you can't free a calloc if you don't know the address to it).
This if statement
if (teleportPlaces != NULL) {
teleportPlaces = NULL;
}
does not make a sense. It means that if the memory was allocated successfully you set the pointer teleportPlaces to the allocated memory to NULL, producing a memory leak.
After that you are using this null pointer in the following for loop.
Remove this if statement or for example write
if (teleportPlaces == NULL) return 0;
Or
if (teleportPlaces != NULL) {
for (int i = 0; i < lenght; i++) {
teleportPlaces[i] = mytele;
}
printf("Teleport END[0] = %d\n",teleportPlaces[0].end);
}
free( teleportPlaces );
Also you could simplify this code snippet
teleporters mytele;
mytele.start = 0;
mytele.end = 0;
the following way
teleporters mytele = { .start = 0, .end = 0 };
Also do not use magic numbers like 2. Instead of this statement
teleportPlaces = calloc(2, sizeof(teleporters));
you should write
teleportPlaces = calloc( length, sizeof(teleporters));
I'm doing a problem on Leetcode. It says I passed my first test case but I failed my second with a simple wrong answer. When I ran that case manually, I passed, so I know it's something to do with data persistence between their runs. It's obviously the hash table I'm using, which I first declared globally. To fix, I first tried resetting to zero with calloc and memset but I got segfault errors.
I decided the logical thing is to create the hash inside the caller function, so each time it's called it would be reinitalized. However, I am still getting seg fault errors (address sanitizer deadly signal) even though it seems like it should work. Am I misusing pointers?
Here is my code that's not working. The comments //\ represent lines of code I had before, where it did work case by case. There were not many changes- mostly to return the hash. I comment where the seg fault occurs (per my printf debugging). I hope I didn't miss anything. I'm trying to display two coding instanecs in one because it's mostly reduntant.
#define SIZE 1000
typedef struct htent{
struct htent* next;
int key, value;
} htent;
int hashf(int val, int size){
return val % SIZE; // don't need anything fancy
}
htent* create_new_htent(int val){ // the value is its own key
htent* ent = malloc(sizeof(htent));
ent->next = NULL;
ent->key = val;
ent->value = val;
return ent;
}
// htent* ht[SIZE] = {0}; //\\ This was my method before (main difference)
htent* build_hash_table_n_get_lowest(int* nums, int numsSize, int* low){ //\\ returned void before
htent* ht[SIZE] = {0}; //\\ before was commented out
int hash;
int running_low = 10000; // large #
htent* tmp;
for (int i = 0; i < numsSize; i++){
if (nums[i] < 1 ) continue; // drop negatives
if (nums[i] < running_low) running_low = nums[i];
printf("%d: Running Low %d\n", i, running_low);
htent* ent = create_new_htent(nums[i]);
hash = hashf(nums[i], numsSize);
if (ht[hash] == NULL){
ht[hash] = ent; // singly linked list
continue;
}
tmp = ht[hash];
while(tmp->next != NULL){
tmp = tmp->next;
}
tmp->next = ent;
}
*low = running_low;
return ht; //\\ was commented out before
}
int find_missing_lowest(htent** ht, int numsSize, int lowest){
int moving_target = 1;
for (int i = 0; i<numsSize; i++){
if (ht[moving_target] == NULL){ // SEG FAULTS HERE!!!
return moving_target;
}
moving_target++;
}
return moving_target;
}
int firstMissingPositive(int* nums, int numsSize){ // Function Leetcode calls
int lowest;
htent* ht = build_hash_table_n_get_lowest(nums, numsSize, &lowest); // tried with htent**
return find_missing_lowest(ht, numsSize, lowest);
}
EDIT: I built this function using the global scope approach and it works and these tests pass (just have to handle edge cases), but there has to be a better way;
void refresh_hashtable(){
for (int i = 0; i<SIZE; i++){
ht[i] = NULL;
}
}
I got assigment from the professor to create a list using pointers. I'm having a problem with free() in all of my functions when I try to free memory. I keep getting a message:
"HEAP CORRUPTION DETECTED: after Normal block (#83) at 0x00D58CE0.
CRT detected that the application wrote to memory after end of heap buffer."
I have no idea how to fix it. I've tried different things but nothing worked so far. I'm not sure where to search for it either anymore. I know that my program is not properly secured yet, but it doesn't affect the problem. I'm trying to eliminate it first before going further with it. Also, do you have any advice on detecting memory leaks from the program in visual studio? Here are my functions, full source code is below in the link:
Full Source Code
struct ListElement
{
int value;
struct element *next;
};
typedef struct ListElement List;
typedef List *ListEl;
void ViewListBackwards(ListEl *list_el)
{
ListEl current_element = *list_el;
int size = 0;
int i = 0;
int *reversed_array;
while (current_element->next != NULL)
{
size++;
current_element = current_element->next;
}
current_element = *list_el;
reversed_array = (int*)malloc(size * sizeof(*reversed_array));
for (i = size; i >= 0; i--)
{
reversed_array[i] = current_element->value;
current_element = current_element->next;
}
for (i = 0; i <= size; i++)
{
printf(" %d. %d\n", i + 1, reversed_array[i]);
}
free(reversed_array);
}
void RemoveFromListFront(ListEl *list_el)
{
if (ListEmpty(list_el) == 0)
{
ListEl current_element = *list_el;
*list_el = current_element->next;
free(current_element);
}
else
{
printf("List is empty!\n");
}
}
void RemoveFromListBack(ListEl *list_el)
{
if (ListEmpty(list_el) == 0)
{
ListEl current_element = *list_el;
ListEl last_element = *list_el;
while (current_element->next != NULL)
{
last_element = current_element;
current_element = current_element->next;
}
last_element->next = NULL;
free(current_element);
}
}
In the following code:
reversed_array = (int*)malloc(size * sizeof(*reversed_array));
for (i = size; i >= 0; i--)
{
reversed_array[i] = current_element->value;
current_element = current_element->next;
}
for (i = 0; i <= size; i++)
{
printf(" %d. %d\n", i + 1, reversed_array[i]);
}
you are allocating (what amounts to) an int reversed_array[size] array, but then proceed to write to reversed_array[size], which is sizeof(int) past the end of the allocated memory segment.
You instead want to change your for loops to:
for (i = size - 1; i >= 0; i--)
so that the indices you write to start at reversed_array[size - 1].
EDIT:
As an aside, please, as other people have suggested in the comments, don't cast malloc(). This is unneeded in C, as void * can be assigned to any object pointer type variables, and in addition can hide bugs in your code, such as forgetting to include stdlib.h.
And FWIW, you don't need the parentheses around sizeof(*reversed_array), as parentheses are only needed when applying the sizeof operator to types.
This is mostly just a style suggestion; it is preferred by many (myself included) that you omit the extraneous parentheses and write that expression as sizeof *reversed_array, as that makes it clear that sizeof is a unary operator and not a function.
In my below code I am trying to create a dynamically expandable array of memory.
#include <stdio.h>
#include <stdlib.h>
#define BLOCKSIZE 5
int hash_table_length = 0;
int *currentblock = NULL;
int size_left;
int *hash_table = NULL;
int *start = NULL;
int *create_hash_table() {
int *tmp;
if (currentblock == NULL || size_left == 0) {
if (currentblock == NULL) {
currentblock = (int *) malloc( BLOCKSIZE * sizeof(int));
start = currentblock;
size_left = BLOCKSIZE;
} else {
currentblock = (int *) malloc( BLOCKSIZE * sizeof(int));
size_left = BLOCKSIZE;
}
}
tmp = currentblock++;
size_left -= 1;
return tmp;
}
void build() {
int hash;
int i = 0;
for (i = 0; i < 20; i++) {
hash = i + 3;
if (hash_table_length == 0) {
hash_table = create_hash_table();
hash_table_length++;
} else {
hash_table = create_hash_table();
hash_table_length++;
}
hash_table = &hash;
printf("hash value is %d\n", *hash_table);
}
}
int main() {
build();
// How do I reach the start of the hash table again?
// the below start does not give me the first value
printf("Hash table first value is %d\n", *start);
return 0;
}
My problem here is I wish to traverse through the values stored in the hash_table. I am unable to reach to the first element/address of the hash_table. I wish to print out all the values stored in my hash table. How can this be done?
In your code the hash values never get stored inside the hash table(inside currentblock). Inside the create_hash_table() function you allocate memory for a new block but never store values inside this block. Thus if you try dereferencing any of these int* locations you might get a garbage value(which may be a 0).
This is what is precisely happening inside your main() function when you dereference the start pointer. It is infact pointing to the start of the hash table and as that location is uninitialized it gives an output of 0.
To actually store values inside the hash table change the following inside build():
hash_table = &hash;
to:
*hash_table = hash; // Store value of 'hash' inside the memory location pointed to by hash table(which happens to be 'current_block' inside build())
Now if you try running the code, it will output 3.
Coming to the second part of question as to how you'll traverse the entire hash table: It cannot be done using this code. This is because there is no linkage between your malloc'd blocks of integers. The malloc() call can assign any block of free memory from the heap. Thus in the current form you have disconnected blocks of locations which cannot be traversed.
Instead of malloc you can use realloc to increase the size of your current block. realloc allocates memory for the larger block and copies your previous data to this new block. This will essentially allow you to traverse the entire hash table using start.
Here is how you might do that:
#include <stdio.h>
#include <stdlib.h>
#define BLOCKSIZE 5
int hash_table_length = 0;
int *currentblock = NULL;
int size_left;
int *hash_table = NULL;
int *start = NULL;
int *create_hash_table() {
int *tmp;
if (currentblock == NULL || size_left == 0) {
if (currentblock == NULL) {
currentblock = (int *) malloc(BLOCKSIZE * sizeof(int));
start = currentblock;
size_left = BLOCKSIZE;
} else {
/* Call realloc() to allocate new memory block of size (hash_table_length+BLOCKSIZE) and copy previous data*/
currentblock = ((int *) realloc(start,(hash_table_length + BLOCKSIZE) * sizeof(int))) + hash_table_length;
size_left = BLOCKSIZE;
}
}
tmp = currentblock++;
size_left -= 1;
return tmp;
}
void build() {
int hash;
int i = 0;
for (i = 0; i < 20; i++) {
hash = i + 3;
if (hash_table_length == 0) {
hash_table = create_hash_table();
hash_table_length++;
} else {
hash_table = create_hash_table();
hash_table_length++;
}
/* Store value of hash inside the hash_table */
*hash_table = hash;
printf("hash value is %d\n", *hash_table);
}
}
int main() {
int i;
build();
printf("Hash table first value is %d\n", *start);
/* Traverse the hash table */
for(i = 0; i < hash_table_length; ++i)
printf("hash_table[%d] = %d\n",i,*start++);
return 0;
}
I've been googling and trying to do this all day but with no success. There are other topic with similar problems but I can't seem to make it work.
This is the code:
void sort_structs_example(Stock **head, int count)
{
Stock **toSort = NULL;
int i;
memLoc(&toSort, sizeof(toSort)*count);
for (i = 0; count > 0 && i < count && (head != NULL); i++)
{
if (i == 0) toSort[0] = *head;
else
{
toSort[i] = toSort[i - 1]->next;
}
}
qsort(toSort, count, sizeof(Stock), struct_cmp_by_product);
for (i = 0; count > 0 && i < count && (head != NULL); i++)
{
printColor(-1, i, toSort[i]->name, 'G', 'B');
}
system("pause");
free(toSort);
}
int struct_cmp_by_product(const void *Ap, const void *Bp)
{
Stock A = *(Stock *)Ap;
Stock B = *(Stock *)Bp;
return strcmp((&A)->name, (&B)->name);
}
Stock is a struct with a variable "name" and "next" in it.
parameter "count" receives the number of current Stock structures.
parameter **head is a pointer the last added Stock, and I access other Stocks by going (*head)->next , it's a linked structure.
This is memLoc:
int memLoc(void **var, int size)
{
if (NULL == (*var = malloc(size)))
{
return 0;
}
else return 1;
}
So I think I amn't using memLoc right and something in the qsort condition is messed up but I got tangled in all the pointers. Help please? Thanks.
I can't offer a solution but I can see you are getting tangled in your pointers. In struct_cmp_by_product() you have copied the struct values to local variables and then used them as pointers.
return strcmp((&A)->name, (&B)->name);
Would be better using the local structures directly
return strcmp(A.name, B.name);
Even better would be this, which recasts the pointer types (not what they point to).
int struct_cmp_by_product(const void *Ap, const void *Bp)
{
return strcmp( ((Stock *)Ap)->name, ((Stock *)Bp)->name );
}
The reason this is better is because Stock might be a very large structure, and it's not necessary to make local copies.