I am trying to load two files into memory, one as an array of 2d arrays of chars (i.e., a char ***) and the other as a hash table. My whole file is below, and I can share the files in files/ if they are asked for. My goal is to implement a minimax algorithm to solve a game a friend made called WordBord (wordbord.com, and I decided that C would be the most efficient language. If you have suggestions for other languages (I am proficient in Python and know probably enough Java to get this done), please tell me. I am mainly doing this to challenge myself.
Program:
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define BOARDS 730
#define BOARD_SIZE 5
#define NUM_BUCKETS 3001
/*
* Plan: Board layout:
* Array of 2d arrays, so a char *** array (lol)
* Array of strings (words)
*/
struct node {
struct node *next;
char *word;
};
char ***boards;
struct node **words;
// Djb2 hash function
// Code from:
// https://gist.github.com/MohamedTaha98/ccdf734f13299efb73ff0b12f7ce429f
unsigned long hash(char *str) {
unsigned long hash = 5381;
int c;
while ((c = *str ))
hash = ((hash << 5) hash) c; /* hash * 33 c */
return hash % NUM_BUCKETS;
}
bool isword(char *str) {
unsigned long int idx = hash(str);
struct node *node_ptr = words[idx];
while (node_ptr != NULL) {
if (!strcmp(node_ptr->word, str)) {
return true;
}
node_ptr = node_ptr->next;
}
return false;
}
void add(char *str) {
// Add string to hash table
printf("%s\n", str);
}
int main() {
FILE *boards_file = fopen("files/boards", "r");
char c[BOARD_SIZE 1];
int count = 0;
int sub_board_count = 0;
boards = malloc(sizeof(char**) * BOARDS);
for (int i = 0; i < BOARDS; i ) {
boards[i] = malloc(sizeof(char*) * BOARD_SIZE);
for (int j = 0; j < BOARD_SIZE; j ) {
boards[i][j] = malloc(BOARD_SIZE 1);
}
}
printf("loading...\n");
printf("here\n");
while (fread(&c, 1, BOARD_SIZE, boards_file)) {
printf("here\n");
strcat(boards[count][sub_board_count], c);
printf("here\n");
printf("%s -> %s (%i, %i)\n", c, boards[count][sub_board_count], count, sub_board_count);
fseek(boards_file, 1, SEEK_CUR);
sub_board_count ;
if (sub_board_count == 5) {
// We reached the end of the board!
count ;
sub_board_count = 0;
}
}
printf("done loading, printing...\n-----\n");
for (int i = 0; i < BOARDS; i ) {
for (int j = 0; j < BOARD_SIZE; j ) {
printf("%s\n", boards[i][j]);
}
printf("-----\n");
}
fclose(boards_file);
printf("done loading boards, loading words...\n");
FILE *words_file = fopen("files/words", "r");
char c2[BOARD_SIZE 1];
printf("here\n");
while (fread(&c2, 1, BOARD_SIZE, words_file)) {
printf("here\n");
add(c2);
}
printf("program done, freeing...\n");
// don't forget to close and free everthing!
for (int i = 0; i < BOARDS; i ) {
for (int j = 0; j < BOARD_SIZE; j ) {
free(boards[i][j]);
}
free(boards[i]);
}
free(boards);
}
When compiled with gcc (full command: gcc -Wall -Werror -Wextra -Wno-sign-compare -Wshadow wordbord-solver.c -lcrypt -lm -lgmp -o wordbord-solver
(I know I don't need those links but they're useful for other programs, ie make <name>), a segfault occurs on line 95, the second while loop.
Thank you in advance for your time. Apologies if I am being stupid and missing something obvious, but some google digging showed that lines like char c[BOARD_SIZE 1]
worked as well as some heap stuff (e.g. char *c = malloc(BOARD_SIZE 1); memset(c, 0, BOARD_SIZE 1);
)
CodePudding user response:
Issues
Here are some issues that might be causing your segmentation fault:
- Both the buffer
c
andc2
are declared on the stack, and not null-terminated. You're unsafely assuming they are null-terminated. This can easily be a source of a segfault when you try toprintf
these buffers (printf
always searches for the null character as an indication of the end of the buffer) - You are using
strcat
in the same way on a non-nulled buffer that you allocate for your 2D boards (strcat(boards[count][sub_board_count], c);
). Youmalloc
'd these buffers but that memory isn't guaranteed to be zero.strcat
also looks for a null character to indicate where to begin concatenating. - You indefinitely read in boards from the file
boards_file
, and never check to see if you have capacity. You've fixed your board count at730
(#define BOARDS 730
). If the file contains more, you'll also get a segmentation fault because you don't perform a bounds check.
Fixes
- Always zero your stack buffers. You can do this with:
char c[N] = {0}; // Zeroes the entire buffer
. - Always zero your allocated memory, if you'll be storing strings in them and using C string functions. So either use
memset
orcalloc
to allocate them zeroed.