Segmentation fault when using fscanf in c - c

I am really trying to learn if someone wouldn't mind to educate me in the principles I may be missing out on here. I thought I had everything covered but it seems I am doing something incorrectly.
The following code gives me a segmentation fault, and I cannot figure out why? I am adding the & in front of the arguments name being passed in to fscanf.
int word_size = 0;
#define HASH_SIZE 65536
#define LENGTH = 45
node* global_hash[HASH_SIZE] = {NULL};
typedef struct node {
char word[LENGTH + 1];
struct node* next;
} node;
int hash_func(char* hash_val){
int h = 0;
for (int i = 0, j = strlen(hash_val); i < j; i++){
h = (h << 2) ^ hash_val[i];
}
return h % HASH_SIZE;
}
bool load(const char *dictionary)
{
char* string;
FILE* dic = fopen(dictionary, "r");
if(dic == NULL){
fprintf(stdout, "Error: File is NULL.");
return false;
}
while(fscanf(dic, "%ms", &string) != EOF){
node* new_node = malloc(sizeof(node));
if(new_node == NULL){
return false;
}
strcpy(new_node->word, string);
new_node->next = NULL;
int hash_indx = hash_func(new_node->word);
node* first = global_hash[hash_indx];
if(first == NULL){
global_hash[hash_indx] = new_node;
} else {
new_node->next = global_hash[hash_indx];
global_hash[hash_indx] = new_node;
}
word_size++;
free(new_node);
}
fclose(dic);
return true;
}
dictionary.c:25:16: runtime error: left shift of 2127912344 by 2 places cannot be represented in type 'int'
dictionary.c:71:23: runtime error: index -10167 out of bounds for type 'node *[65536]'
dictionary.c:73:13: runtime error: index -10167 out of bounds for type 'node *[65536]'
dictionary.c:75:30: runtime error: index -22161 out of bounds for type 'node *[65536]'
dictionary.c:76:13: runtime error: index -22161 out of bounds for type 'node *[65536]'
Segmentation fault

Update after OP posted more code
The problem is that your hash_func works with signed integers and that it overflows. Therefore you get a negative return value (or rather undefined behavior).
That is also what these lines tell you:
dictionary.c:25:16: runtime error: left shift of 2127912344 by 2 places cannot be represented in type 'int'
Here it tells you that you have a signed integer overflow
dictionary.c:71:23: runtime error: index -10167 out of bounds for type 'node *[65536]'
Here it tells you that you use a negative index into an array (i.e. global_hash)
Try using unsigned integer instead
unsigned int hash_func(char* hash_val){
unsigned int h = 0;
for (int i = 0, j = strlen(hash_val); i < j; i++){
h = (h << 2) ^ hash_val[i];
}
return h % HASH_SIZE;
}
and call it like:
unsigned int hash_indx = hash_func(new_node->word);
Original answer
I'm not sure this is the root cause of all problems but it seems you have some problems with memory allocation.
Each time you call fscanf you get new dynamic memory allocated for string du to %ms. However, you never free that memory so you have a leak.
Further, this looks like a major problem:
global_hash[hash_indx] = new_node; // Here you save new_node
} else {
new_node->next = global_hash[hash_indx];
global_hash[hash_indx] = new_node; // Here you save new_node
}
word_size++;
free(new_node); // But here you free the memory
So it seems your table holds pointers to memory that have been free'd already.
That is a major problem that may cause seg faults when you use the pointers.
Maybe change this
free(new_node);
to
free(string);
In general I'll suggest that you avoid %ms and also avoid fscanf. Use char string[LENGTH + 1] and fgets instead.

There are multiple issues in the code posted. Here are the major ones:
you should use unsigned arithmetic for the hash code computation to ensure that the hash value is positive. The current implementation has undefined behavior as words longer than 15 letters cause an arithmetic overflow, which may produce a negative value and cause the modulo to be negative as well, indexing outside the bounds of global_hash.
You free the newly allocated node with free(new_node);. It has been stored into the global_hash array: later dereferencing it for another word with the same hash value will cause undefined behavior. You probably meant to free the parsed word instead with free(string);.
Here are the other issues:
you should check the length of the string before copying it to the node structure array with strcpy(new_node->word, string);
fscanf(dic, "%ms", &string) is not portable. the m modifier causes fscanf to allocate memory for the word, but it is an extension supported by the glibc that may not be available in other environments. You might want to write a simple function for better portability.
the main loop should test for successful conversion with while(fscanf(dic, "%ms", &string) == 1) instead of just end of file with EOF. It may not cause a problem in this specific case, but it is a common cause of undefined behavior for other conversion specifiers.
the definition #define HASH_SIZE 65536; has a extra ; which may cause unexpected behavior if HASH_SIZE is used in expressions.
the definition #define LENGTH = 45; is incorrect: the code does not compile as posted.
Here is a modified version:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#define HASH_SIZE 65536
#define LENGTH 45
typedef struct node {
char word[LENGTH + 1];
struct node *next;
} node;
int word_size = 0;
node *global_hash[HASH_SIZE];
unsigned hash_func(const char *hash_val) {
unsigned h = 0;
for (size_t i = 0, j = strlen(hash_val); i < j; i++) {
h = ((h << 2) | (h >> 30)) ^ (unsigned char)hash_val[i];
}
return h % HASH_SIZE;
}
/* read a word from fp, skipping initial whitespace.
return the length of the word read or EOF at end of file
store the word into the destination array, truncating it as needed
*/
int get_word(char *buf, size_t size, FILE *fp) {
int c;
size_t i;
while (isspace(c = getc(fp)))
continue;
if (c == EOF)
return EOF;
for (i = 0;; i++) {
if (i < size)
buf[i] = c;
c = getc(fp);
if (c == EOF)
break;
if (isspace(c)) {
ungetc(c, fp);
break;
}
}
if (i < size)
buf[i] = '\0';
else if (size > 0)
buf[size - 1] = '\0';
return i;
}
bool load(const char *dictionary) {
char buf[LENGTH + 1];
FILE *dic = fopen(dictionary, "r");
if (dic == NULL) {
fprintf(stderr, "Error: cannot open dictionary file %s\n", dictionary);
return false;
}
while (get_word(buf, sizeof buf, dic) != EOF) {
node *new_node = malloc(sizeof(node));
if (new_node == NULL) {
fprintf(stderr, "Error: out of memory\n");
fclose(dic);
return false;
}
unsigned hash_indx = hash_func(buf);
strcpy(new_node->word, buf);
new_node->next = global_hash[hash_indx];
global_hash[hash_indx] = new_node;
word_size++;
}
fclose(dic);
return true;
}

the following proposed code:
cleanly compiles
still has a major problem with the function: hash_func()
separates the definition of the struct from the typedef for that struct for clarity and flexibility.
properly formats the #define statements
properly handles errors from fopen() and malloc()
properly limits the length of the string read from the 'dictionary' file
assumes that no text from the 'dictionary' file will be greater than 45 bytes.
and now, the proposed code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
//prototypes
bool load(const char *dictionary);
int hash_func(char* hash_val);
#define HASH_SIZE 65536
#define LENGTH 45
struct node
{
char word[LENGTH + 1];
struct node* next;
};
typedef struct node node;
node* global_hash[HASH_SIZE] = {NULL};
int word_size = 0;
int hash_func(char* hash_val)
{
int h = 0;
for ( size_t i = 0, j = strlen(hash_val); i < j; i++)
{
h = (h << 2) ^ hash_val[i];
}
return h % HASH_SIZE;
}
bool load(const char *dictionary)
{
char string[ LENGTH+1 ];
FILE* dic = fopen(dictionary, "r");
if(dic == NULL)
{
perror( "fopen failed" );
//fprintf(stdout, "Error: File is NULL.");
return false;
}
while( fscanf( dic, "%45s", string) == 1 )
{
node* new_node = malloc(sizeof(node));
if(new_node == NULL)
{
perror( "malloc failed" );
return false;
}
strcpy(new_node->word, string);
new_node->next = NULL;
int hash_indx = hash_func(new_node->word);
// following statement for debug:
printf( "index returned from hash_func(): %d\n", hash_indx );
if( !global_hash[hash_indx] )
{
global_hash[hash_indx] = new_node;
}
else
{
new_node->next = global_hash[hash_indx];
global_hash[hash_indx] = new_node;
}
word_size++;
}
fclose(dic);
return true;
}

Related

Got memory leak; how to free this malloc?

bool check(const char *word)
{
int length = strlen(word);
//malloc size of char times length of word plus \0
char *lower_case = malloc(sizeof(char) * (length + 1));
lower_case[length + 1] = '\0';
//change characters to lowercase
for (int i = 0; i < length; i++)
{
lower_case[i] = tolower(word[i]);
}
//generate int hash
int index = generate_hash(lower_case);
node_ptr trav = hashtable[index];
while (trav != NULL)
{
if (strcmp(trav->word, lower_case) == 0)
{
return true;
}
trav = trav -> next;
}
free(lower_case);
return false;
}
I got 27 bytes of memory leaked from a Valgrind test; how to free it?
lower_case[length + 1] = '\0'; writes out of bounds, change to [length].
You are missing #include <stdlib.h> and other necessary includes.
You create a memory leak each time you execute return true;.
Never hide pointers behind typedefs, as taught by crap classes like CS-50.
You should be able to fix the code along the lines of this:
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>
bool check (const char *word)
{
size_t length = strlen(word);
char* lower_case = malloc(length + 1);
if(lower_case == NULL)
{
return false;
}
//change characters to lowercase
for (size_t i = 0; i < length; i++)
{
lower_case[i] = tolower(word[i]);
}
lower_case[length] = '\0';
//generate int hash
int index = generate_hash(lower_case);
bool result = false;
for(const node* trav = hashtable[index]; trav!=NULL; trav=trav->next)
{
if (strcmp(trav->word, lower_case) == 0)
{
result = true;
break;
}
}
free(lower_case);
return result;
}
The type node_ptr needs to be changed into node without hidden pointers.
There's an out of bounds access immediately after malloc.
Here, you're accessing out of bounds:
lower_case[length + 1] = '\0';
It should be:
lower_case[length] = '\0';
It's also a sensible idea to check if malloc failed, too!
As noted in comments, there's also a case when memory leak can happen when returning from inside the loop. You need to free there:
if (strcmp(trav->word, lower_case) == 0)
{
free(lower_case);
return true;
}

Realloc struct array as a function parameter yields segmentation fault?

I have searched quite a bit, before asking, but I can't seem to make this function work.
I have this array of structs with 2 strings (char*)
and the function put() that adds a new struct, Unless the key already exists in that case it just ovewrites the current value with the new one.
Despite I am passing the array by reference and not making a local copy in the function, the memory still is corrupted (Segmentation Fault).
The source code is compiled under Ubuntu 15.10 on latest version of gcc.
Thanks in advance for your help guys!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 3
struct store{
char *key;
char *value;
};
void put(char *key, char *value, struct store **store, int size){
int i, found;
struct store *temp = realloc(*store, (size + 1) * sizeof(struct store));
for(i = 0; i < size; ++i){
if(strcmp(key, store[i]->key) == 0){ //Key found, overwrite new value.
store[i]->value = strdup(value); //Assume that every value is null terminated
found = 1;
break;
}
}
if(found) return;
*store = temp;
if(!store){
perror("realloc failed");
exit(EXIT_FAILURE);
}
store[size]->key = strdup(key); //New element
store[size]->value = strdup(value);
return;
}
int main(){
int i = 0;
struct store *store = malloc(N * sizeof(struct store));
if(!store){
perror("malloc failed");
exit(EXIT_FAILURE);
}
store[0].key = strdup("123a");
store[1].key = strdup("456b");
store[2].key = strdup("789c");
store[0].value = strdup("John");
store[1].value = strdup("Sam");
store[2].value = strdup("Mary");
for(i = 0; i < N; ++i)
printf("%s, %s\n\n",store[i].key,store[i].value); //This works fine
put("123a","Jim",&store,N);
for(i = 0; i < N; ++i)
printf("%s, %s\n\n",store[i].key,store[i].value);
put("653a","Tom",&store,N);
for(i = 0; i < N+1; ++i)
printf("%s, %s\n\n",store[i].key,store[i].value);
return 0;
}
struct store *temp = realloc(*store, (size + 1) * sizeof(struct store));
for(i = 0; i < size; ++i){
if(strcmp(key, store[i]->key) == 0){ //Key found, overwrite new value.
store[i]->value = strdup(value); //Assume that every value is null terminated
found = 1;
break;
}
}
if(found) return;
*store = temp;
If the key is found, you don't assign temp to *store. realloc can move the allocated memory to a completely new address, thus leaving *store a dangling pointer. And you really should also check that temp isn't null as well.
There's also the problem of your misuse of store. store is the the address of the pointer you passed into the function, not the first element of an array.
You need to index the array like this (*store)[i].

storing value to doubly linked list in C

I have a doubly linked list data structure which is well formulated, as I have tested it on different inputs.
But, here is a piece of code where I have problem. I am trying to read in a line of string from a file, and store the values by converting them into integers in an array of integer called num. The code is fine unto here as I have printed the entries out and checked them. But when I try storing them into my doubly linked list, I get all the values correct except the second value which is an arbitrary long integer. I have my code and output below:
num_read is a function which reads all the values in a doubly linked list, and takes the array num and its length as arguments.
#include "DlistInterface.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Dnode *num_read(int *,int *);
int main(){
Dnode *number;
int num[100];
char a[10];
char *lineptr = NULL;
int j = 0;
int i = 0;
int index = 0;
size_t len;
ssize_t read;
FILE *fp;
fp = fopen("Dlist_v_array.txt","r");
while ((read = getdelim(&lineptr,&len,32,fp)) != -1){
i = 0;
index = 0;
while (1){
if ((lineptr[i] == ' ') || (lineptr[i] == '\n')) break;
else a[index++] = lineptr[i++];
}
a[index] = '\0';
num[j] = atoi(a);
printf("%d ",num[j]);
j++;
}
//printf("\n %d",j);
printf("\n");
fclose(fp);
free(lineptr);
number = num_read(num, &j);
while (number != NULL){
printf("%d ",number->data);
number = number->next;
}
printf("\n");
return 0;
}
Dnode *num_read(int *n, int *len){
int k;
for (k=1; k< *len;k++){
//printf("%d ",n[k]);
}
printf("\n");
Dnode *number = (Dnode *)malloc(sizeof(Dnode *));
number->data = n[0];
number->next = NULL;
number->prev = NULL;
Dnode *another_node;
Dnode *temp;
another_node = number;
k = 1;
while(k < *len){
temp = (Dnode *)malloc(sizeof(Dnode));
temp->data = n[k++];
temp->next = NULL;
another_node->next = temp;
temp->prev = another_node;
another_node = temp;
}
return number;
}
I get this as the output:
12 21 33 4 5 6 7 8 9
12 -2109715456 33 4 5 6 7 8 9
The first line of output is because the verification of values read in the number array, which is correct according to the values in the .txt file.
But the same values on the next line have their corresponding second entries to be a weird number, which happens to be their always, no matter what I do.
I desperately need help on this one. I will be very thankful to you all for the help. Please help!!!
Incorrect amount of memory assigned #BLUEPIXY.
// Dnode *number = (Dnode *)malloc(sizeof(Dnode *));
Dnode *number = (Dnode *)malloc(sizeof(Dnode));
To avoid this mistake in the future, and to create simpler original and maintainable code, use;
// pointer = malloc(sizeof *pointer * number_elements)
Dnode *number = malloc(sizeof *number); // number_elements == 1 in OP's case
// check pointer
if (number == NULL) return NULL; // detect and handle out-of-memory somehow
This has advantages
In C, the cast on malloc() is not needed.
by using the sizeof *pointer rather than sizeof(element_type), less chance to get the wrong type, as OP did in this post, and less to update should the type change.
By using the sizeof() first, the memory needs are calculated in at least size_t math. This becomes important with large programs: Consider int h,w; malloc(sizeof *pointer*h*w) vs. malloc(h*w*sizeof *pointer) where h*w overflowed int math, but not size_t math.
Always check for out-of-memory. At a minimum, it saves time in debugging as at least you know, proper memory allocated. Note: on some systems, if number_elements is 0 (and so is sizeof *pointer * number_elements) allocating 0 bytes may return NULL and that is not an out of memory condition.
pointer = malloc(sizeof *pointer * number_elements)
if (pointer == NULL && number_elements > 0) Handle_OOM();

realloc() invalid nxt size

I use this code, with this structure, im trying to make function to add item into array of this structure
typedef struct goods{
char *name;
int num;
} goods;
void addWord(char *what, goods *where, int pnr, int *arrsize, int n){
if (pnr >= *arrsize){
where = (goods*)realloc(where,*arrsize*2*sizeof(goods*));
*arrsize*=2;
}
where[pnr].name = (char*)malloc(strlen(what)*sizeof(char));
strcpy(where[pnr].name,what);
where[pnr].num = n;
}
in main function i have this:
int extstore = 1;
goods *store = (goods*)malloc(1*sizeof(goods*));
addWord(line, store, nr, &extstore, n);
Why am I getting an "invalid next size" runtime-error on the line where = (goods*)realloc(where,*arrsize*2*sizeof(goods*)); in addWord()?
EDIT:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct goods{
char *name;
int r;
} goods;
int main()
{
int linelen, i, nr = 0, current_r;
char *line = NULL;
size_t len = 0;
int extstore = 1;
goods *store;
store = malloc(extstore*sizeof(goods*));
while (1){
while ((linelen = getline(&line, &len, stdin)) != -1){
if (line[linelen - 1] == '\n'){
line[linelen - 1] = '\0';
}
linelen = strlen(line);
if (line[0] == '#'){
if (sscanf(line,"#%d",&current_r) != 1){
printf("bad input.");
return 0;
} else continue;
}
if (nr >= extstore){
store = realloc(store,extstore * sizeof(goods*) * 2);
extstore*=2;
}
store[nr].name = malloc(strlen(line)*sizeof(char));
strcpy(store[nr].name,line);
store[nr].r = current_r;
nr++;
}
if (linelen == -1) break;
}
printf("\n");
for (i = 0;i < nr;i++){
printf("%s, [id:%d]\n", store[i].name, store[i].r);
}
return 0;
}
extstore * sizeof(goods*) * 2
should be extstore * sizeof(goods) * 2 because the space for structures should be allocated - not just for pointers.
There is a fundamental problem in your code. You are passing pointer by value, which means that any change made to a pointer (not the variable pointed to, but the pointer itself) will not be visible from outside the function. You should pass a pointer by pointer instead, and you should check the result returned from realloc. Secondly, don't assign result of realloc back to same pointer - in case of failure you will lost pointer to memory -> thus, memory leak will occur.
To pass pointer by pointer:
void addWord( char *what, goods **where, size, ...) {
if ( *where == NULL) return; // nothing to do
if ( size < 1) return; // it would result in realloc=free call
goods *res = NULL;
res = realloc( *where, size * sizeof( goods));
if ( res != NULL) {
*where = res;
}
else {
// Error (re)allocating memory
// If realloc() fails the original block is left untouched,
// it is not freed or moved, so here *where is unchanged
}
And there is no need in C to cast a result from malloc.
* Error in `path': realloc(): invalid next size: 0x0000000000ec8010 *
This failure must be because "where" is invalid due to a heap corruption earlier in the execution.
C is pass-by-value.
Which means changing an argument in the function does not change the expression it was initialized from.
Thus, the first time realloc moves the memory, the pointer in main will be bad.
To correct that, either use an extra level of indirection, or preferably return the new value as the result.
(Anyway, you should check for allocation failure (malloc and realloc),
and you should not cast from void* to any pointer-type in C.)

Why did this worked on someone and else not me? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I got this code:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <dirent.h>
#include <stdlib.h>
#define W 1031
#define B 256
struct position {
int x;
int y;
struct position *next;
};
struct wordFiles {
char *fileName;
struct position *cor;
struct wordFiles *next;
};
struct wordTree {
char *word;
struct wordFiles *files;
struct wordTree *left;
struct wordTree *right;
};
struct wordTree *hashTable[W];
typedef struct wordFiles *files_Ptr;
typedef struct position *pos_ptr;
typedef struct wordTree *wordTreePtr;
long int power(int a, long b){
long int value,i;
value = 1;
for (i = 0; i < b; i++)
value *= a;
return value;
}
int hashValue (char *word){
long int i=0,s=0,n;
n = strlen(word);
for (i=0; i<n; i++){
s += power(B,n-i-1) * word[i];
}
return (s%W);
}
void readword(char *word , FILE *curr_file, int *x_axis, int *y_axis, int *newline, int *endfile){
char c;
c = (char) malloc(sizeof(char));
if ((fscanf(curr_file, "%s", word))!=1 || fscanf(curr_file, "%c", &c)!=1){
*endfile=1;
}
*x_axis += strlen(word);
if (strlen(word)==1 && c=='\n'){
*newline = 1;
return;
}
if (c==' ') {
*x_axis +=1;
}
else if (c=='\n') {
*newline = 1;
}
return;
}
void coordinateslistInsert (pos_ptr *lp,int x, int y){
pos_ptr prev,curr;
prev = NULL;
curr = *lp;
while (curr != NULL){
prev = curr;
curr = curr->next;
}
pos_ptr n = (pos_ptr) malloc(sizeof(struct position));
if (n == NULL) {
printf("Out of memory\n");
return;
}
n->next = NULL;
n->x = x;
n->y = y;
if (prev==NULL) {
*lp = n;
}
else {
prev->next = n;
}
return;
}
void filelistInsert (files_Ptr *lp, char *filename, int x, int y, int k) {
files_Ptr prev, curr;
prev = NULL;
curr = *lp;
if ( curr!=NULL && k == 1 && strcmp(curr->fileName, filename) == 0 ){
coordinateslistInsert(&(*lp)->cor, x, y);
return;
}
while (curr != NULL){
prev = curr;
curr = curr->next;
}
files_Ptr n = (files_Ptr)malloc(sizeof(struct wordFiles));
if (n == NULL) {
printf("Out of memory\n");
return;
}
n->fileName = filename;
n->next = NULL;
coordinateslistInsert (&(*n).cor , x ,y);
if (prev==NULL) {
*lp = n;
}
else {
prev->next = n;
}
return;
}
void treeBalancedInsert (wordTreePtr *curr_tree, char *word, char *filename, int x, int y) {
int k=0;
if (*curr_tree == NULL) {
*curr_tree =(wordTreePtr) malloc(sizeof(struct wordTree));
if (*curr_tree == NULL) {
printf("Out of memory\n");
exit(1);
}
(*curr_tree)->word=malloc(30*sizeof(char));
(*curr_tree)->left = (*curr_tree)->right = NULL;
strcpy((*curr_tree)->word,word);
filelistInsert (&(*curr_tree)->files , filename,x,y,k);
}
else {
if (strcmp((*curr_tree)->word,word) == 0){
k=1;
filelistInsert (&(*curr_tree)->files , filename,x,y,k);
return;
}
else if (strcmp((*curr_tree)->word,word) < 0)
treeBalancedInsert(&(((*curr_tree)->left)), word, filename, x, y);
else
treeBalancedInsert(&(((*curr_tree)->right)), word, filename,x ,y);
}
}
void search (char *word, int h_value, struct wordTree *hashtable[]){
wordTreePtr n = hashTable[h_value];
while(n!=NULL && strcmp ( n->word , word ) !=0){
if (strcmp ( n->word , word ) > 0 ){
n = n->right;
}
else if(strcmp ( n->word , word ) < 0){
n = n->left;
}
}
if (n==NULL){
printf("NOT FOUND");
return;
}
printf("%s\n",n->word);
files_Ptr k = n->files;
while (k!=NULL) {
pos_ptr q = k->cor ;
while (q!=NULL) {
printf("%s(%d,%d)\n",k->fileName,q->y,q->x);
q = q->next;
}
k = k->next;
}
return;
}
int main(int argc, char *argv[])
{
int j,i;
for (i=0; i<W; i++){
hashTable[i] = NULL;
}
for (j=1; j<argc; j++){
FILE *curr_file=fopen(argv[j], "r+");
int h_value = 0, x_axis = 1, y_axis=1, newline=0,endfile=0;
if (curr_file == NULL) {
perror("Error: ");
return (-1);
}
char *word=NULL , *filename;
filename = (char *) malloc(30*sizeof(char));
filename = argv[j];
while (endfile!=1){
word = (char *) malloc(20*sizeof(char));
readword(word, curr_file, &x_axis, &y_axis, &newline, &endfile);
h_value = hashValue(word);
treeBalancedInsert(&hashTable[h_value], word, filename, x_axis-(unsigned)strlen(word)-1, y_axis);
if (newline==1){
y_axis +=1;
x_axis=1;
newline=0;
}
}
fclose(curr_file);
free(word);
}
char *wordToSearch;
wordToSearch = (char *) malloc(20*sizeof(char));
scanf("%s",wordToSearch);
search(wordToSearch,hashValue(wordToSearch),hashTable);
return 0;
}
and it was written on a mac, and supposedly works. But when i compile and run on my machine it just wont.
What it does is it takes text files as arguments and sorts the words in binary trees which are placed in the hashtable depending the hashvalue of the word. And then you can type a word and it tells you the coordinates it appears and which files.
Anyway, debugging on eclipse step by step stucks at the (curr=curr->next) of the filelistInsert and code blocks shows 2 more problems, one at the treebalancedinsert function where it calls for the filelistinsert function and at the main when it calls for the treebalancedinsertfunction.
I cant find what's wrong in the filelistinsert and im short on time. (i know it's an awful question, but im desperate)
Change:
char c;
c = (char) malloc(sizeof(char));
to
char c;
Note: this is an error in your program but it is does not explain why your program is crashing.
Elsewhere:
filename = (char *) malloc(30*sizeof(char));
filename = argv[j];
It is a memory leak and also if you then suppose filename to be an array of 30 characters you might have troubles.
I see several problems.
The first thing that has alarm bells going off in my head are lines like
(*curr_tree)->word=malloc(30*sizeof(char));
and
word = (char *) malloc(20*sizeof(char));
If you read any word that's longer than 19 characters from your input file, you're going to have a buffer overflow, which will cause heartburn at some point. I'm reasonably sure that this is the source of your problem (when I run this program on its own source text, I start getting segfaults after reading "(*curr_tree)->word=malloc(30*sizeof(char));", most likely because we overflow a 20-character buffer and clobber something else.
The readword function should decide how much memory to allocate for a word based on the contents of the input file. This means you're going to have to make the readword function a bit smarter, and have it allocate/reallocate a buffer as it's reading input, something like the following:
void readword(char **word , FILE *curr_file, int *x_axis, int *y_axis, int *newline, int *endfile){
int c;
size_t bufLen = 0;
const size_t bufExtent=10;
size_t idx = 0;
*word = NULL;
/**
* Read input one character at a time until we see a space or EOF
*/
while ( ( c = fgetc( curr_file ) ) != EOF && !isspace( c ))
{
/**
* Are we at the end of our buffer?
*/
if ( idx == bufLen )
{
/**
* Extend the buffer
*/
char *tmp = realloc( *word, bufLen + bufExtent );
if ( tmp )
{
bufLen += bufExtent;
*word = tmp;
}
else
{
fprintf( stderr, "readword: Could not allocate memory to extend word\n" );
return;
}
}
(*word)[idx++] = c;
}
/**
* If we read a string, 0-terminate it
*/
if ( *word )
{
(*word)[idx] = 0;
*x_axis += strlen(*word);
}
However, even with this I'm still getting runtime errors, so there are other time bombs hiding in this code.
Then there's this:
filename = (char *) malloc(30*sizeof(char));
filename = argv[j];
This does not copy the contents of argv[j] to the memory you just allocated; instead, it assigns the pointer value of argv[j] to filename, overwriting the pointer to the memory you just allocated, leading to a memory leak. And again, you're picking an arbitrary length for the filename. Try something like the following:
filename = malloc( strlen( argv[j] ) + 1 );
strcpy( filename, argv[j] );
Style nit:
Hiding pointer types behind typedefs is not recommended, unless the type is meant to be opaque and never derferenced directly. If I see the * in the object declaration, I immediately know how it's supposed to be used in an expression. Using a foo_ptr typedef may make the code scan a little better, but it hinders undersatnding IMO. I've been bitten by this enough over the years to where I avoid using typedefs in general.

Resources