i made a linked list and filled it with 4 "#" characters, i wanted to print them in screen with the ncurses library because i'm trying to make a snake game but idk why it doesn't print, here's the code:
#include<ncurses.h>
#include<stdlib.h>
struct snake{
char piece;
struct snake *nextPiece;
};
struct snake *addNewPiece(const char piece){
struct snake *newPiece = NULL;
newPiece = malloc(sizeof(struct snake));
if(newPiece != NULL){
newPiece->nextPiece = NULL;
newPiece->piece = piece;
}else{
endwin();
printf("mem aloc failure, the program couldn't alloc the memory correctly");
}
return newPiece;
}
int main(){
int i = 0;
struct snake *first = NULL;
struct snake *added = NULL;
initscr();
noecho();
int yMaxStd,xMaxStd;
getmaxyx(stdscr,yMaxStd,xMaxStd);
WINDOW* win = newwin(20,50,(yMaxStd/2)-10,10);
box(win,0,0);
refresh();
wrefresh(win);
leaveok(win, true);
int yMaxWin,xMaxWin;
getmaxyx(win,yMaxWin,xMaxWin);
wmove(win,yMaxWin/2,yMaxWin/2);
//llenar lista con 4 #
while(i<=4){
if(first == NULL){
first = addNewPiece("#");
if(first != NULL){
added = first;
}
}else{
added->nextPiece = addNewPiece("#");
if(added->nextPiece != NULL){
added = added->nextPiece;
}
}
}
if(first == NULL){
endwin();
printf("Men alloc failure.");
}
printinscreen(first,win);
getch();
endwin();
return 0;
}
void printinscreen(struct snake *piece,WINDOW* win){
struct snake *t;
t = piece;
int y = 5,x = 5;
if(t == NULL){
endwin();
}else{
while(t != NULL){
mvwprintw(win,y,x,t);
t = t->nextPiece;
y--;
}
}
}
i know that im making good the linking process of the linked list becuase i tested it printing it with stdio.h in another file and it worked
Your programs have several bugs, I have fixed them. The most serious is that your code cannot be compiled in C++. If it's intended to build it under C++, you need to fix the compile errors at first.
newPiece = malloc(sizeof(struct snake));, need a convertion here: newPiece = (snake *)malloc(sizeof(struct snake));, generally it's not recomended to use malloc in c++, it's more naturally to use new
first = addNewPiece("#"); Pass string literal as char argument, need to pass a character here.
mvwprintw(win, y, x, t);, you have misunderstand the API, should be fixed as mvwprintw(win, y, x, "%c", t->piece);, you need to see the document before use a library API to see what types of arguments it expects
You forget to refresh the screen after printing the screen!
You haven't increment the index in for loop, it's an infinite loop.
Your code is somewhat c style, if you are trying to write with C++, it needs to be refactored, some suggestions:
use std::vector to store the snake body, then we don't need to manage the memory by hand. And avoid the error-prone linked list processing. Then most part of your code can be simplified.
Use a logging library and print logs to help to debug
The fixed code should work, I get a vertical snake on my console.
#include <ncurses.h>
#include <stdlib.h>
struct snake {
char piece;
struct snake *nextPiece;
};
struct snake *addNewPiece(const char piece) {
struct snake *newPiece = NULL;
newPiece = (snake *)malloc(sizeof(struct snake));
if (newPiece != NULL) {
newPiece->nextPiece = NULL;
newPiece->piece = piece;
} else {
endwin();
printf("mem aloc failure, the program couldn't alloc the memory correctly");
}
return newPiece;
}
void printinscreen(struct snake *piece, WINDOW *win);
int main(int argc, char *argv[]) {
int i = 0;
struct snake *first = NULL;
struct snake *added = NULL;
initscr();
noecho();
int yMaxStd, xMaxStd;
getmaxyx(stdscr, yMaxStd, xMaxStd);
WINDOW *win = newwin(20, 50, (yMaxStd / 2) - 10, 10);
box(win, 0, 0);
refresh();
wrefresh(win);
leaveok(win, true);
int yMaxWin, xMaxWin;
getmaxyx(win, yMaxWin, xMaxWin);
wmove(win, yMaxWin / 2, yMaxWin / 2);
// llenar lista con 4 #
while (i <= 4) {
if (first == NULL) {
first = addNewPiece('#');
if (first != NULL) {
added = first;
}
} else {
added->nextPiece = addNewPiece('#');
if (added->nextPiece != NULL) {
added = added->nextPiece;
}
}
++i;
}
if (first == NULL) {
endwin();
printf("Men alloc failure.");
}
printinscreen(first, win);
refresh();
wrefresh(win);
getch();
endwin();
return 0;
}
void printinscreen(struct snake *piece, WINDOW *win) {
struct snake *t;
t = piece;
int y = 5, x = 5;
if (t == NULL) {
endwin();
} else {
while (t != NULL) {
mvwprintw(win, y, x, "%c", t->piece);
t = t->nextPiece;
y--;
}
}
}
After seeing the PO's comments, we know that the question have been falsely tagged with c++, the c version code:
#include <ncurses.h>
#include <stdlib.h>
struct snake {
char piece;
struct snake *nextPiece;
};
struct snake *addNewPiece(const char piece) {
struct snake *newPiece = NULL;
newPiece = malloc(sizeof(struct snake));
if (newPiece != NULL) {
newPiece->nextPiece = NULL;
newPiece->piece = piece;
} else {
endwin();
printf("mem aloc failure, the program couldn't alloc the memory correctly");
}
return newPiece;
}
void printinscreen(struct snake *piece, WINDOW *win);
int main(int argc, char *argv[]) {
int i = 0;
struct snake *first = NULL;
struct snake *added = NULL;
initscr();
noecho();
int yMaxStd, xMaxStd;
getmaxyx(stdscr, yMaxStd, xMaxStd);
WINDOW *win = newwin(20, 50, (yMaxStd / 2) - 10, 10);
box(win, 0, 0);
refresh();
wrefresh(win);
leaveok(win, true);
int yMaxWin, xMaxWin;
getmaxyx(win, yMaxWin, xMaxWin);
wmove(win, yMaxWin / 2, yMaxWin / 2);
// llenar lista con 4 #
while (i <= 4) {
if (first == NULL) {
first = addNewPiece('#');
if (first != NULL) {
added = first;
}
} else {
added->nextPiece = addNewPiece('#');
if (added->nextPiece != NULL) {
added = added->nextPiece;
}
}
++i;
}
if (first == NULL) {
endwin();
printf("Men alloc failure.");
}
printinscreen(first, win);
refresh();
wrefresh(win);
getch();
endwin();
return 0;
}
void printinscreen(struct snake *piece, WINDOW *win) {
struct snake *t;
t = piece;
int y = 5, x = 5;
if (t == NULL) {
endwin();
} else {
while (t != NULL) {
mvwprintw(win, y, x, "%c", t->piece);
t = t->nextPiece;
y--;
}
}
}
Related
I am attempting to solve a maze using BFS, but I am getting a segmentation fault. Can anyone help me figure out why this is happening? Also if you see anything else wrong with my code? my if statements are to check if the point exists in the maze and that there is a white space at the point. I also am solving the maze using DFS, but the seg fault happens during solve_bfs. Also, everything except solve.c was given to my professor, so the only thing I am suppose to edit is solve.c
Solve.c
#include <stdio.h>
#include <stdlib.h>
#include "maze.h"
#include "stack.h"
#include "queue.h"
int solve_bfs(maze * the_maze){
Queue Q= initQueue();
enqueue(Q, the_maze->entry);
while(!emptyQueue(Q)){
coord to_explore= dequeue(Q);
if(to_explore.row == the_maze->exit.row && to_explore.col == the_maze->exit.col){
print_maze(the_maze);
free(Q);
return 1;
}
else{
the_maze->data[to_explore.row][to_explore.col]= 'o';
if(to_explore.row-1 >= 0){
if(the_maze->data[to_explore.row-1][to_explore.col] == ' '){
coord new;
new.row= to_explore.row-1;
new.col= to_explore.col;
enqueue(Q, new);
}
}
if(to_explore.col+1 < the_maze->width){
if(the_maze->data[to_explore.row][to_explore.col+1]== ' '){
coord new;
new.row= to_explore.row;
new.col= to_explore.col+1;
enqueue(Q, new);
}
}
if(to_explore.row+1 < the_maze->height){
if(the_maze->data[to_explore.row+1][to_explore.col]== ' '){
coord new;
new.row= to_explore.row+1;
new.col= to_explore.col;
enqueue(Q, new);
}
}
if(to_explore.col-1 >= 0) {
if(the_maze->data[to_explore.row][to_explore.col-1]== ' '){
coord new;
new.row= to_explore.row;
new.col= to_explore.col-1;
enqueue(Q, new);
}
}
}
if(emptyQueue(Q)){
print_maze(the_maze);
free(Q);
return 0;
}
}
}
int solve_dfs(maze * the_maze){
Stack s= initStack();
push(s, the_maze->entry);
while(!emptyStack(s)){
coord to_explore= pop(s);
if(to_explore.row == the_maze->exit.row && to_explore.col == the_maze->exit.col){
print_maze(the_maze);
free(s);
return 1;
}
else{
if(to_explore.row-1 >= 0){
if(the_maze->data[to_explore.row-1][to_explore.col]== ' '){
coord new;
new.row= to_explore.row-1;
new.col= to_explore.col;
push(s, new);
}
}
if(to_explore.col+1 < the_maze->width){
if(the_maze->data[to_explore.row][to_explore.col+1]== ' '){
coord new;
new.row= to_explore.row;
new.col= to_explore.col+1;
push(s, new);
}
}
if(to_explore.row+1 < the_maze->height){
if(the_maze->data[to_explore.row+1][to_explore.col]== ' '){
coord new;
new.row= to_explore.row+1;
new.col= to_explore.col;
push(s, new);
}
}
if(to_explore.col-1 >= 0){
if(the_maze->data[to_explore.row][to_explore.col-1]== ' '){
coord new;
new.row= to_explore.row;
new.col= to_explore.col-1;
push(s, new);
}
}
}
if(emptyStack(s)){
print_maze(the_maze);
free(s);
return 0;
}
}
}
void print_maze(maze * the_maze){
the_maze->data[the_maze->entry.row][the_maze->entry.col]='S';
the_maze->data[the_maze->exit.row][the_maze->exit.col]='F';
for(int i=0; i<the_maze->width; i++){
for(int j=0; j<the_maze->height; j++){
printf("%s",the_maze->data[i][j]);
}
}
}
coord * make_coord(int r, int c){
coord * coord= malloc(sizeof(coord));
coord->row = r;
coord->col = c;
return coord;
}
void print_coord(coord c){
printf("(%d,%d)",c.row, c.col);
}
Maze.c
#include <stdio.h>
#include <stdlib.h>
#include "maze.h"
/**********************************************************
create_maze
creates a new maze from the input file characters
*********************************************************/
maze * create_maze(FILE *in) {
// create maze
maze * new_maze = (maze *) malloc(sizeof(maze));
// read first line of in
int start_row;
int start_col;
int end_row;
int end_col;
int num_rows;
int num_cols;
// start line
char * line = malloc(sizeof(char)*100); // start buffer out at 100
size_t num_read;
getline(&line, &num_read, in);
if(sscanf(line, "%d %d %d %d %d %d", &num_rows, &num_cols, &start_row, &start_col, &end_row, &end_col) != 6) {
fprintf(stderr, "Maze file format invalid. Top line must include 6 numbers.\n");
return NULL;
}
// if any are negative values, return NULL
if(start_row < 0 || start_col < 0 || end_row < 0 || end_col < 0 || num_rows < 0 || num_cols < 0) {
fprintf(stderr, "Maze file format invalid. Maze file numbers in first row must be non-negative.\n");
return NULL;
}
// make sure start_row is in bounds
if(start_row >= num_rows) {
fprintf(stderr, "Maze file format invalid. Start row must be < num rows in maze.\n");
return NULL;
}
// make sure end_row is in bounds
if(end_row >= num_rows) {
fprintf(stderr, "Maze file format invalid. End row must be < num rows in maze.\n");
return NULL;
}
// make sure start_col is in bounds
if(start_col >= num_cols) {
fprintf(stderr, "Maze file format invalid. Start col must be < num cols in maze.\n");
return NULL;
}
// make sure end_col is in bounds
if(end_col >= num_cols) {
fprintf(stderr, "Maze file format invalid. Start col must be < num cols in maze.\n");
return NULL;
}
// assign maze members
new_maze->entry.row = start_row;
new_maze->entry.col = start_col;
new_maze->exit.row = end_row;
new_maze->exit.col = end_col;
new_maze->width = num_cols;
new_maze->height = num_rows;
// allocate memory for maze data
new_maze->data = (char **) malloc(sizeof(char *)*num_rows);
int i;
for(i=0; i<num_rows; i++) {
new_maze->data[i] = (char *) malloc(sizeof(char)*num_cols);
}
// get characters from file, one line at a time
size_t num_vals_read = 0;
for(i=0; i<num_rows; i++) {
num_vals_read = getline(&line, &num_read, in);
if(num_vals_read != num_cols + 1) { //account for newline character
fprintf(stderr, "Maze file format invalid. Found %d chars on line %d and the width is %d.\n",
(num_vals_read-1), i, new_maze->width);
return NULL;
}
// parse out line
int j;
for(j=0; j<num_cols; j++) {
if(line[j] != ' ' && line[j] != '*') {
fprintf(stderr, "Maze file format invalid. Maze file data must contain spaces and stars. Read %c.\n", line[j]);
return NULL;
}
new_maze->data[i][j] = line[j];
}
}
// try to read more data
char c;
if((c = fgetc(in)) != EOF) {
fprintf(stderr, "Maze file format invalid. Too many characters past %d rows.\n", num_rows);
return NULL;
}
free(line);
return new_maze;
}
/******************************************************
free_maze
frees memory used by the_maze
******************************************************/
void free_maze(maze * the_maze) {
// first free the data
// need to free rows of data, then data
int i;
for(i = 0; i < the_maze->height; i++) {
free(the_maze->data[i]);
}
free(the_maze->data);
free(the_maze);
return;
}
Queue.c
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
/* initializes empty queue */
Queue initQueue() {
Queue q = malloc(sizeof(QueueType));
q->head = 0;
q->tail = 0;
return q;
}
/* returns 1 if queue is empty and 0 otherwise */
int emptyQueue(Queue Q) {
return (Q->head == Q->tail);
}
/* puts data item d into queue */
void enqueue(Queue Q, QueueData d) {
if(full(Q)) {
printf("Queue is full. Did not add item.\n");
return;
}
Q->tail++;
Q->tail = Q->tail % MAX_Q; // in case it goes off array
Q->data[Q->tail] = d;
}
/* removes data item from queue */
QueueData dequeue(Queue Q) {
if(emptyQueue(Q)) {
printf("Attempting to remove from empty queue\n");
exit(1);
}
Q->head++;
Q->head = Q->head % MAX_Q; // in case it goes off array
return Q->data[Q->head];
}
/* checks if queue is full */
int full(Queue Q) {
return (Q->tail + 1) % MAX_Q == Q->head;
}
/* freeQueue */
void freeQueue(Queue Q) {
free(Q);
}
Main.c
#include <stdio.h>
#include <stdlib.h>
#include "maze.h"
#define NUM_PARAMS 2
/* prototypes */
void usage(char * executable);
/***********************************************************************
* main
executable_name input_filename.txt
opens input_filename.txt for reading
creates maze object
runs the maze solver
frees maze
*********************************************************************/
// function completed for the CS 305 students: DO NOT MODIFY (Unless you find a bug)
int main(int argc, char * argv[]) {
if(argc != NUM_PARAMS) {
usage(argv[0]);
return EXIT_FAILURE;
}
// open file for reading
FILE *fp = NULL;
fp = fopen(argv[1], "r");
if(fp == NULL) {
fprintf(stderr, "Error opening input file %s. Exiting.\n", argv[1]);
return EXIT_FAILURE;
}
// create maze objects
// need 2 since we are running BFS on one (which modifies the
// maze with the path marker character)
// need clean copy of maze for DFS
maze * the_maze = create_maze(fp);
rewind(fp); // resets file pointer to beginning of file
maze * the_maze2 = create_maze(fp);
// done with file at this point
fclose(fp);
fp = NULL;
// check maze to see if it was created successfully
if(the_maze == NULL || the_maze2 == NULL) {
fprintf(stderr, "Error creating maze data structure\n");
return EXIT_FAILURE;
}
// run breadth-first-search on maze
printf("\nSolving using breadth-first search.\n");
int a = solve_bfs(the_maze);
// run depth-first-search on maze
printf("\nSolving using depth-first search:\n");
int b = solve_dfs(the_maze2);
printf("\ncan solve BFS: %d, can solve DFS: %d\n\n", a, b);
// free memory and exit
free_maze(the_maze);
free_maze(the_maze2);
return EXIT_SUCCESS;
}
/*********************************************************
usage
prints error message to user
**********************************************************/
void usage(char * executable) {
printf("Usage: \n%s maze_file.txt\n", executable);
}
stack.c
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
/* initializes a new stack */
Stack initStack() {
Stack s = (Stack) malloc(sizeof(StackType));
s->top = NULL;
return s;
}
/* empty returns 0 if S is empty and non-zero if S is not empty */
int emptyStack(Stack S) {
return (S->top == NULL);
}
/* pushes d to S */
void push(Stack S, StackData d) {
Node * n = (Node *)malloc(sizeof(Node));
n->data = d;
n->next = S->top;
S->top = n;
}
/* pops top item from S */
StackData pop(Stack S) {
if(emptyStack(S)) {
printf("Stack is empty. Attempting to pop an empty stack. Exiting program.\n");
exit(1); // exiting program
}
// there is data to pop
StackData toReturn = S->top->data;
Node * tmp = S->top; // in order to free this later
S->top = S->top->next; // move pointer to next item in stack
free(tmp);
return toReturn;
}
/* frees stack memory */
void freeStack(Stack S) {
while(!emptyStack(S)) {
pop(S);
}
free(S);
}
queue.h
#ifndef QUEUE_H
#define QUEUE_H
#include "maze.h"
#define MAX_Q 5000 // 1 more than what can be stored in the queue
// in this application, the mazes are on the small
// side
/* data to store into queue */
typedef coord QueueData; // putting coordinates into queue
/* queue data structure */
typedef struct QueueTag QueueType;
typedef struct QueueTag* Queue; // pointer to queue struct
// so when it is passed, the values
// can be updated in functions
struct QueueTag {
int head;
int tail;
QueueData data[MAX_Q]; // space for items in queue
};
/* function prototypes on queues */
Queue initQueue();
int emptyQueue(Queue Q);
void enqueue(Queue Q, QueueData d);
QueueData dequeue(Queue Q);
int full(Queue Q);
void freeQueue();
#endif
maze.h
#ifndef MAZE_H
#define MAZE_H
/* struct definition for coord */
typedef struct coord {
int row;
int col;
} coord;
/* struct definition for maze */
typedef struct maze {
coord entry;
coord exit;
int width;
int height;
char ** data;
} maze;
/* prototypes */
/* in maze.c */
maze * create_maze(FILE *in);
void free_maze(maze * the_maze);
/* in solve.c */
int solve_bfs(maze * the_maze);
int solve_dfs(maze * the_maze);
void print_maze(maze * the_maze);
coord * make_coord(int r, int c);
void print_coord(coord c);
#endif
stack.h
#ifndef STACK_H
#define STACK_H
#include "maze.h"
#define BAD {-1, -1} // coordinate off maze
/* data to store into stack */
typedef coord StackData;
/* stack data structures */
typedef struct NodeTag Node;
typedef struct StackTag StackType;
typedef struct StackTag* Stack;
/* linked list implementation of stacks */
struct NodeTag {
StackData data;
Node *next;
};
struct StackTag {
Node * top;
};
/* function prototypes on stacks */
Stack initStack();
int emptyStack(Stack S);
void push(Stack S, StackData d);
StackData pop(Stack S);
void freeStack(Stack S);
#endif
you need to fix your bound checking, assuming zero based indexing
# incorrect
to_explore.col+1 =< the_maze->width
# correct
to_explore.col+1 < the_maze->width
similar is the case for checking of to_explore.rowemphasized text
The error is in print_maze function.
void print_maze(maze * the_maze){
the_maze->data[the_maze->entry.row][the_maze->entry.col]='S';
the_maze->data[the_maze->exit.row][the_maze->exit.col]='F';
for(int i=0; i<the_maze->width; i++){
for(int j=0; j<the_maze->height; j++){
printf("%s",the_maze->data[i][j]);
}
}
data[i] represents ith row, so i should iterate over height.
data[i][j] represents jth element in ith row, so j should iterate over width. You need to swap height and width in the for loop.
void print_maze(maze * the_maze){
the_maze->data[the_maze->entry.row][the_maze->entry.col]='S';
the_maze->data[the_maze->exit.row][the_maze->exit.col]='F';
for(int i=0; i<the_maze->height; i++){
for(int j=0; j<the_maze->width; j++){
printf("%s",the_maze->data[i][j]);
}
}
}
I just found this code online, and do not understand how the input should be formatted. An example of similar input from the same programmer is shown here: Pushdown automaton implemented in C
But it still does not help that much. Here is what it says:
The input format is like:
e01:e0$:000111:a:ad:aeeb$:b0eb0:b10ce:c10ce:ce$de The input is
separated by a semicolon “:”, first section is “input alphabet”,
second is “stack alphabet”, then “input” and the last whole bunch are
transition functions.
Can anyone provide some guidance how the input is handled? I am trying really hard for about 6 hours now, and cannot for the life of me decipher how the input should be formatted for this code.
Once it is compiled with gcc, to run it just do "./executable" and press enter. Then paste in the sample input string as shown above (although for this program I would need a different input).
/* This C file implements a Turing Machine
* author: Kevin Zhou
* Computer Science and Electronics
* University of Bristol
* Date: 21st April 2010
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct tapes {
struct tapes *left;
struct tapes *right;
char content;
} Tape;
typedef enum { LEFT,RIGHT } Direction;
typedef struct transition {
char current_state;
char tape_symbol;
char new_state;
char new_tape_symbol;
Direction dir;
} Transition;
typedef struct list {
Transition *content;
struct list *next;
} List;
typedef struct tm {
char *input_alpha;
char *input;
char *tape_alpha;
char start;
char accept;
char reject;
List *transition;
} TM;
Tape *insert_tape(Tape *t, Direction dir, char c) {
Tape *head = t;
Tape *new1 = calloc(1,sizeof(Tape));;
new1 -> content = c;
if(dir == LEFT) {
while(t->left != NULL) {
t = t->left;
}
new1->right = t;
new1->left = NULL;
t->left = new1;
return new1;
}
if(dir == RIGHT) {
while(t->right != NULL) {
t = t->right;
}
new1->left = t;
new1->right = NULL;
t->right = new1;
}
return head;
}
Tape *create_tape(char *input) {
int i=1;
Tape *t = calloc(1,sizeof(Tape));
t->content = input[0];
while(1) {
if(input[i] == '\0') break;
t = insert_tape(t,RIGHT,input[i]);
i++;
}
return t;
}
/* turn the input string into Transition fields */
Transition *get_transition(char *s) {
Transition *t = calloc(1,sizeof(Transition));
Direction dir;
t->current_state = s[0];
t->tape_symbol = s[1];
t->new_state = s[2];
t->new_tape_symbol = s[3];
dir = (s[4]=='R')? RIGHT:LEFT;
t->dir = dir;
return t;
}
/* turn the string into transitions and add into list */
List *insert_list( List *l, char *elem ) {
List *t = calloc(1,sizeof(List));
List *head = l;
while(l->next!=NULL)
l = l->next;
t->content = get_transition(elem);
t->next = NULL;
l->next = t;
return head;
}
/* insert a transition into a list */
List *insert_list_transition( List *l, Transition *tr) {
List *t = calloc(1,sizeof(List));
List *head = l;
while(l->next!=NULL)
l = l->next;
t->content = tr;
t->next = NULL;
l->next = t;
return head;
}
void print_tape( Tape *t,char blank) {
char c;
while(1) {
if(t->content != blank) break;
t= t->right;
}
while(1) {
if(t==NULL) break;
c = t->content;
if(t->content != blank)
putchar(c);
t= t->right;
}
putchar('\n');
}
void print_transition (Transition *t) {
char s1[] = "Left";
char s2[] = "Right";
if(t==NULL) {
printf("NULL Transfer");
return;
}
printf("current:%c tape:%c new state:%c new tape:%c direction %s\n",t->current_state,t->tape_symbol,t->new_state,t->new_tape_symbol,(t->dir == LEFT)?s1:s2);
}
/*test if the char c is in the string s */
int contains ( char c, char *s ) {
int i=0;
while(1) {
if(c== s[i]) return 1;
if(s[i] == '\0') return 0;
i++;
}
}
/* test if the input is a valid input */
int is_valid_input( char *input_alpha, char *input ) {
int i=0;
char c;
while(1) {
c = input[i];
if(c == '\0') break;
if(!contains(c,input_alpha)) return 0;
i++;
}
return 1;
}
TM *createTM (char *input) {
TM *m = calloc(1,sizeof(TM));
List *tr = calloc(1,sizeof(List));
char *buffer;
/*read input alphabet of PDA*/
buffer = strtok(input,":");
if(buffer == NULL) {
printf("Error in reading input alphabet!\n");
exit(1);
}
m->input_alpha = buffer;
/*read tape alphabet*/
buffer = strtok(NULL,":");
if(buffer == NULL) {
printf("Error in reading tape alphabet!\n");
exit(1);
}
m->tape_alpha = buffer;
/*read input sequence*/
buffer = strtok(NULL,":");
if(buffer == NULL) {
printf("Error in reading input sequence!\n");
exit(1);
}
if(!is_valid_input(m->input_alpha,buffer)) {
printf("Error! Input contains some invalid characters that don't match the input alphabet!\n");
exit(1);
}
m->input = buffer;
buffer = strtok(NULL,":");
m->start = buffer[0];
buffer = strtok(NULL,":");
m->accept = buffer[0];
buffer = strtok(NULL,":");
m->reject = buffer[0];
/*read tape transition*/
while(1) {
buffer = strtok(NULL,":");
if(buffer == NULL) break;
tr = insert_list(tr,buffer);
}
m->transition = tr->next;
return m;
}
Transition *find_transition(List * list,char state, char tape_symbol) {
Transition *t;
while(1) {
if(list==NULL) return NULL;
t = list -> content;
if(t->current_state == state && t->tape_symbol == tape_symbol)
return t;
list = list->next;
}
}
Tape *move(Tape *t,Direction dir, char blank) {
if(dir == LEFT) {
if(t->left==NULL) {
t = insert_tape(t,LEFT,blank);
}
return t->left;
}
if(dir == RIGHT) {
if(t->right==NULL) {
t = insert_tape(t,RIGHT,blank);
}
return t->right;
}
return NULL;
}
void simulate( TM *m ) {
/* first symbol in input symbol used to represent the blank symbol */
const char blank = m->tape_alpha[0];
char current_state = m->start;
Tape *tape = create_tape(m->input);
Tape *current_tape = tape;
char current_tape_symbol;
Transition *current_transition;
while(1) {
if(current_state == m->accept) {
printf("Accept\n");
print_tape(tape,blank);
break;
}
if(current_state == m->reject) {
printf("Reject\n");
print_tape(tape,blank);
break;
}
current_tape_symbol = (current_tape==NULL||current_tape ->content == '\0')?blank:current_tape->content;
current_transition = find_transition(m->transition,current_state,current_tape_symbol);
current_state = current_transition -> new_state;
current_tape -> content = current_transition -> new_tape_symbol;
current_tape = move( current_tape, current_transition ->dir, blank);
}
}
int main(void) {
char s[300];
TM *p;
scanf("%s",s);
p = createTM(s);
simulate(p);
return 0;
}
The heavy use of the line buffer = strtok(NULL,":") confirms that the input strings are (like in the linked-to code) colon-delimited.
The struct defintions are the key to reverse-engineering the input.
The main struct is:
typedef struct tm {
char *input_alpha;
char *input;
char *tape_alpha;
char start;
char accept;
char reject;
List *transition;
} TM;
The function createTM() is the function which splits the input on : and loads the Turing machine. struct tm has 7 fields and createTM() has 7 clear phases
1) The first part is the input alphabet. Presumably this would be a string of 1 or more characters, e.g. 01.
2) The second part is the tape is the tape alphabet. The only character in this which plays any role in the rest of the code is the first character. The line const char blank = m->tape_alpha[0]; in the main simulation function indicates that the first character plays the role of the blank character -- the character which indicates that a tape square is empty. The ability to write the blank to a square allows the Turing machine to erase the data in a square. Note that in some sense this part of the input is out of order -- it is listed as the third field in the struct definition but is the second field in the input string.
3) The thirs part is the initial input on the tape. It is a string all of whose characters are drawn from the first part. The function is_valid_input() is used to check this condition.
4) The next part is the start state, which consists of a single char
5) The next part is the accept state, which is again a single char. Thus, in this model of a TM there is a single accepting state
6) The next part is the rejecting state, which is again represented by a single char
7) What follows is a sequence of strings, fed into a linked list of strings. The key function in understanding how it works is get_transition() which takes one of these transition strings and converts it into a Transition struct, declared as:
typedef struct transition {
char current_state;
char tape_symbol;
char new_state;
char new_tape_symbol;
Direction dir;
} Transition;
Looking carefully at the function get_transition() you can infer that a transition is represented by a string of length 5 where the last char is either R or L. An example would be something like a1b0R which says something like "if you are in state a while scanning symbol 0, transition to state b, write symbol 1 and the move to the right".
Putting it all together, the form of an input string would be something like:
01:_102:1001010101:$:a:r:$0b1R:b1b0L:a1b2R
corresponding to
01 _102 1001010101 $ a r $0b1R b1b0L a1b2R
input tape input start accept reject transitions
| alphabets | | states |
(blank = '_')
I just made some transitions at random, and neither know nor care what the program would do with this input. This should be enough for you to start experimenting with the program.
I'm a noob at C and create this program to help me learn. Purpose is to add soccer players to a team and print info.
I'm trying to print fields of my club structure but when my program gets to my print method, all my values are garbage or addresses. How can I get "real" values
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 8
typedef struct player {
int id;
char *position;
} Player;
typedef struct club {
int size;
Player *team[SIZE];
} Club;
Player *create_player(int id, const char *description);
void create_team(Club *club);
void print_club(const Club *club);
void add_player_to_club(Club *club, int id, const char *position);
int main() {
Club club;
create_team(&club);
add_player_to_club(&club, 1, "forward");
add_player_to_club(&club, 2, "goalie");
print_club(&club);
return 0;
}
Player *create_player(int id, const char *description){
Player *player;
player = malloc(sizeof(Player));
if(description == NULL){
player->position = NULL;
} else {
player->position = malloc(strlen(description) + 1);
strcpy(player->position, description);
player->id = id;
}
return player;
}
void create_team(Club *team){
team = malloc(sizeof(Club));
if (team == NULL) {
return;
} else {
team->size = 0;
}
}
void print_club(const Club *club) {
int i = 0;
if (club == NULL) {
return;
} else if (club->size == 0) {
printf("No team members\n");
} else {
for (i = 0; i < SIZE; i++) {
printf("Id: %d Position: %s\n", club->team[i]->id,
club->team[i]->position);
}
}
}
void add_player_to_club(Club *club, int id, const char *position){
if (club == NULL || club->size >= SIZE) {
return;
} else {
Player player = *create_player(id, position);
club->team[club->size -1] = &player;
}
}
Here's a pic of my debugging session
Debugger
Problem 1
create_team is not doing anything useful for main. You are changing the value of a function local variable. As a consequence club remains uninitialized in main. You proceed to use it as though it is valid object, which is cause for undefined behavior.
You can change that function to:
void create_team(Club *team){
team->size = 0;
for (int i = 0; i < SIZE; ++i )
{
team->team[i] = NULL; // Unfortunate choice of variable names
// but should be OK.
}
}
Problem 2
You are storing a pointer to a function local variable in add_player_to_club. That pointer becomes invalid the function returns.
Player player = *create_player(id, position);
club->team[club->size -1] = &player; // Problem
Change it to:
club->team[club->size] = create_player(id, position);
club->size++;
Problem 3
You are printing too may Players in print_club. There aren't always SIZE number of Players in the team. Change the line
for (i = 0; i < SIZE; i++) {
to
for (i = 0; i < club->size; i++) {
I am trying to implement a generic hash structure that can support any type of data and any hash function.
A wrote the code and try to run it, it dosn't work, it breaks. I try to debug it and there it works well. I don't know where the problem is?
Here is the code that I used for implementing the structure:
The "hash.h" file:
typedef struct tip_hash_nod
{
void *info;
struct tip_hash_nod *urm;
}NOD_LISTA_HASH;
typedef struct
{
NOD_LISTA_HASH *Table;
int size;
int sizeMemory;
int (*hash)(const void *obiect,const int m);
void (*distruge)(void *obiect);
}*HASH;
void initializare_hash(HASH *h,int size,int (*hash_dat)(const void *obiect,const int m),void (*distruge)(void *obiect));
int hash_insert(HASH *h,void *obiect,int sizeOfObiect);
int hash_search(HASH h,void *obiect,int (*compara)(const void *a,const void *b));
void hash_delete(HASH *h);
And the "hash.c" file:
void initializare_hash(HASH *h,int size,int (*hash_dat)(const void *obiect,const int m),void (*distruge)(void *obiect))
{
int i;
(*h) = (HASH)malloc(sizeof(HASH));
(*h)->sizeMemory = size;
if(size != 0)
{
(*h)->Table = (NOD_LISTA_HASH *)malloc((*h)->sizeMemory * sizeof(NOD_LISTA_HASH));
for(i=0;i<(*h)->sizeMemory;i++)
{
(*h)->Table[i].info = NULL;
(*h)->Table[0].urm = NULL;
}
}
else
{
(*h)->Table = (NOD_LISTA_HASH *)malloc(sizeof(NOD_LISTA_HASH));
(*h)->Table[0].info = NULL;
(*h)->Table[0].urm = NULL;
(*h)->sizeMemory = 1;
}
(*h)->size = 0;
(*h)->hash = hash_dat;
(*h)->distruge = distruge;
}
int hash_insert(HASH *h,void *obiect,int sizeOfObiect)
{
int i,poz;
NOD_LISTA_HASH *p;
if((*h)->size == (*h)->sizeMemory)
{
HASH h1;
initializare_hash(&h1,2*(*h)->sizeMemory,(*h)->hash,(*h)->distruge);
for(i=0;i<(*h)->sizeMemory;i++)
{
if((*h)->Table[i].info != NULL)
hash_insert(&h1,(*h)->Table[i].info,sizeOfObiect);
p=(*h)->Table[i].urm;
while(p!=NULL)
{
hash_insert(&h1,p->info,sizeOfObiect);
p = p->urm;
}
}
hash_delete(h);
*h=h1;
return hash_insert(h,obiect,sizeOfObiect);
}
else
{
poz = (*h)->hash(obiect,(*h)->sizeMemory);
if((*h)->Table[poz].info == NULL)
{
(*h)->Table[poz].info = malloc(sizeOfObiect);
memcpy((*h)->Table[poz].info,obiect,sizeOfObiect);
(*h)->Table[poz].urm = NULL;
(*h)->size++;
}
else
{
p = &((*h)->Table[poz]);
while(p->urm!=NULL)
p = p->urm;
p->urm = (NOD_LISTA_HASH *)malloc(sizeof(NOD_LISTA_HASH));
p = p->urm;
p->info = malloc(sizeOfObiect);
memcpy(p->info,obiect,sizeOfObiect);
p->urm = NULL;
}
return poz;
}
}
int hash_search(HASH h,void *obiect,int (*compara)(const void *a,const void *b))
{
int poz;
NOD_LISTA_HASH *p;
poz = h->hash(obiect,h->sizeMemory);
if(h->Table[poz].info == NULL)
return -1;
else
if(compara(h->Table[poz].info,obiect)==0)
return poz;
else
{
p=h->Table[poz].urm;
while(p != NULL)
{
if(compara(p->info,obiect)==0)
return poz;
p = p->urm;
}
return -1;
}
}
static void distruge_lista(NOD_LISTA_HASH *p,void (*distruge_obiect)(void *obiect))
{
if(p->urm != NULL)
distruge_lista(p->urm,distruge_obiect);
else
{
if(p->info != NULL)
distruge_obiect(p->info);
free(p);
}
}
void hash_delete(HASH *h)
{
int i;
for(i=0;i<(*h)->sizeMemory;i++)
{
if((*h)->Table[i].info != NULL && (*h)->Table[i].urm != NULL)
{
distruge_lista((*h)->Table[i].urm,(*h)->distruge);
}
}
free((*h)->Table);
*h = NULL;
}
And this is my "main.c" file:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include "hash.h"
int comparare(const void *a,const void *b)
{
return (*(int *)a - *(int *)b);
}
int hash(const void *obiect,int m)
{
return (*(int *)obiect) % m;
}
void distruge_obiect(void *obiect)
{
free((int *)obiect);
}
int main()
{
HASH h;
int val,error;
initializare_hash(&h,0,hash,distruge_obiect);
val = 20;
hash_insert(&h,&val,sizeof(int));
val = 800;
hash_insert(&h,&val,sizeof(int));
val = 2000;
hash_insert(&h,&val,sizeof(int));
val = 765;
hash_insert(&h,&val,sizeof(int));
val = 800;
error = hash_search(h,&val,comparare);
if(error == -1)
printf("Elementul %d nu se afla in hash.\n",val);
else
printf("Elementul %d se afla pe pozitia: %d.\n",val,error);
hash_delete(&h);
getch();
return 0;
}
How I already sad if I try to debug it works with no problem, but when I run it, it crashes. I can onely make an assumption that it can not dealocate the memory or something. My call stack loocks like this:
You've dropped a pretty big pile of code on us, without much to go on. I had a quick look anyway, and noticed this incorrect allocation:
(*h) = (HASH)malloc(sizeof(HASH));
HASH is a pointer type, so you are allocating only enough memory for one pointer. You want to allocate memory for the thing to which it points:
*h = malloc(sizeof(**h));
(The cast is not required in C, and some folks around here will be strident about not using one.)
That error would be entirely enough to cause all manner of bad behavior. In particular, the erroneous code might seem to work until you dynamically allocate more memory and write to that, so perhaps that explains why your tests crash on the second insertion.
Edit:
Hash.c is updated with revisions from the comments, I am still getting a Seg fault. I must be missing something here that you guys are saying
I have created a hash table ADT using C but I am encountering a segmentation fault when I try to call a function (find_hash) in the ADT.
I have posted all 3 files that I created parse.c, hash.c, and hash.h, so you can see all of the variables. We are reading from the file gettysburg.txt which is also attached
The seg fault is occuring in parse.c when I call find_hash. I cannot figure out for the life of me what is going on here. If you need anymore information I can surely provide it.
sorry for the long amount of code I have just been completely stumped for a week now on this. Thanks in advance
The way I run the program is first:
gcc -o parse parse.c hash.c
then: cat gettysburg.txt | parse
Parse.c
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "hash.h"
#define WORD_SIZE 40
#define DICTIONARY_SIZE 1000
#define TRUE 1
#define FALSE 0
void lower_case_word(char *);
void dump_dictionary(Phash_table );
/*Hash and compare functions*/
int hash_func(char *);
int cmp_func(void *, void *);
typedef struct user_data_ {
char word[WORD_SIZE];
int freq_counter;
} user_data, *Puser_data;
int main(void)
{
char c, word1[WORD_SIZE];
int char_index = 0, dictionary_size = 0, num_words = 0, i;
int total=0, largest=0;
float average = 0.0;
Phash_table t; //Pointer to main hash_table
int (*Phash_func)(char *)=NULL; //Function Pointers
int (*Pcmp_func)(void *, void *)=NULL;
Puser_data data_node; //pointer to hash table above
user_data * find;
printf("Parsing input ...\n");
Phash_func = hash_func; //Assigning Function pointers
Pcmp_func = cmp_func;
t = new_hash(1000,Phash_func,Pcmp_func);
// Read in characters until end is reached
while ((c = getchar()) != EOF) {
if ((c == ' ') || (c == ',') || (c == '.') || (c == '!') || (c == '"') ||
(c == ':') || (c == '\n')) {
// End of a word
if (char_index) {
// Word is not empty
word1[char_index] = '\0';
lower_case_word(word1);
data_node = (Puser_data)malloc(sizeof(user_data));
strcpy(data_node->word,word1);
printf("%s\n", data_node->word);
//!!!!!!SEG FAULT HERE!!!!!!
if (!((user_data *)find_hash(t, data_node->word))){ //SEG FAULT!!!!
insert_hash(t,word1,(void *)data_node);
}
char_index = 0;
num_words++;
}
} else {
// Continue assembling word
word1[char_index++] = c;
}
}
printf("There were %d words; %d unique words.\n", num_words,
dictionary_size);
dump_dictionary(t); //???
}
void lower_case_word(char *w){
int i = 0;
while (w[i] != '\0') {
w[i] = tolower(w[i]);
i++;
}
}
void dump_dictionary(Phash_table t){ //???
int i;
user_data *cur, *cur2;
stat_hash(t, &(t->total), &(t->largest), &(t->average)); //Call to stat hash
printf("Number of unique words: %d\n", t->total);
printf("Largest Bucket: %d\n", t->largest);
printf("Average Bucket: %f\n", t->average);
cur = start_hash_walk(t);
printf("%s: %d\n", cur->word, cur->freq_counter);
for (i = 0; i < t->total; i++)
cur2 = next_hash_walk(t);
printf("%s: %d\n", cur2->word, cur2->freq_counter);
}
int hash_func(char *string){
int i, sum=0, temp, index;
for(i=0; i < strlen(string);i++){
sum += (int)string[i];
}
index = sum % 1000;
return (index);
}
/*array1 and array2 point to the user defined data struct defined above*/
int cmp_func(void *array1, void *array2){
user_data *cur1= array1;
user_data *cur2= array2;//(user_data *)array2;
if(cur1->freq_counter < cur2->freq_counter){
return(-1);}
else{ if(cur1->freq_counter > cur2->freq_counter){
return(1);}
else return(0);}
}
hash.c
#include "hash.h"
Phash_table new_hash (int size, int(*hash_func)(char*), int(*cmp_func)(void*, void*)){
int i;
Phash_table t;
t = (Phash_table)malloc(sizeof(hash_table)); //creates the main hash table
t->buckets = (hash_entry **)malloc(sizeof(hash_entry *)*size); //creates the hash table of "size" buckets
t->size = size; //Holds the number of buckets
t->hash_func = hash_func; //assigning the pointer to the function in the user's program
t->cmp_func = cmp_func; // " "
t->total=0;
t->largest=0;
t->average=0;
t->sorted_array = NULL;
t->index=0;
t->sort_num=0;
for(i=0;i<size;i++){ //Sets all buckets in hash table to NULL
t->buckets[i] = NULL;}
return(t);
}
void free_hash(Phash_table table){
int i;
hash_entry *cur;
for(i = 0; i<(table->size);i++){
if(table->buckets[i] != NULL){
for(cur=table->buckets[i]; cur->next != NULL; cur=cur->next){
free(cur->key); //Freeing memory for key and data
free(cur->data);
}
free(table->buckets[i]); //free the whole bucket
}}
free(table->sorted_array);
free(table);
}
void insert_hash(Phash_table table, char *key, void *data){
Phash_entry new_node; //pointer to a new node of type hash_entry
int index;
new_node = (Phash_entry)malloc(sizeof(hash_entry));
new_node->key = (char *)malloc(sizeof(char)*(strlen(key)+1)); //creates the key array based on the length of the string-based key
new_node->data = data; //stores the user's data into the node
strcpy(new_node->key,key); //copies the key into the node
//calling the hash function in the user's program
index = table->hash_func(key); //index will hold the hash table value for where the new node will be placed
table->buckets[index] = new_node; //Assigns the pointer at the index value to the new node
table->total++; //increment the total (total # of buckets)
}
void *find_hash(Phash_table table, char *key){
int i;
hash_entry *cur;
printf("Inside find_hash\n"); //REMOVE
for(i = 0;i<table->size;i++){
if(table->buckets[i]!=NULL){
for(cur = table->buckets[i]; cur->next != NULL; cur = cur->next){
if(strcmp(table->buckets[i]->key, key) == 0)
return((table->buckets[i]->data));} //returns the data to the user if the key values match
} //otherwise return NULL, if no match was found.
}
return NULL;
}
void stat_hash(Phash_table table, int *total, int *largest, float *average){
int node_num[table->size]; //creates an array, same size as table->size(# of buckets)
int i,j, count = 0;
int largest_buck = 0;
hash_entry *cur;
for(i = 0; i < table->size; i ++){
if(table->buckets[i] != NULL){
for(cur=table->buckets[i]; cur->next!=NULL; cur = cur->next){
count ++;}
node_num[i] = count;
count = 0;}
}
for(j = 0; j < table->size; j ++){
if(node_num[j] > largest_buck)
largest_buck = node_num[j];}
*total = table->total;
*largest = largest_buck;
*average = (table->total) / (table->size);
}
void *start_hash_walk(Phash_table table){
Phash_table temp = table;
int i, j, k;
hash_entry *cur; //CHANGE IF NEEDED to HASH_TABLE *
if(table->sorted_array != NULL) free(table->sorted_array);
table->sorted_array = (void**)malloc(sizeof(void*)*(table->total));
for(i = 0; i < table->total; i++){
if(table->buckets[i]!=NULL){
for(cur=table->buckets[i]; cur->next != NULL; cur=cur->next){
table->sorted_array[i] = table->buckets[i]->data;
}}
}
for(j = (table->total) - 1; j > 0; j --) {
for(k = 1; k <= j; k ++){
if(table->cmp_func(table->sorted_array[k-1], table->sorted_array[k]) == 1){
temp -> buckets[0]-> data = table->sorted_array[k-1];
table->sorted_array[k-1] = table->sorted_array[k];
table->sorted_array[k] = temp->buckets[0] -> data;
}
}
}
return table->sorted_array[table->sort_num];
}
void *next_hash_walk(Phash_table table){
table->sort_num ++;
return table->sorted_array[table->sort_num];
}
hash.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct hash_entry_ { //Linked List
void *data; //Generic pointer
char *key; //String-based key value
struct hash_entry_ *next; //Self-Referencing pointer
} hash_entry, *Phash_entry;
typedef struct hash_table_ {
hash_entry **buckets; //Pointer to a pointer to a Linked List of type hash_entry
int (*hash_func)(char *);
int (*cmp_func)(void *, void *);
int size;
void **sorted_array; //Array used to sort each hash entry
int index;
int total;
int largest;
float average;
int sort_num;
} hash_table, *Phash_table;
Phash_table new_hash(int size, int (*hash_func)(char *), int (*cmp_func)(void *, void *));
void free_hash(Phash_table table);
void insert_hash(Phash_table table, char *key, void *data);
void *find_hash(Phash_table table, char *key);
void stat_hash(Phash_table table, int *total, int *largest, float *average);
void *start_hash_walk(Phash_table table);
void *next_hash_walk(Phash_table table);
Gettysburg.txt
Four score and seven years ago, our fathers brought forth upon this continent a new nation: conceived in liberty, and dedicated to the proposition that all men are created equal.
Now we are engaged in a great civil war. . .testing whether that nation, or any nation so conceived and so dedicated. . . can long endure. We are met on a great battlefield of that war.
We have come to dedicate a portion of that field as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.
But, in a larger sense, we cannot dedicate. . .we cannot consecrate. . . we cannot hallow this ground. The brave men, living and dead, who struggled here have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember, what we say here, but it can never forget what they did here.
It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us. . .that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion. . . that we here highly resolve that these dead shall not have died in vain. . . that this nation, under God, shall have a new birth of freedom. . . and that government of the people. . .by the people. . .for the people. . . shall not perish from the earth.
It's possible that one of several problems with this code are loops like:
for(table->buckets[i];
table->buckets[i]->next != NULL;
table->buckets[i] = table->buckets[i]->next)
...
The initializing part of the for loop (table->buckets[i]) has no effect. If i is 0 and table->buckets[0] == NULL, then the condition on this loop (table->buckets[i]->next != NULL) will dereference a null pointer and crash.
That's where your code seemed to be crashing for on my box, at least. When I changed several of your loops to:
if (table->buckets[i] != NULL) {
for(;
table->buckets[i]->next != NULL;
table->buckets[i] = table->buckets[i]->next)
...
}
...it kept crashing, but in a different place. Maybe that will help get you unstuck?
Edit: another potential problem is that those for loops are destructive. When you call find_hash, do you really want all of those buckets to be modified?
I'd suggest using something like:
hash_entry *cur;
// ...
if (table->buckets[i] != NULL) {
for (cur = table->buckets[i]; cur->next != NULL; cur = cur->next) {
// ...
}
}
When I do that and comment out your dump_dictionary function, your code runs without crashing.
Hmm,
here's hash.c
#include "hash.h"
Phash_table new_hash (int size, int(*hash_func)(char*), int(*cmp_func)(void*, void*)){
int i;
Phash_table t;
t = (Phash_table)calloc(1, sizeof(hash_table)); //creates the main hash table
t->buckets = (hash_entry **)calloc(size, sizeof(hash_entry *)); //creates the hash table of "size" buckets
t->size = size; //Holds the number of buckets
t->hash_func = hash_func; //assigning the pointer to the function in the user's program
t->cmp_func = cmp_func; // " "
t->total=0;
t->largest=0;
t->average=0;
for(i=0;t->buckets[i] != NULL;i++){ //Sets all buckets in hash table to NULL
t->buckets[i] = NULL;}
return(t);
}
void free_hash(Phash_table table){
int i;
for(i = 0; i<(table->size);i++){
if(table->buckets[i]!=NULL)
for(table->buckets[i]; table->buckets[i]->next != NULL; table->buckets[i] = table->buckets[i]->next){
free(table->buckets[i]->key); //Freeing memory for key and data
free(table->buckets[i]->data);
}
free(table->buckets[i]); //free the whole bucket
}
free(table->sorted_array);
free(table);
}
void insert_hash(Phash_table table, char *key, void *data){
Phash_entry new_node; //pointer to a new node of type hash_entry
int index;
new_node = (Phash_entry)calloc(1,sizeof(hash_entry));
new_node->key = (char *)malloc(sizeof(char)*(strlen(key)+1)); //creates the key array based on the length of the string-based key
new_node->data = data; //stores the user's data into the node
strcpy(new_node->key,key); //copies the key into the node
//calling the hash function in the user's program
index = table->hash_func(key); //index will hold the hash table value for where the new node will be placed
table->buckets[index] = new_node; //Assigns the pointer at the index value to the new node
table->total++; //increment the total (total # of buckets)
}
void *find_hash(Phash_table table, char *key){
int i;
hash_entry *cur;
printf("Inside find_hash\n"); //REMOVE
for(i = 0;i<table->size;i++){
if(table->buckets[i]!=NULL){
for (cur = table->buckets[i]; cur != NULL; cur = cur->next){
//for(table->buckets[i]; table->buckets[i]->next != NULL; table->buckets[i] = table->buckets[i]->next){
if(strcmp(cur->key, key) == 0)
return((cur->data));} //returns the data to the user if the key values match
} //otherwise return NULL, if no match was found.
}
return NULL;
}
void stat_hash(Phash_table table, int *total, int *largest, float *average){
int node_num[table->size];
int i,j, count = 0;
int largest_buck = 0;
hash_entry *cur;
for(i = 0; i < table->size; i ++)
{
if(table->buckets[i]!=NULL)
for (cur = table->buckets[i]; cur != NULL; cur = cur->next){
//for(table->buckets[i]; table->buckets[i]->next != NULL; table->buckets[i] = table->buckets[i]->next){
count ++;}
node_num[i] = count;
count = 0;
}
for(j = 0; j < table->size; j ++){
if(node_num[j] > largest_buck)
largest_buck = node_num[j];}
*total = table->total;
*largest = largest_buck;
*average = (table->total) /(float) (table->size); //oook: i think you want a fp average
}
void *start_hash_walk(Phash_table table){
void* temp = 0; //oook: this was another way of overwriting your input table
int i, j, k;
int l=0; //oook: new counter for elements in your sorted_array
hash_entry *cur;
if(table->sorted_array !=NULL) free(table->sorted_array);
table->sorted_array = (void**)calloc((table->total), sizeof(void*));
for(i = 0; i < table->size; i ++){
//for(i = 0; i < table->total; i++){ //oook: i don't think you meant total ;)
if(table->buckets[i]!=NULL)
for (cur = table->buckets[i]; cur != NULL; cur = cur->next){
//for(table->buckets[i]; table->buckets[i]->next != NULL; table->buckets[i] = table->buckets[i]->next){
table->sorted_array[l++] = cur->data;
}
}
//oook: sanity check/assert on expected values
if (l != table->total)
{
printf("oook: l[%d] != table->total[%d]\n",l,table->total);
}
for(j = (l) - 1; j > 0; j --) {
for(k = 1; k <= j; k ++){
if (table->sorted_array[k-1] && table->sorted_array[k])
{
if(table->cmp_func(table->sorted_array[k-1], table->sorted_array[k]) == 1){
temp = table->sorted_array[k-1]; //ook. changed temp to void* see assignment
table->sorted_array[k-1] = table->sorted_array[k];
table->sorted_array[k] = temp;
}
}
else
printf("if (table->sorted_array[k-1] && table->sorted_array[k])\n");
}
}
return table->sorted_array[table->sort_num];
}
void *next_hash_walk(Phash_table table){
/*oook: this was blowing up since you were incrementing past the size of sorted_array..
NB: *you **need** to implement some bounds checking here or you will endup with more seg-faults!!*/
//table->sort_num++
return table->sorted_array[table->sort_num++];
}
here's parse.c
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <assert.h> //oook: added so you can assert ;)
#include "hash.h"
#define WORD_SIZE 40
#define DICTIONARY_SIZE 1000
#define TRUE 1
#define FALSE 0
void lower_case_word(char *);
void dump_dictionary(Phash_table );
/*Hash and compare functions*/
int hash_func(char *);
int cmp_func(void *, void *);
typedef struct user_data_ {
char word[WORD_SIZE];
int freq_counter;
} user_data, *Puser_data;
int main(void)
{
char c, word1[WORD_SIZE];
int char_index = 0, dictionary_size = 0, num_words = 0, i;
int total=0, largest=0;
float average = 0.0;
Phash_table t; //Pointer to main hash_table
int (*Phash_func)(char *)=NULL; //Function Pointers
int (*Pcmp_func)(void *, void *)=NULL;
Puser_data data_node; //pointer to hash table above
user_data * find;
printf("Parsing input ...\n");
Phash_func = hash_func; //Assigning Function pointers
Pcmp_func = cmp_func;
t = new_hash(1000,Phash_func,Pcmp_func);
// Read in characters until end is reached
while ((c = getchar()) != EOF) {
if ((c == ' ') || (c == ',') || (c == '.') || (c == '!') || (c == '"') ||
(c == ':') || (c == '\n')) {
// End of a word
if (char_index) {
// Word is not empty
word1[char_index] = '\0';
lower_case_word(word1);
data_node = (Puser_data)calloc(1,sizeof(user_data));
strcpy(data_node->word,word1);
printf("%s\n", data_node->word);
//!!!!!!SEG FAULT HERE!!!!!!
if (!((user_data *)find_hash(t, data_node->word))){ //SEG FAULT!!!!
dictionary_size++;
insert_hash(t,word1,(void *)data_node);
}
char_index = 0;
num_words++;
}
} else {
// Continue assembling word
word1[char_index++] = c;
}
}
printf("There were %d words; %d unique words.\n", num_words,
dictionary_size);
dump_dictionary(t); //???
}
void lower_case_word(char *w){
int i = 0;
while (w[i] != '\0') {
w[i] = tolower(w[i]);
i++;
}
}
void dump_dictionary(Phash_table t){ //???
int i;
user_data *cur, *cur2;
stat_hash(t, &(t->total), &(t->largest), &(t->average)); //Call to stat hash
printf("Number of unique words: %d\n", t->total);
printf("Largest Bucket: %d\n", t->largest);
printf("Average Bucket: %f\n", t->average);
cur = start_hash_walk(t);
if (!cur) //ook: do test or assert for null values
{
printf("oook: null== (cur = start_hash_walk)\n");
exit(-1);
}
printf("%s: %d\n", cur->word, cur->freq_counter);
for (i = 0; i < t->total; i++)
{//oook: i think you needed these braces
cur2 = next_hash_walk(t);
if (!cur2) //ook: do test or assert for null values
{
printf("oook: null== (cur2 = next_hash_walk(t) at i[%d])\n",i);
}
else
printf("%s: %d\n", cur2->word, cur2->freq_counter);
}//oook: i think you needed these braces
}
int hash_func(char *string){
int i, sum=0, temp, index;
for(i=0; i < strlen(string);i++){
sum += (int)string[i];
}
index = sum % 1000;
return (index);
}
/*array1 and array2 point to the user defined data struct defined above*/
int cmp_func(void *array1, void *array2){
user_data *cur1= array1;
user_data *cur2= array2;//(user_data *)array2;
/* ooook: do assert on programmatic errors.
this function *requires non-null inputs. */
assert(cur1 && cur2);
if(cur1->freq_counter < cur2->freq_counter){
return(-1);}
else{ if(cur1->freq_counter > cur2->freq_counter){
return(1);}
else return(0);}
}
follow the //ooks
Explanation:
There were one or two places this was going to blow up in.
The quick fix and answer to your question was in parse.c, circa L100:
cur = start_hash_walk(t);
printf("%s: %d\n", cur->word, cur->freq_counter);
..checking that cur is not null before calling printf fixes your immediate seg-fault.
But why would cur be null ? ~because of this bad-boy:
void *start_hash_walk(Phash_table table)
Your hash_func(char *string) can (& does) return non-unique values. This is of course ok except that you have not yet implemented your linked list chains. Hence you end up with table->sorted_array containing less than table->total elements ~or you would if you were iterating over all table->size buckets ;)
There are one or two other issues.
For now i hacked Nate Kohl's for(cur=table->buckets[i]; cur->next != NULL; cur=cur->next) further, to be for(cur=table->buckets[i]; cur != NULL; cur=cur->next) since you have no chains. But this is *your TODO so enough said about that.
Finally. note that in next_hash_walk(Phash_table table) you have:
table->sort_num++
return table->sorted_array[table->sort_num];
Ouch! Do check those array bounds!
Notes
1) If you're function isn't designed to change input, then make the input const. That way the compiler may well tell you when you're inadvertently trashing something.
2) Do bound checking on your array indices.
3) Do test/assert for Null pointers before attempting to use them.
4) Do unit test each of your functions; never write too much code before compiling & testing.
5) Use minimal test-data; craft it such that it limit-tests your code & attempts to break it in cunning ways.
6) Do initialise you data structures!
7)Never use egyptian braces ! {
only joking ;)
}
PS Good job so far ~> pointers are tricky little things! & a well asked question with all the necessary details so +1 and gl ;)
(//oook: maybe add a homework tag)