Reputation: 23
So I'm trying to create a function that takes in a text file, which contains a bunch of words separated by the newline character, and reads the text file into a char**
array.
When I run this code in netbeans on windows, it works fine but if I run it in Linux, I get a segmentation fault error.
// globals
FILE *words_file;
char **dic;
int num_words = 0;
void read_to_array() {
words_file = fopen("words.txt", "r");
char *line = NULL;
int i = 0;
size_t len = 0;
dic = (char **)malloc(99999 * sizeof(char *));
// read dic to array
while (getline(&line, &len, words_file) != -1) {
dic[i] = (char*)malloc(len);
strcpy(dic[i], line);
// get rid of \n after word
if (dic[i][strlen(dic[i]) - 1] == '\n') {
dic[i][strlen(dic[i]) - 1] = '\0';
}
++i;
num_words++;
}
//printf("%s", dic[i][strlen(dic[i]) - 1]); //testing
fclose(words_file);
dic[i] = NULL;
}
What am I missing here?
Upvotes: 1
Views: 140
Reputation: 144770
There are some problems in your program that may cause the undefined behavior that you observe:
/usr/share/dict/words
has 139716 lines on my system, for example.Your memory allocation scheme is suboptimal but correct: you should compute the length of the word and strip the newline before allocating the copy. As coded, you allocate too much memory. Yet you should free line
before returning from read_to_array
and you should avoid using global variables.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **read_to_array(const char *filename, int *countp) {
FILE *words_file;
char *line = NULL;
size_t line_size = 0;
char **dic = NULL;
int dic_size = 0;
int i = 0;
words_file = fopen(filename, "r");
if (words_file == NULL) {
fprintf(stderr, "cannot open dictionary file %s\n", filename);
return NULL;
}
dic_size = 99999;
dic = malloc(dic_size * sizeof(char *));
if (dic == NULL) {
fprintf(stderr, "cannot allocate dictionary array\n");
fclose(words_file);
return NULL;
}
// read dic to array
while (getline(&line, &line_size, words_file) != -1) {
size_t len = strlen(line);
/* strip the newline if any */
if (len > 0 && line[len - 1] == '\n') {
line[--len] = '\0';
}
if (i >= dic_size - 1) {
/* too many lines: should reallocate the dictionary */
fprintf(stderr, "too many lines\n");
break;
}
dic[i] = malloc(len + 1);
if (dic[i] == NULL) {
/* out of memory: report the error */
fprintf(stderr, "cannot allocate memory for line %d\n", i);
break;
}
strcpy(dic[i], line);
i++;
}
dic[i] = NULL;
*countp = i;
fclose(words_file);
free(line);
return dic;
}
int main(int argc, char **argv) {
const char *filename = (argc > 1) ? argv[1] : "words.txt";
int num_words;
char **dic = read_to_array(filename, &num_words);
if (dic != NULL) {
printf("dictionary loaded: %d lines\n", num_words);
while (num_words > 0)
free(dic[--num_words]);
free(dic);
}
return 0;
}
Output:
chqrlie> readdic /usr/share/dict/words too many lines dictionary loaded: 99998 lines
Upvotes: 1