RPN calculator using linked list - c

I'm having trouble with my code. it seems to work only on single digit int. I don't know how to create a function that would work for int greater than 9. Also I don't know how to end the program if string is empty.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
//stack type
struct node
{
int head;
int *array;
unsigned capacity;
};
struct node* createNode();
int isEmpty();
char pop();
void push(struct node* stack, char op);
int evaluatePostfix();
int main() {
char exp[1000]; // = "5 1 2 + 4 * + 3 -";
printf("Input string:\t");
fgets(exp, 1000, stdin);
for(int i = 1 ; i <= strlen(exp); i++) {
if(exp[i] == '\n') {
exp[i] = '\0';
}
else if (exp[0] == '\n') {
printf("stack is empty\n");
exit(0);
}
}
printf ("%s = %d\n", exp, evaluatePostfix(exp));
return 0;
}
struct node* createNode(unsigned capacity) {
struct node* stack = (struct node*) malloc(sizeof(struct node));
if (!stack) return NULL;
(*stack).head = -1;
(*stack).capacity = capacity;
(*stack).array = (int*) malloc((*stack).capacity *sizeof(int));
if (!(*stack).array) return NULL;
return stack;
}
int isEmpty(struct node *stack) {
return (*stack).head == -1 ;
}
char pop(struct node* stack) {
if (!isEmpty(stack))
return (*stack).array[(*stack).head--] ;
return '$';
}
void push(struct node* stack, char op) {
(*stack).array[++(*stack).head] = op;
}
// The main function that returns value of a given postfix expression
int evaluatePostfix(char* exp) {
// Create a stack of capacity equal to expression size
struct Stack* stack = createStack(strlen(exp));
struct node *stack = createNode(strlen(exp));
if (!stack) return -1;
// Scan all characters one by one
for (int i = 0; exp[i]; ++i){
// If the scanned character is an operand or number,
// push it to the stack.
if ((exp[i])== ' ') continue;
else if (isdigit(exp[i]))
push(stack, exp[i] - '0');
// If the scanned character is an operator, pop two
// elements from stack apply the operator
else
{
int val1 = pop(stack);
int val2 = pop(stack);
switch (exp[i])
{
case '+': push(stack, val2 + val1); break;
case '-': push(stack, val2 - val1); break;
case '*': push(stack, val2 * val1); break;
case '/': push(stack, val2/val1); break;
}
}
}
return pop(stack);
}

I can't write the whole thing for you but can point you in the right direction. Firstly, when someone says "library function XYZ() would be helpful for you" then you should go and read about that function in the manual pages. For example, from a Linux shell run: man atoi to read about the atoi function.
For your particular problem, it boils down to parsing strings and converting them to numbers and operators. Some helpful library functions would thus be:
strtok: Extracts delimited string tokens from a longer string. You can use this to get each of the seperate inputs.
atoi: This can convert a string representation of a number to its integer equivalent. Does not allow for error checking.
strtol: Can do the same as atoi (and more) and also allows for error checking.
With that information in mind, here is a code snippet that may be useful for you:
int evaluatePostfix(char* exp)
{
char *token;
long int number;
/* strtok will keep extracting the next token delimited by space */
while (token = strtok(exp, " ")) {
/* Now parse the token and process it */
if (is_operator(token)) {
/* do operator processing */
} else {
number = strtol(token, NULL, 10);
/* do number processing */
}
}
/* strtok returns NULL when no more tokens. So
we are done when the while loop exits */
}
Note that the above code does not do error checking on strtol. You probably want to do that. Read the manual pages for strtol to understand how error checking is done for it.

Related

Segmentation fault in postfix to infix C code

I'm writing a code to convert postfix to infix. but when i try to print the stack elements to check it it's not showing any thing. in the push function it prints the top element, but the display function only shows the top element no matter what. and there is segmentation fault after the line strcat(nn,y).The input i tried was 09+.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 20
char *stk[MAX], a[MAX];
int t = -1;
void push(char x[]);
void pop();
void display();
int main()
{
int i = 0;
char *x, *y, nn[MAX];
printf("enter expression:");
gets(a);
while (a[i] != '\0')
{
if (isdigit(a[i]))
{
push((char [2]){ a[i], '\0' });
}
else
{
display();
pop();
x = stk[t];
pop();
y = stk[t];
strcpy(nn, "");
strcat(nn, "(");
strcat(nn, y);
strcat(nn, (char [2]){ a[i], '\0' });
strcat(nn, x);
strcat(nn, ")");
push(nn);
}
i++;
}
printf("%s", stk[0]);
}
void push(char x[])
{
t = t + 1;
stk[t] = x;
printf("curtop %d:%s\n", t, stk[t]);
}
void pop()
{
t = t - 1;
}
void display()
{
printf("%s:%s", stk[t], stk[t - 1]);
}
I will reiterate the comments, with some references, and add a few thoughts of my own.
The first thing you should do is read Why is the gets function so dangerous that it should not be used? gets was removed from language in C11, any halfway modern tool chain should not include it:
example.c:5:9: warning: implicit declaration of function ‘gets’; did you mean ‘fgets’? [-Wimplicit-function-declaration]
fgets is the suggested replacement. Use it.
Both compound literals
(char [2]){ a[i], '\0' }
occur at block scope, and thus have automatic storage duration. This means the lifetime of each object ends when their respective enclosing blocks end.
As such, you are pushing a soon-to-be dangling pointer on to the stack.
This is an example of Undefined Behaviour.
The following
push(nn);
repeatedly pushes the same pointer to the first element of nn on to the stack. This pointer value is always the same, and always points to the current contents of the array, which is constantly being changed.
Both these problems are solved by using dynamic memory to create copies of the strings pushed on to the stack.
nn (infix expression buffer) has the same size as a (postfix expression buffer), with both being much too small.
Remembering that to store a string in a buffer, the size of the buffer must be at least the length of the string plus one (for the null terminating byte).
The postfix expression
09+6+10*+63-/
has a string length of 13, which fits in a. With your parenthesis rules, this creates the infix expression
((((0+9)+6)+(1*0))/(6-3))
which has a string length of 25. This does not fit in nn, and strcat does nothing to guard against buffer overflows.
This would be another example of Undefined Behaviour.
As a quick point of design
pop();
x = stk[t];
is clumsy.
While the use of file scope variables (globals) and functions that wrap around them is a very common way data structures are introduced to beginners, you should still aim to implement something closer to an abstract data type.
pop should return the topmost element of the stack, and you as a user of the pop function should not care how that is managed, just that it behaves as expected.
char *x = pop();
The next step is to remove the file scope variables, so that more than one stack can exist in your programs at the same time.
Here is a cursory example program that addresses most of the issues discussed. Note that it parses input slightly differently, using whitespace as a delimiter. It follows your rules for parenthesis.
It does not validate operands or the resulting expression. Operands can be longer than a single character.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 256
#define SEP " \r\n"
#define STACK_INIT { 0 }
#define STACK_MAX 64
struct stack {
size_t height;
char *data[STACK_MAX];
};
size_t count(struct stack *s)
{
return s->height;
}
int push(struct stack *s, const char *item)
{
if (s->height >= STACK_MAX)
return 0;
char *copy = malloc(1 + strlen(item));
if (!copy)
return 0;
strcpy(copy, item);
s->data[s->height++] = copy;
return 1;
}
char *pop(struct stack *s)
{
return s->height ? s->data[--s->height] : NULL;
}
void free_stack(struct stack *s)
{
char *item;
while ((item = pop(s)))
free(item);
}
int main(void)
{
char buffer[BUF_SIZE];
printf("enter expression: ");
fflush(stdout);
if (!fgets(buffer, sizeof buffer, stdin)) {
if (ferror(stdin))
perror("reading stdin");
return EXIT_FAILURE;
}
struct stack tokens = STACK_INIT;
char *tok = strtok(buffer, SEP);
while (tok) {
char expr[BUF_SIZE * 2];
/* is the first and only character an operator? */
int is_op = strchr("+-/*", *tok) && !tok[1];
if (is_op) {
if (count(&tokens) < 2) {
fprintf(stderr, "Operator (%c) needs two operands.\n", *tok);
free_stack(&tokens);
return EXIT_FAILURE;
}
char *rhs = pop(&tokens);
char *lhs = pop(&tokens);
if (snprintf(expr, sizeof expr, "(%s %c %s)", lhs, *tok, rhs) >= sizeof expr)
fprintf(stderr, "Warning: expression truncated.\n");
free(rhs);
free(lhs);
}
if (!push(&tokens, is_op ? expr : tok)) {
fprintf(stderr, "Failed to push stack item.\n");
free_stack(&tokens);
return EXIT_FAILURE;
}
tok = strtok(NULL, SEP);
}
for (char *s; (s = pop(&tokens)); free(s))
printf("%s\n", s);
}

Segmentation fault when using fscanf in 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;
}

queue using struct that point to array

In C I try to learn queue data structure and make pointer to struct but inside the struct there is pointer to array. Here queue is struct, q is pointer to the struct, and inside struct there are rear, front, num and int *que(pointer to array to store data)
typedef struct {
int max;
int rear;
int front;
int num;
int *que;
} queue;
And malloc() using
queue->que=malloc(sizeof(int)12) ; to make arrray And to access it,
q->que[q->rear++] //not to familiar,
First I'm not declaring array but can I access data pointed by que using []?
Is this mean access que[q->rear++] inside q pointer?
Is this the same as (q).que[q->rear++]? I got segmentation fault .
Part of the code; but there are some errors
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int max;
int num;
int front;
int rear;
int *que;
} queue;
int initialization(queue*q, int max) {
q->num = 0;
q->front = 0;
q->rear = 0;
if (q->que =(int*)malloc(max * sizeof(int)) == NULL) { // got pointer NULL i dont know why
q->max = 0;
return-1;
}
q->max=max;
return 0;
}
int main() {
queue que;
if (initialization(&que, 12) == -1)
printf("fail");
else {
int m,x;
while (m != 0) {
printf("1.enque 2.deque. 3.peek 4.display 0. slese");
scanf("%d", &m);
switch (m) {
case 0: break;
case 1: printf("data");
scanf("%d", &x);
enqueue(&que, x);
break;
case 2: dequeue(&que, &x);
printf("%d is dequeue", x);
break;
case 3:x=peek(&que,&x);
printf("max now is %d", x);
break;
case 4:display(&que);
}
}
}
int enqueue(queue*q, int x) {
if (q->num >= q->max)
return -1;
else{
q->num++;
q->que[q->rear++]= x; //got segmentation fault
if (q->rear == q->max)
q->rear = 0;
}
}
In your initialization() function, while allocation memory with malloc() like
if (q->que =(int*)malloc(max * sizeof(int)) == NULL) {
the (int*)malloc(max * sizeof(int)) part is evaluated first and then this value is compared against NULL via the == operator. This will result in 0 if the condition is false and 1 otherwise.
Now this (0 or 1) value is being assigned to q->que instead of the return value of malloc(). So bottom-line is that q->que points to the memory location 0 (or 1 as the case maybe) which is most probably not a part of memory that a normal program is allowed to mess with and hence you get error.
You can solve this operator precedence problem by using parenthesis like
if ((q->que = malloc(max * sizeof(int))) == NULL) {
And in your while loop inside main(), the control expression is m!=0 but m is not even initialised during the first iteration. At that point, its value is indeterminate (garbage value).
You could initialise m to something other than 0 first like
int m=1,x;
while (m != 0) {
And in C, you needn't cast the value returned by malloc(). See here.

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.

Learning Pointers in C

I have been cutting my teeth for the past 48 hours or so trying to implement this hash table function in C. My code is rather long (I realize it is not the most efficient, some of it is more me playing around with C to get a feel for how it works etc).
The problem I am having is with the last line of my main program at the bottom (printing MyEntry->Name). I am receiving a bus error and am unsure why. I do not believe I am supposed to allocate memory in the main driver for this pointer but I could be wrong.
Sorry about the length of this code. BTW SymEntry is 'struct SymEntry{char *Name, void *Attributes, struct SymEntry *Next}
#include <strings.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>
#include "SymTab.h"
struct SymTab * CreateSymTab(int Size)
{
struct SymTab *symtable;
if(!(symtable=malloc(sizeof(struct SymTab)))) return NULL;
if(!(symtable->Contents=calloc(Size, sizeof(struct SymEntry*)))) {
free(symtable);
return NULL;
}
symtable->Size=Size;
return symtable;
}
/* hash form hash value for string s, taken from 'The C Programming Language'*/
unsigned hash(struct SymTab *ATable, const char *s)
{
unsigned hashval, size;
size = ATable->Size;;
for (hashval = 0; *s != '\0'; s++)
hashval = *s + 31 * hashval;
return hashval % size;
}
bool EnterName(struct SymTab *ATable,
const char *Name,
struct SymEntry **AnEntry)
{
struct SymEntry *ptr;
unsigned hashvalue;
char *string;
struct SymEntry *previous;
string = malloc(strlen(Name)+1);
AnEntry=(struct SymEntry**)malloc(sizeof(struct SymEntry*));
strcpy(string, Name);
printf("string is: is %s\n",string);
hashvalue = hash(ATable, string);
printf("hv is %d\n",hashvalue);
ptr = ATable->Contents[hashvalue];
previous = NULL;
while(ptr)
{
printf("WHILE LOOP\n");
if(!(strcmp(ptr->Name,string)))
{
printf("if(!strcmp(ptr->Name,string))\n");
*AnEntry = ptr;
return true;
}
previous = ptr;
ptr=ptr->Next;
}
if(previous)
{
printf("IF (PREVIOUS)\n");
if(!(ptr=malloc(sizeof(struct SymEntry)))) return false;
if(!(ptr->Name=string))
{
printf("if(!(ptr->Name=string))\n");
free(ptr);
return false;
}
ptr->Name = string;
previous->Next = ptr;
printf("Previous->Next: %s\n", previous->Next->Name);
*AnEntry = ptr;
return false;
}
else
{
printf("ELSE (PREVIOUS)\n");
if(!(ptr=malloc(sizeof(struct SymEntry)))) return false;
if(!(ptr->Name=string))
{
printf("if(!(ptr->Name=string))\n");
free(ptr);
return false;
}
ptr->Name = string;
ATable->Contents[hashvalue] = ptr;
printf("here\n");
*AnEntry = ptr;
printf("there\n");
return false;
}
}
struct SymEntry * FindName(struct SymTab *ATable, const char *Name)
{
struct SymEntry *Entry;
unsigned hashvalue;
hashvalue = hash(ATable, Name);
Entry = ATable->Contents[hashvalue];
while(Entry)
{
if(strcmp(Name,Entry->Name)==0)
{
return Entry;
}
}
return NULL;
}
main(int argc, char **argv)
{
struct SymTab *mysymtab;
struct SymEntry *myEntry;
mysymtab = CreateSymTab(1);
const char *string1 = "HELLO";
printf("%d\n",6);
EnterName(mysymtab, string1, &myEntry);
printf("first: %s\n", mysymtab->Contents[0]->Name);
EnterName(mysymtab, string1, NULL);
EnterName(mysymtab, "WORLD", NULL);
printf("second: %s\n", mysymtab->Contents[0]->Name);
printf("second->Next: %s\n", mysymtab->Contents[0]->Next->Name);
EnterName(mysymtab, "!##$%", &myEntry);
printf("third: %s\n", mysymtab->Contents[0]->Name);
printf("third->Next: %s\n", mysymtab->Contents[0]->Next->Name);
printf("third->Next->Next: %s\n", mysymtab->Contents[0]->Next->Next->Name);
printf("myEntry->Name: %s\n", myEntry->Name);
}
The problem is this line in EnterName:
AnEntry=(struct SymEntry**)malloc(sizeof(struct SymEntry*));
You need to remove that as you want AnEntry to point to the argument that the caller specified.
Because AnEntry may be NULL, you will also need to change every instance of:
*AnEntry = ptr;
to:
if (AnEntry)
*AnEntry = ptr;
What is happening is that when the function starts, AnEntry is pointing to the pointer the caller wants to change. When you change the value of AnEntry (i.e AnEntry = ...;), your code will not modify the pointer the caller want you to change but some internal pointer. Therefore, when EnterName returns, myEntry is still pointing to some random place in memory.
While you're at learning, there are some stylistic WTFs in your code. Take this part, for example.
if(!(ptr=malloc(sizeof(struct SymEntry)))) return false;
if(!(ptr->Name=string))
{
printf("if(!(ptr->Name=string))\n");
free(ptr);
return false;
}
ptr->Name = string;
It's inconsistent. You cast the return of malloc for AnEntry above, but not this malloc. Either do one or the other, but don't mix it. Better yet, write it in a way that doesn't "need" a cast at all.
You shouldn't assign values within if-statements. While it is still clear what you want to do in the malloc-case, the intention is obfuscated in the string assignment. Especially since it is superfluous. When the if evaluates to true, ptr is immediately freed. When it evaluates to false, the exact same assignment is done again. Additionally, in this case it prevents an obvious optimization.
Here is the same code rewritten:
if (string == NULL)
{
printf("string == NULL\n");
return false;
}
ptr = malloc(sizeof *ptr);
if (ptr == NULL)
{
return false;
}
ptr->Name = string;

Resources