I don't know if my problem is a memory leak, or i'm not acessing the hashtable in the correct way.
My hash.h
#define HASHSIZE 31
#define EMPTY ""
#define DELETED "-"
typedef char KeyType[9];
typedef void *Info;
typedef struct entry
{
KeyType key;
Info info;
}Entry;
typedef Entry HashTable[HASHSIZE];
My hash.c
int Hash(KeyType k){
return atoi(k)%HASHSIZE;
}
void InitializeTable(HashTable t){
for(int i=0; i < HASHSIZE; i++){
strncpy(t[i].key,EMPTY,9);
}
}
void ClearTable(HashTable t){
InitializeTable(t);
}
void InsertTable_LP(HashTable t, KeyType k, Info i){
int a = 0;
int hash = Hash(k);
while((a<HASHSIZE)
&& strcmp(t[hash].key,EMPTY)!=0
&& strcmp(t[hash].key,DELETED)!=0 ){
hash = (hash + 1) % HASHSIZE;
a++;
}
strncpy(t[hash].key,k,9);
t[hash].info = i;
printf("Value of info is %d\n",(int)t[hash].info);
}
int RetrieveTable_LP(HashTable t, KeyType k){
int a=0;
int hash = Hash(k);
while(a<HASHSIZE
&& strcmp(t[hash].key,k)!=0
&& strcmp(t[hash].key,EMPTY)!=0){
hash=(hash+1) % HASHSIZE;
a++;
}
if(strcmp(t[hash].key,k)==0)
return hash;
return -1;
}
int main(){
HashTable *t = malloc(HASHSIZE*sizeof(Entry));
int valores[] = {1,2,3,4,5,6,7,8,9};
ClearTable(*t);
InsertTable_LP(*t,"1",valores);
InsertTable_LP(*t,"2",valores+1);
InsertTable_LP(*t,"3",valores+2);
InsertTable_LP(*t,"4",valores+3);
InsertTable_LP(*t,"5",valores+4);
int pos = RetrieveTable_LP(*t,"2");
if(pos==-1){
printf("Error\n");
}
else
printf("Position %d\n",pos);
printf("okay %d\n",(int)t[pos]->info);
printf("asdasdas\n");
return 1;
}
My output is
Value of info is 1537727040
Value of info is 1537727044
Value of info is 1537727048
Value of info is 1537727052
Value of info is 1537727056
Position 2
okay 0
If anyone could explain me, thanks in advance.
valores is an array. You are inserting Info which has been typedefed to void *. You need to fix those things.
Your malloc is not necessary the reason why that wasn't obvious is because it was hidden by the way you typedefd the HashTable, don't ever do that, the following code works as you expected yours to do
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HASHSIZE 31
#define EMPTY ""
#define DELETED "-"
typedef char KeyType[9];
typedef void *Info;
typedef struct entry
{
KeyType key;
Info info;
}Entry;
typedef Entry HashTable[HASHSIZE];
int Hash(KeyType k){
return atoi(k)%HASHSIZE;
}
void InitializeTable(HashTable t) {
int i;
for(i=0; i < HASHSIZE; i++) {
strncpy(t[i].key, EMPTY, 9);
}
}
void ClearTable(HashTable t) {
InitializeTable(t);
}
void InsertTable_LP(HashTable t, KeyType k, Info i){
int a = 0;
int hash = Hash(k);
while((a<HASHSIZE) && strcmp(t[hash].key, EMPTY) !=0 && strcmp(t[hash].key, DELETED) !=0 ) {
hash = (hash + 1) % HASHSIZE;
a++;
}
strncpy(t[hash].key, k, 9);
t[hash].info = i;
printf("Value of info is %p\n", t[hash].info);
}
int RetrieveTable_LP(HashTable t, KeyType k){
int a=0;
int hash = Hash(k);
while(a<HASHSIZE
&& strcmp(t[hash].key,k)!=0
&& strcmp(t[hash].key,EMPTY)!=0){
hash=(hash+1) % HASHSIZE;
a++;
}
printf("%s, %s\n", t[hash].key, k);
if(strcmp(t[hash].key, k)==0)
return hash;
return -1;
}
int main(){
/*
* You don't need to malloc, since HashTable is an array,
* and it does not need to be a pointer, since it decays
* to one when passed as such.
*/
HashTable t;// = malloc(HASHSIZE * sizeof(Entry));
int valores[] = {1,2,3,4,5,6,7,8,9};
ClearTable(t);
InsertTable_LP(t,"1",valores);
InsertTable_LP(t,"2",valores+1);
InsertTable_LP(t,"3",valores+2);
InsertTable_LP(t,"4",valores+3);
InsertTable_LP(t,"5",valores+4);
int pos = RetrieveTable_LP(t, "2");
if(pos==-1) {
printf("Error\n");
}
else
{
printf("Position %d\n",pos);
printf("okay %p\n", t[pos].info);
}
printf("asdasdas\n");
return 1;
}
your typedef of the HashTable makes it hard to know what to do with a HashTable type variable, that is not a very good use of typedef.
Also the second printf will be executed regardless of the condition
else
printf("Position %d\n",pos);
printf("okay %d\n",(int)t[pos]->info);
you need to add {
else
{
printf("Position %d\n",pos);
printf("okay %d\n",(int)t[pos]->info);
}
Related
So i implemented a hashtable with separate chaining for a struct called Objective, so that i could perform some operations on said Objectives. Currently i have this:
Hashtable.h:
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/*Using separate chaining to store the obejctives*/
typedef struct Objective{
char name [8000];
unsigned long id, duration, deps [9000];
int hasDeps;
}*pObjective;
typedef struct nodehash{ /*Node of list*/
pObjective obj;
struct nodehash*next;
}*link;
void Init(int M);
int search(unsigned long id);
void insert(pObjective o);
void delete(unsigned long id);
link insertBegin(link h, pObjective obj);
int searchList(link h, unsigned long id);
link removeList(link h, unsigned long id);
pObjective searchObj(unsigned long id);
pObjective searchObjAux(link h, unsigned long id);
#endif
Objectives.c:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "OBJECTIVES.h"
/*Checks if all inserted dependencies already exist*/
int existDeps(unsigned long dep[9000]){
int i, count = 0;
for(i = 0; i < 9000; i++){
if(search(dep[i]) != 0)
count++;
}
return count;
}
/ *Adds objective with dependencies*/
void addObj(unsigned long id, char name [8000], unsigned long duration,
unsigned long dep[9000]){
int i;
pObjective obj = malloc(sizeof(pObjective));
obj->id = id;
obj->duration = duration;
obj->hasDeps = 1;
strcpy(name, obj->name);
for(i = 0; i < 9000; i++){
obj->deps[i] = dep[i];
}
if(search(id) != 0)
printf("id already exists\n");
else if(existDeps(dep) != 0)
printf("no such task\n");
else
insert(obj);
free(obj);
}
/*Adds objective with no dependencies*/
void addNoDeps(unsigned long id, char name [8000], unsigned long
duration){
pObjective obj = malloc(sizeof(pObjective));
obj->id = id;
obj->duration = duration;
obj->hasDeps = 1;
strcpy(name, obj->name);
if(search(id) != 0)
printf("id already exists\n");
else
insert(obj);
free(obj);
}
/*Removes objective with no dependencies*/
void removeObj(unsigned long id){
int res = search(id);
pObjective obj = searchObj(id);
if(res == 0)
printf("no such task\n");
else if(obj->hasDeps == 1)
printf("task with dependencies\n");
else
delete(id);
}
Objectives.h:
#ifndef OBJECTIVES_H
#define OBJECTIVES_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "HASHTABLE.h"
/*Functions to work with objectives*/
int existDeps(unsigned long dep[9000]);
void addObj(unsigned long id, char name [8000], unsigned long duration,
unsigned long dep[9000]);
void addNoDeps(unsigned long id, char name [8000], unsigned long
duration);
void removeObj(unsigned long id);
#endif
Hashtable.c:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "HASHTABLE.h"
#define hash(A,B) (A%B) /*Hash function*/
static link *heads;
static int M;
/*Initiates hashtable with size m*/
void Init(int m){
int i;
M = m;
heads = (link*)malloc(M*sizeof(link));
for(i = 0; i < M; i++)
heads[i] = NULL;
}
/*Searches objective with said id*/
int search(unsigned long id){
int i = hash(id, M);
return searchList(heads[i], id);
}
/*Inserts objective into hashtable*/
void insert(pObjective o){
int i = hash(o->id, M);
heads[i] = insertBegin(heads[i], o);
}
/*Deletes objective using it's id*/
void delete(unsigned long id){
int i = hash(id, M);
heads[i] = removeList(heads[i], id);
}
/*Returns objective with said id*/
pObjective searchObj(unsigned long id){
int i = hash(id, M);
return searchObjAux(heads[i], id);
}
/*Inserts objective into list*/
link insertBegin(link h, pObjective obj){
link new = (link)malloc(sizeof(struct nodehash));
new->obj = obj;
new->next = h;
return new;
}
/*Searches objective by id in a list*/
int searchList(link h, unsigned long id){
link t;
int count = 0;
for(t = h; t != NULL; t = t->next){
if(t->obj->id == id)
count++;
}
return count++;
}
/*Removes objective from list*/
link removeList(link h, unsigned long id){
link t, x, z;
for(t = h; t != NULL; t = t->next){
if(t->next->obj->id == id)
x = t;
}
z = x->next;
x->next = z->next;
free(z);
return h;
}
/*Returns objetive from said id from list*/
pObjective searchObjAux(link h, unsigned long id){
link t, x;
for(t = h; t != NULL; t = t->next){
if(t->obj->id == id)
x = t;
}
return x->obj;
}
I'm quick testing the funcions addObj (adds an objective with dependencies) and addNoDeps (adds an objective with no dependencies) on my main:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "OBJECTIVES.h"
int main(){
unsigned long array [1] = {3};
Init(11);
addNoDeps(1, "tarefa1", 20);
addObj(2, "tarefa2", 20, array);
return 0;
}
But i keep getting segmentation fault(core dumped) and i can't figure out why. Is my implementation wrong? Are the functions wrong? I can't get to the problem, can someone help me?
I can't run your code right now so I can't analyze the core dump, but I believe what is happening is that you are trying to access memory that has already been freed. At the end of addNoDeps, you free the pObjective after putting it into the list. Then, when you addObj after, you search the list and check to make sure that the links object associated with it is not null. Specifically this code:
for(t = h; t != NULL; t = t->next){
if(t->obj->id == id)
count++;
You only check to see that the t (links pointer) is not null, but since you freed the previous object, the t->obj pointer is not pointing to initialized memroy. Therefore trying to access it via t->obj->id is accessing uninitialized memory. If you remove the free(obj) at the end of your addNoDeps and addObj functions you should be fine. You may also want to add checks to make sure that t->obj is not null as well. In general segmentation faults are caused by accessing uninitialized memory, so when debugging check for accessing pointers after a free, double frees, and other things. Also learning to use GDB can help a lot in these situations.
I my code i call the insert function and it passes a pointer to the struct (table) and the insert function recieves a pointer and does some stuff and returns it again. But running the code gives segmentation fault. when i try to access the values in the struct array using the pointer passed.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define __USE_BSD
#include <string.h>
#include "speller.h"
#include "dict.h"
typedef struct
{ // hash-table entry
Key_Type element; // only data is the key itself
enum {empty, in_use, deleted} state;
} cell;
typedef unsigned int Table_size; // type for size-of or index-into hash table
struct table
{
cell *cells; Table_size table_size; // cell cells [table_size];
Table_size num_entries; // number of cells in_use
// add anything else that you need
};
int hashfunc(Key_Type k, Table_size size)
{
printf("enterd\n");
char * d = k;
int hash = 0;
int c;
printf("%s\n", d);
printf("wtf??\n");
while (c = *d++)
{
printf("maybehere??\n");
hash = hash + c;
}
hash = hash%size;
printf("%d\n", hash);
return hash;
}
Table initialize_table (Table_size size)
{
Table t = malloc(sizeof(struct table));
t->table_size = size;
cell hash_table[size];
for (int i=0; i<size; i++)
{
hash_table[i].state = empty;
hash_table[i].element = "-";
//printf("initialised\n");
}
t->num_entries = 0;
t->cells = hash_table;
/*for (int i = 0; i < t->table_size; i++)
{
printf("%d %s\n", i, (t->cells + i)->element);
}*/
return t;
}
int a = 0;
Table insert (Key_Type k, Table t)
{
//printf("insert called %d\n", a);
printf("%d\n", t->table_size);
//printf("%s\n", (t->cells + 2)->element);
// as soon as program reaches here i get output like - 1 (NULL)
2 (NULL) and then segmentation fault
for (int i = 0; i < t->table_size; i++)
{
printf("%d %s\n", i, (t->cells + i)->element);
}
a++;
printf("%s\n", k);
int hash_code = hashfunc(k, t->table_size);
// Linear Probing
printf("im here\n");
while(strcmp((t->cells + hash_code)->element,"-") != 0)
{
if (strcmp((t->cells + hash_code)->element,k) == 0)
{
printf("return at if\n");
return t;
}
else if (hash_code == (t->table_size - 1))
hash_code = 0;
else
hash_code++;
}
(t->cells + hash_code)->element = k;
(t->cells + hash_code)->state = in_use;
t->num_entries += 1;
printf("return at end with value %s\n", k);
printf("inserted value %s\n", (t->cells + hash_code)->element);
return t;
}
Boolean find (Key_Type k, Table t)
{
return FALSE;
}
void print_table (Table t)
{
Table_size size = t->table_size;
for (int i = 0; i<size; i++)
{
if (strcmp((t->cells + i)->element,"-") != 0)
printf("%d %s\n", i, (t->cells + i)->element);
}
}
void print_stats (Table t)
{
}
void main()
{
Table table;
Table_size table_size = 19;
int a = 5;
Key_Type input[5] = {"a","b","ab","abc","abcd"};
table= initialize_table (table_size);
//printf("%s\n", input[1]);
while (a)
{
table= insert("a",table);
a--;
}
printf("printing table\n");
print_table(table);
}
this is the dict.h code
typedef char* Key_Type;
typedef struct table* Table; // allows different definitions of struct table
Table initialize_table (); // allows different parameters
Table insert (Key_Type, Table);
Boolean find (Key_Type, Table);
void print_table (Table);
void print_stats (Table);
This is the speller.h code
typedef enum {FALSE, TRUE} Boolean;
extern int verbose; // used to control monitoring output
extern int mode; // used to control your algorithm
extern char *prog_name; // used by check
void check (void *memory) ; // check result from strdup, malloc etc.
I believe i dont understand how the pointers work in this program.
Here is the problem,
cell hash_table[size];
and then, you make t->cells point to hash_table but hash_table is a local variable in the initialize_table() function, so it's destroyed/deallocated when the function returns and no longer accessible after it returns.
You should allocate it on the heap too, like this
cell *hash_table;
hash_table = malloc(size * sizeof(*hash_table));
if (hash_table == NULL)
return NULL; // Probably free `t' so that no memory leaks
// happen
Accessing such a local variable that was allocated in the stack frame of a function, after that function returns is undefined behavior, the problem could happen somewhere else in the code or when accessing the pointer pointing to the deallocated data.
A side note
Be consistent with naming, and unambigous, you used a weird CamelCase and underscore combination, it doesn't matter if it's weird or not, keep it and preserve it throughout the code — respect your own style. And call the cell typedef: Cell instead.
Also, always check the return value of malloc() which returns NULL on error (allocation failure), you should write code as if all the bad things will happen, because they do.
And finally, never typedef a pointer. It doesn't help whatsoever, it only obscures the fact that a declaration is that of a pointer.
So i'm trying to figure out how to do a few different things and I haven't worked with C that much, so any help would be much appreciated.
typedef int data_t;
typedef struct set {
data_t *array;
size_t capacity;
size_t size;
} set_t;
typedef data_t* set_i_t;
#define CLEAR -1
I have gotten this method working which uses malloc and allocates memory:
int set_init( set_t *set, int capacity ){
set->array = (data_t*)malloc(capacity * sizeof(data_t));
if(set->array == NULL){
return 1;
}
else{
set->capacity = capacity;
set->size = 0;
return 0;
}
}
And a method which frees it:
void set_free( set_t *set ){
free(set->array);
set->array = NULL;
set->capacity = set->size = 0;
}
In a separate method i'm trying to set all the values in the set to -1 (CLEAR)
void set_clear( set_t *set){
int i = 0;
for (i = 0; i < set->size; i++){
set->array = CLEAR;
}
set->size = 0;
}
Return the Size of the set:
int set_size( set_t set ) {
return sizeof(set->array);
}
Return the capacity:
int set_capacity( set_t set ) {
int capacity = set->capacity;
return capacity;
}
And then print the set:
void set_print( set_t set ) {
//Honestly don't feel like i'm ready for this one yet.
}
If anyone could walk me through a couple of these or give me a little assistance on how these can work, that would be awesome. Thanks guys!
A good resource is C dynamically growing array
1
You can read about size_t. What is size_t in C?
typedef int data_t;
// Here you are redefining int to data_t this is then used in array.
typedef struct set {
data_t *array;
// The address on heap where the typedef data_t is stored
size_t capacity;
size_t size;
} set_t;
typedef data_t* set_i_t;
// not sure why this is here maybe you use somewhere else
#define CLEAR -1
2
set_free( set_t *set); Looks good to me.
set_init(); yes but no
set_t set_init(int capacity) {
// create it here then return it.
set_t ret;
ret.array = (data_t*)malloc(capacity * sizeof(data_t));
if (ret.array == NULL) return NULL;
ret.capacity = capacity;
ret.size = 0;
return ret;
}
In the calling function
set_t A = set_init(5);
if (A == NULL) fprintf(stderr, "could not alloc memory\n");
// :)
3
void set_clear( set_t *set){
// you pass the address of the struct into the function. you could also use set_i_t
//int i = 0;
// why do this you can do it in the for loop as you can see
// for (i = 0; i < set->size; i++){
for (int i = 0; i < set->size; i++){
//set->array = CLEAR; common mistake
// you are saying the address of the array. aka array[0]
// this is the same as set->(array+i)
set->array[i] = CLEAR;
}
set->size = 0;
}
4 & 5
// looks good but again better ways of doing this.
set_size( set_t set );
set_capacity( set_t set );
Better ways of managing memory such as in the example here. C dynamically growing array
6
read all about printf();
http://www.tutorialspoint.com/c_standard_library/c_function_printf.htm
void set_print( set_t set ) {
// Here you passed the struct in plain and simple no pointer......
// so you will use the '.' not the '->'
// Here we can take a look at printf();
// %d is used to print int variables.
// to start off you know you will have to loop through the array.
for (int i = 0; i < set.size; i++) {
// you know the array must be at least have one item in it.
printf("%d\n", set.array[i]);
// using printf print the data_t aka "int" item in the array
}
}
Hope this helps. G
There were a few places where you defined the function arguments with set_t instead of set_t *.
Your set_size would just return the size of the array pointer (i.e. always 4 or 8), so that needed set->size
Also, set_clear was incorrect [and wouldn't even compile].
I've added some functions and implemented the [dreaded :-)] print function. No worries ...
Anyway, here's the corrected code [please pardon the gratuitous style cleanup]:
#include <stdio.h>
#include <malloc.h>
typedef int data_t;
typedef struct set {
data_t *array; // pointer to set's data
size_t capacity; // total number of data slots
size_t size; // number of slots currently in use
} set_t;
typedef data_t *set_i_t;
#define CLEAR -1
int
set_init(set_t *set, int capacity)
{
set->array = (data_t *) malloc(capacity * sizeof(data_t));
if (set->array == NULL) {
return 1;
}
else {
set->capacity = capacity;
set->size = 0;
return 0;
}
}
// And a method which frees it:
void
set_free(set_t *set)
{
free(set->array);
set->array = NULL;
set->capacity = set->size = 0;
}
// i'm trying to set all the values in the set to -1 (CLEAR)
void
set_clear(set_t *set)
{
int i = 0;
for (i = 0; i < set->size; i++) {
#if 0
set->array = CLEAR;
#else
set->array[i] = CLEAR;
#endif
}
set->size = 0;
}
// Return the Size of the set:
int
set_size(set_t *set)
{
return set->size;
}
// Return the maximum capacity:
int
set_capacity_max(set_t *set)
{
int capacity = set->capacity;
return capacity;
}
// Return the remaining available capacity:
int
set_capacity_avail(set_t *set)
{
int capacity = set->capacity - set->size;
return capacity;
}
// add some data
void
set_append(set_t *set,int val)
{
// NOTES:
// (1) this does _not_ check for overflow against capacity
// (2) when out of capacity, we might increase capacity and do a realloc
// on array
#if 0
if ((set->size + 1) >= set->capacity) {
set->capacity += 100;
set->array = realloc(set->array,sizeof(data_t) * set->capacity);
}
#endif
set->array[set->size++] = val;
}
// And then print the set:
void
set_print(set_t *set)
{
int i;
int len;
// Honestly don't feel like i'm ready for this one yet.
// Relax, no worries ...
len = 0;
for (i = 0; i < set->size; i++) {
len += printf(" %d",set->array[i]);
if (len >= 72) {
printf("\n");
len = 0;
}
}
if (len > 0)
printf("\n");
}
int
main(void)
{
set_t myset;
set_init(&myset,100);
set_append(&myset,17);
set_append(&myset,23);
set_append(&myset,37);
set_print(&myset);
set_free(&myset);
return 0;
}
There really isnt much I can say here.
Here is my lexer file:
#include <ctype.h>
#include <stdio.h>
#include "vector.h"
enum TokenType
{
tok_let = -1,
tok_iden = -2,
tok_int = -3,
tok_end = -4
};
typedef struct
{
int type;
char* str_d;
int int_d;
} Token;
char* seed;
int i=0;
char next_char()
{
i++;
return seed[i-1];
}
vector* get_tokens(char* in)
{
vector *toks;
vector_new(toks);
seed = in;
char tap;
if(isalpha(tap = next_char()))
{
char* iden_str="";
iden_str += tap;
char nc;
while(isalnum((nc = next_char())))
iden_str += nc;
if(iden_str == "let")
{
Token* tp;
tp->type = tok_let;
vector_push(toks, (void*)tp);
goto out;
}
Token* tp;
tp->type = tok_iden;
tp->str_d = iden_str;
vector_push(toks, (void*)tp);
}
out:
return toks;
}
int main()
{
vector* toks;
toks = get_tokens("let");
Token* ftok = (Token*)vector_get(toks, 0);
switch(ftok->type)
{
case tok_let:
printf("Its a let\n");
break;
default:
printf("Ummm lol nup\n");
break;
}
}
And here is my vector file:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct d_vector
{
void **items;
int capacity;
int total;
} vector;
void vector_new(vector *v)
{
v->capacity = 4;
v->total = 0;
v->items = malloc(sizeof(void*)*v->capacity);
}
int vector_total(vector *v)
{
return v->total;
}
static void vector_resize(vector *v, int capacity)
{
void** items = realloc(v->items, sizeof(void*) * capacity);
if(items)
{
v->items = items;
v->capacity = capacity;
}
}
void vector_push(vector *v, void* item)
{
if(v->capacity == v->total)
vector_resize(v, v->capacity * 2);
v->items[v->total++] = item;
}
void vector_set(vector *v, int index, void* item)
{
if(index >= 0 && index < v->total)
v->items[index] = item;
}
void* vector_get(vector *v, int index)
{
if(index >= 0 && index < v->total)
return v->items[index];
return NULL;
}
void vector_remove(vector *v, int index)
{
if(index < 0 || index >= v->total)
return;
v->items[index] = NULL;
for (int i = 0; i < v->total - 1; i++) {
v->items[i] = v->items[i + 1];
v->items[i + 1] = NULL;
}
v->total--;
if (v->total > 0 && v->total == v->capacity / 4)
vector_resize(v, v->capacity / 2);
}
void vector_free(vector *v)
{
free(v->items);
}
When I run the code above, I get a Seg-Fault.
How can this be happening? Here is the output of gdb:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400656 in vector_new (v=0x1) at vector.h:14
14 v->capacity = 4;
As you can see, its segfaulting when i set the vector capacity!
But why?
It segfaults because you dereference a garbage pointer:
vector* get_tokens(char* in)
{
vector *toks;
vector_new(toks);
The variable toks is not assigned to anything meaningful, just whatever garbage value happens to be floating about. This gets passed into vector_new() which immediately dereferences it:
void vector_new(vector *v)
{
v->capacity = 4;
Then BAM! it blows up because v points nowhere appropriate.
Try mallocing a vector before making your call to vector_new() or put the malloc in vector_new() and have it return the pointer to the new vector instead. It's also a good idea to check the return value from malloc().
You might try something like:
vector *vector_new(void)
{
vector *v;
if ( (v = malloc(sizeof(*v))) == NULL ) {
/* Replace with something appropriate */
exit(EXIT_FAILURE);
}
v->capacity = 4;
v->total = 0;
if ( (v->items = malloc(sizeof(*v->items)*v->capacity)) == NULL ) {
/* Replace with something appropriate */
exit(EXIT_FAILURE);
}
return v;
}
Then change how you call it:
vector* get_tokens(char* in)
{
vector *toks;
toks = vector_new();
And for every malloc(), let there be a free(). Don't forget to clean up this allocation too or you'll leak memory:
void vector_free(vector *v)
{
free(v->items);
free(v);
}
(You defined a vector_free(), but never called it. You might want to consider doing that too.)
invalid pointer dereference happened
vector *toks;
vector_new(toks);
Should be
vector *toks = (vector*)malloc(sizeof(vector));
vector_new(toks);
Alright sorry for creating another question but the last one got overwhelmed and chaotic.
So I'm making a hash table which inserts words from a file (tokens) and after I have inserted them I need to sort them. The program template was given, the only functions that weren't complete were : insert_ht() , clear_ht() and compare. Even though I've done tons of search about qsort with compare, the program doesn't sort the frequencies (number of times each word was inserted) . I want em sorted from the highest to lowest.
Here is the code : "note that i shouldn't change any function except insert_ht() , clear_ht() and compare
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define HTABLE_SIZ 1001
#define MAX_LINE_SIZ 1024
/* Hash Table */
typedef struct node* link;
struct node { char *token; int freq; link next; };
link htable[HTABLE_SIZ] = { NULL }; /* Table of lists (#buckets) */
int size = 0; /* Size (number of elements) of hash table */
unsigned int hash (char *tok );
void insert_ht (char *data);
void clear_ht ( );
void print_ht ( );
void Process(FILE *fp);
int main(int argc, char *argv[])
{
int i;
FILE *fp;
printf("prin tin for \n");
for (i=1; i < argc; i++)
{
printf("prin tin fopen \n");
fp = fopen(argv[i],"r");
if (NULL == fp)
{
fprintf(stderr,"Problem opening file: %s\n",argv[i]);
continue;
}
printf("prin tin process \n");
Process(fp);
fclose(fp);
}
print_ht();
//clear_ht();
return 0;
}
void Process(FILE *fp)
{
const char *seperators = " ?!'\";,.:+-*&%(){}[]<>\\\t\n";
char line[MAX_LINE_SIZ];
char *s;
while((fgets(line,MAX_LINE_SIZ, fp)) != NULL)
{
for (s=strtok(line,seperators); s; s=strtok(NULL,seperators)){
printf("prin tin insert %s \n",s);
insert_ht(s);
}
}
}
/* Hash Function */
unsigned int hash(char *tok)
{
printf("bike stin hash \n");
unsigned int hv = 0;
while (*tok)
hv = (hv << 4) | toupper(*tok++);
printf("VGAINEIIIIIIIIIIIIII %d \n",hv);
return hv % HTABLE_SIZ;
}
void insert_ht(char *token)
{
printf("bike stin insert %s \n",token);
unsigned int hashval = hash(token);
struct node *new_list;
if (htable[hashval]==NULL){
printf("mesa stin prwti if %u %s \n",hashval,token);
//token = strdup(token);
new_list = malloc(sizeof(link));
new_list->token = strdup(token) ;
new_list->freq = 1;
new_list->next = htable[hashval];
htable[hashval] = new_list;
size++;
}else {
htable[hashval]->freq++;
}
printf("ta evale epitixws \n");
}
void clear_ht()
{
int i;
for(i=0; i<HTABLE_SIZ; i++) {
while(htable[i]->token!=NULL) {
htable[i]->token=NULL;
htable[i]->freq=NULL;
free(htable[i]);
}
}
}
int compare(const void *elem1, const void *elem2)
{
const struct node *p1 = elem1;
const struct node *p2 = elem2;
if (p1->freq > p2->freq)
return(+1);
else if (p1->freq < p2->freq)
return(-1);
else
return(0);
}
void print_ht()
{
int i, j=0;
link l, *vector = (link*) malloc(sizeof(link)*size);
for (i=0; i < HTABLE_SIZ; i++)
for (l=htable[i]; l; l=l->next)
vector[j++] = l;
qsort(vector,size,sizeof(link),compare);
for (i=0; i < size; i++)
printf("%-50s\t%7d\n",vector[i]->token,vector[i]->freq);
free(vector);
}
Ι found the solution. Apparently for some reason my compare function was wrong.
I still haven't figured out why but here is the correct one, hopefully someone else will find this post helpful!
int compare(const void *elem1, const void *elem2)
{
return (*(link*)elem2)->freq - (*(link*)elem1)->freq;
}