C - Saving strings into array elements - c

I have a notepad file with approximately 150,000 words (representing a dictionary). I'm trying to scan in each word and print it to the console. This setup works fine:
void readDictionary(FILE *ifp, int numWords) {
fscanf(ifp, "%d", &numWords);
printf("%d\n", numWords);
int i;
char* words = (char*)malloc(20 * sizeof(char));
for(i = 0; i < numWords; i++) {
fscanf(ifp, "%s", words);
printf("%s\n", words);
}
}
However, this code obviously overwrites "words" each time it loops. I'm trying to get each word to save to a certain array element. I did the following but it instantly crashes (I changed the memory allocation to 2D because I read around here and it seems that is what I am supposed to do):
void readDictionary(FILE *ifp, int numWords) {
fscanf(ifp, "%d", &numWords);
printf("%d\n", numWords);
int i;
char** words = (char**)malloc(20 * sizeof(char*));
for(i = 0; i < numWords; i++) {
fscanf(ifp, "%s", words[i]);
printf("%s\n", words[i]);
}
}
Any help is appreciated. I've read around on many posts but haven't figured it out.

In your second version, you allocate space for 20 pointers, but you leave those pointers uninitialized and without anything to point to. I'm sure you can imagine how that presents a problem when you then try to read from your dictionary into the memory designated by one of those pointers.
It looks like you want to allocate space for numwords pointers
char** words = malloc(numwords * sizeof(*words));
, and for each of them, to allocate space for a word.
for(i = 0; i < numWords; i++) {
words[i] = malloc(20); // by definition, sizeof(char) == 1
// ...
Additionally, do check the return value of malloc(), which will be NULL in the event of allocation failure.

The first problem is you only allocated space for a list of words (ie. character pointers) but you didn't allocate space for the words themselves.
char** words = (char**)malloc(20 * sizeof(char*));
This allocates space for 20 character pointers and assigns it to words. Now words[i] has space for a character pointer but not for the characters.
words[i] contains garbage, because malloc does not initialize memory. When you pass it into fscanf, fscanf tries to use the garbage in words[i] as a memory location to write characters to. That's either going to corrupt some memory in the program, or more likely it tries to read a memory location is isn't allowed to and crashes. Either way, it's not good.
You have to allocate memory for the string, pass that to fscanf, and finally put that string into words[i].
char** words = malloc(numWords * sizeof(char*));
for(i = 0; i < numWords; i++) {
char *word = malloc(40 * sizeof(char));
fscanf(ifp, "%39s", word);
words[i] = word;
printf("%s\n", words[i]);
}
Note that I didn't cast the result of malloc, that's generally considered unnecessary.
Also note that I allocated space for numWords in the list. Your original only allocates space for 20 words, once it goes over that it'll start overwriting allocated memory and probably crash. As a rule of thumb, avoid constant memory allocations. Get used to dynamic memory allocation as quickly as you can.
Also note that I limited how many characters fscanf is allowed to read to the size of my buffer (minus one because of the null byte at the end of strings). Otherwise if your word list contained "Pneumonoultramicroscopicsilicovolcanoconiosis", 45 characters, it would overrun the word buffer and start scribbling on adjacent elements and that would be bad.
This leads to a new problem that are common to fscanf and scanf: partial reads. When the code above encounters "Pneumonoultramicroscopicsilicovolcanoconiosis" fscanf(ifp, "%39s", word); will read in the first 39 characters, "Pneumonoultramicroscopicsilicovolcanoco" and stop. The next call to fscanf will read "niosis". You'll store and print them as if they were two words. That's no good.
You could solve this by making the word buffer bigger, but now most words will be wasting a lot of memory.
scanf and fscanf have a whole lot of problems and are best avoided. Instead, it's best to read entire lines and parse them with sscanf. In this case you don't need to do any parsing, they're just strings, so getting the line will suffice.
fgets is the usual way to read a line, but that also requires that you try and guess how much memory you'll need to read in the line. To mitigate that, have a large line buffer, and copy the words out of it.
void strip_newline( char* string ) {
size_t len = strlen(string);
if( string[len-1] == '\n' ) {
string[len-1] = '\0';
}
}
...
int i;
/* The word list */
char** words = malloc(numWords * sizeof(char*));
/* The line buffer */
char *line = malloc(1024 * sizeof(char*));
for(i = 0; i < numWords; i++) {
/* Read into the line buffer */
fgets(line, 1024, ifp);
/* Strip the newline off, fgets() doesn't do that */
strip_newline(line);
/* Copy the line into words */
words[i] = strdup(line);
printf("%s\n", words[i]);
}
strdup won't copy all 1024 bytes, just enough for the word. This will result in using only the memory you need.
Making assumptions about files, like that they'll have a certain number of lines, is a recipe for problems. Even if the file says it contains a certain number of lines you should still verify that. Otherwise you'll get bizarre errors as you try to read past the end of the file. In this case, if the file has less than numWords it'll try to read garbage and probably crash. Instead, you should read the file until there's no more lines.
Normally this is done by checking the return value of fgets in a while loop.
int i;
for( i = 0; fgets(line, 1024, ifp) != NULL; i++ ) {
strip_newline(line);
words[i] = strdup(line);
printf("%s\n", words[i]);
}
This brings up a new problem, how do we know how big to make words? You don't. This brings us to growing and reallocating memory. This answer is getting very long, so I'll just sketch it.
char **readDictionary(FILE *ifp) {
/* Allocate a decent initial size for the list */
size_t list_size = 256;
char** words = malloc(list_size * sizeof(char*));
char *line = malloc(1024 * sizeof(char*));
size_t i;
for( i = 0; fgets(line, 1024, ifp) != NULL; i++ ) {
strip_newline(line);
/* If we're about to overflow the list, double its size */
if( i > list_size - 1 ) {
list_size *= 2;
words = realloc( words, list_size * sizeof(char*));
}
words[i] = strdup(line);
}
/* Null terminate the list so readers know when to stop */
words[i] = NULL;
return words;
}
int main() {
FILE *fp = fopen("/usr/share/dict/words", "r");
char **words = readDictionary(fp);
for( int i = 0; words[i] != NULL; i++ ) {
printf("%s\n", words[i]);
}
}
Now the list will start at size 256 and grow as needed. Doubling grows pretty fast without wasting too much memory. My /usr/share/dict/words has 235886 lines in it. That can be stored in 218 or 262144. 256 is 28 so it only requires 10 expensive calls to realloc to grow to the necessary size.
I've changed it to return the list, because there isn't much good in building the list if you're just going to use it immediately. This allows me to demonstrate another technique in working with dynamically sized lists, null termination. The last element in the list is set to NULL so anyone reading the list knows when to stop. This is safer and simpler than trying to pass the length around with the list.
That was a lot, but that's all the basic stuff you need to do when working with files in C. It's good to do it manually, but fortunately there are libraries out there which make doing this sort of thing a lot easier. For example, Gnome Lib provides a lot of basic functionality including arrays of pointers that automatically grow as needed.

Related

C / Getting line string from text file and storing them in array/pointer

I want to get all lines from the text file and store them in my char** pointer (array of strings). The problem is that when I try to set indices for pointer's strings, the program assigns the last scanned sentence for all indices.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE 10000
int main()
{
FILE *fp = NULL;
char line[MAX_LINE];
char** lines = (char**) malloc(10000*200*sizeof(char));
int count = 0;
fp = fopen("test.txt","r");
while(fgets(line,10000,fp)) {
lines[count] = line;
count++;
}
fclose(fp);
for(int i =0; i<2000;i++){
printf("%s",lines[i]);
}
return 0;
}
lets assume test.txt is like this:
Alice was beginning to get very tired of sitting by her sister on the
bank, and of having nothing to do: once or twice she had peeped into the
book her sister was reading, but it had no pictures or conversations in
it, and what is the use of a book, thought Alice without pictures or
conversations?
When I print like this, every time I get the last sentence (in this case conversations? ) in my text file. However, I want to set every scanned sentence from the text file to the different index in my char**. For example, I want to set like this:
lines[0] gives "Alice was beginning to get very tired of sitting by her sister on the"
lines[1] gives "bank, and of having nothing to do: once or twice she had peeped into the"
and so on.
You can't copy characters from one string buffer to another simply by assigning a pointer (all that does is to make the destination point to the source, as you have noticed).
Instead, you must actually copy the characters, using the strcpy function. So, instead of:
lines[count] = line; // Just makes each pointer point to the same buffer
use:
strcpy(lines[count], line); // Copies the CURRENT contents of "line"
You also have a severe problem in the way you are using your char** lines buffer. If you want an array of 200 lines, each with a maximum length of 10000 characters, you should allocate them as follows:
char** lines = malloc(200 * sizeof(char*)); // Make 200 pointers
// Now allocate 10000 chars to each of these pointers:
for (int i = 0; i < 200; ++i) lines[i] = malloc(10000 * sizeof(char));
Note: The 200 buffers will be uninitialized (contain random data) so, in your print loop, you should only use those you have copied real data to, using the count variable as the loop limit:
for(int i = 0; i < count; i++) {
printf("%s", lines[i]);
}
Also, don't forget to free the memory allocated when you're done:
for (int i = 0; i < 200; ++i) free(lines[i]); // Free each line buffer...
free(lines); // ... then free the array of pointers itself
strdup resolve the issue, free resources as said by Adrian when finished.
int main()
{
FILE *fp = NULL;
char line[MAX_LINE];
char** lines = (char**) malloc(10000*200*sizeof(char));
int count = 0;
fp = fopen("test.txt","r");
while(fgets(line,10000,fp)) {
lines[count] = strdup(line);
count++;
}
fclose(fp);
for(int i =0; i<count;i++){
printf("%s",lines[i]);
}
for (int i = 0; i < count; ++i) free(lines[i]);
free(lines);
return 0;
}
If you are looking for better performance look at my repo (https://github.com/PatrizioColomba/strvect)

reading a file of strings to a multidimensional array to access later

I am really having a problem understanding dynamically allocated arrays.
I am attempting to read a text file of strings to a 2d array so I can sort them out later. right now as my code stands it throws seg faults every once in a while. Which means I'm doing something wrong. I've been surfing around trying to get a better understanding of what malloc actually does but I want to test and check if my array is being filled.
my program is pulling from a text file with nothing but strings and I am attempting to put that data into a 2d array.
for(index = 0; index < lines_allocated; index++){
//for loop to fill array 128 lines at a time(arbitrary number)
words[index] = malloc(sizeof(char));
if(words[index] == NULL){
perror("too many characters");
exit(2);
}
//check for end of file
while(!feof(txt_file)) {
words = fgets(words, 64, txt_file);
puts(words);
//realloc if nessesary
if (lines_allocated == (index - 1)){
realloc(words, lines_allocated + lines_allocated);
}
}
}
//get 3rd value placed
printf("%s", words[3]);
since this just a gist, below here ive closed and free'd the memory, The output is being displayed using puts, but not from the printf from the bottom. an ELI5 version of reading files to an array would be amazing.
Thank you in advance
void *malloc(size_t n) will allocate a region of n bytes and return a pointer to the first byte of that region, or NULL if it could not allocate enough space. So when you do malloc(sizeof(char)), you're only allocating enough space for one byte (sizeof(char) is always 1 by definition).
Here's an annotated example that shows the correct use of malloc, realloc, and free. It reads in between 0 and 8 lines from a file, each of which contains a string of unknown length. It then prints each line and frees all the memory.
#include <stdio.h>
#include <stdlib.h>
/* An issue with reading strings from a file is that we don't know how long
they're going to be. fgets lets us set a maximum length and discard the
rest if we choose, but since malloc is what you're interested in, I'm
going to do the more complicated version in which we grow the string as
needed to store the whole thing. */
char *read_line(void) {
size_t maxlen = 16, i = 0;
int c;
/* sizeof(char) is defined to be 1, so we don't need to include it.
the + 1 is for the null terminator */
char *s = malloc(maxlen + 1);
if (!s) {
fprintf(stderr, "ERROR: Failed to allocate %zu bytes\n", maxlen + 1);
exit(EXIT_FAILURE);
}
/* feof only returns 1 after a read has *failed*. It's generally
easier to just use the return value of the read function directly.
Here we'll keep reading until we hit end of file or a newline. */
while ('\n' != (c = getchar())) {
if (EOF == c) {
/* We return NULL to indicate that we hit the end of file
before reading any characters, but if we've read anything,
we still want to return the string */
if (0 == i) return NULL;
break;
}
if (i == maxlen) {
/* Allocations are expensive, so we don't want to do one each
iteration. As such, we're always going to allocate more than
we need. Exactly how much extra we allocate depends on the
program's needs. Here, we just add a constant amount. */
maxlen += 16;
/* realloc will attempt to resize the memory pointed to by s,
or copy it to a newly allocated region of size maxlen. If it
makes a copy, it will free the old version. */
char *p = realloc(s, maxlen + 1);
if (!p) {
/* If the realloc fails, it does not free the old version, so we do it here. */
free(s);
fprintf(stderr, "ERROR: Failed to allocate %zu bytes\n", maxlen + 1);
exit(EXIT_FAILURE);
}
s = p;//set the pointer to the newly allocated memory
}
s[i++] = c;
}
s[i] = '\0';
return s;
}
int main(void) {
/* If we wanted to, we could grow the array of strings just like we do the strings
themselves, but for brevity's sake, we're just going to stop reading once we've
read 8 of them. */
size_t i, nstrings = 0, max_strings = 8;
/* Each string is an array of characters, so we allocate an array of char*;
each char* will point to the first element of a null-terminated character array */
char **strings = malloc(sizeof(char*) * max_strings);
if (!strings) {
fprintf(stderr, "ERROR: Failed to allocate %zu bytes\n", sizeof(char*) * max_strings);
return 1;
}
for (nstrings = 0; nstrings < max_strings; nstrings++) {
strings[nstrings] = read_line();
if (!strings[nstrings]) {//no more strings in file
break;
}
}
for (i = 0; i < nstrings; i++) {
printf("%s\n", strings[i]);
}
/* Free each individual string, then the array of strings */
for (i = 0; i < nstrings; i++) {
free(strings[i]);
}
free(strings);
return 0;
}
I haven't looked too closely so I could be offering an incomplete solution.
That being said, the error is probably here:
realloc(words, lines_allocated + lines_allocated);
realloc if succesful returns the new pointer, if you're lucky it can allocate the adjacent space (which wouldn't cause a segfault).
words = realloc(words, lines_allocated + lines_allocated);
would solve it, although you probably need to check for errors.

How to store fgets string results into an char array?

I am currently getting the following error
Process terminated with status -1073741819
and I suspect its my fgets() but I have no idea why this is happening, any help would be much appreciated.
//Gets Dictionary from file
char* GetDictionary() {
int ArraySize;
int i = 0;
FILE * DictionaryFile;
//Gets first line (in this case it is the amount of Lines)
DictionaryFile = fopen("dictionary.txt", "r");
fscanf(DictionaryFile,"%d", &ArraySize);
ArraySize = ArraySize + 1;
printf("%d", ArraySize);
fclose(DictionaryFile);
//Gets the array
char* Dictionary = malloc(sizeof(char)*ArraySize);
char Temp[ArraySize];
char TempArray[ArraySize];
DictionaryFile = fopen("dictionary.txt", "r");
while(fgets(Temp, sizeof Temp, DictionaryFile)!=NULL) {
Dictionary[i] = Temp;
//Check The array
printf("%s", Dictionary[i]);
i++;
}
fclose(DictionaryFile);
return Dictionary;
}
-1073741819 --> C0000005 and likely has some significance. Maybe use below to discern its meaning.
puts(strerror(-1073741819));
Code has many issues: Here are some corrected to get you going.
1) Allocate an array of pointers, not an array of char
// char* Dictionary = malloc(sizeof(char)*ArraySize);
char** Dictionary = malloc(ArraySize * sizeof *Dictionary);
2) Form a big buffer to read each line
char Temp[100];
3) After reading each line, get rid of the likely trailing '\n'
size_t len = strlen(Temp);
if (len && Temp[len-1] == '\n') Temp[--len] = 0;
4) Allocate memory for that word and save
Dictionary[i] = malloc(len + 1);
assert(Dictionary[i]);
memcpy(Dictionary[i], Temp, len + 1);
5) Robust code frees it allocations before completion
6) Code reads "amount of Lines" twice as file is opened twice. Just leave file open (and not re-open it). #user3386109
You likely want Dictionary to be an array of char strings. That is, Dictionary is an array, and each element in the array is a char *. That makes Dictionary a char **.
For this example, it may be most straightforward to allocate memory for the Dictionary array itself, then allocate memory for its contents. You'll need to free all this when you're done, of course.
char **Dictionary = malloc(sizeof(char *) * ArraySize);
for (int i = 0; i < ArraySize; i++) {
Dictionary[i] = malloc(ArraySize);
}
There are better ways to do this. For one, you might only allocate memory when you need it, for each fgets() return. You could also use strdup() to allocate only the memory you need. You could also pass in Dictionary from the caller, already allocated, so you don't worry about allocating it here.
Later in your program, as #WhozCraig pointed out, you need to copy the string in Temp, like strcpy(Dictionary[i], Temp), in place of Dictionary[i] = Temp. I too am surprised that's not generating a compiler warning!

fscanf in C with a text file with no spaces

I have a text file with names that looks as follows:
"MARY","PATRICIA","LINDA","BARBARA","ELIZABETH","JENNIFER","MARIA","SUSAN","MARGARET",
I have used the following code to attempt to put the names into an array:
char * names[9];
int i = 0;
FILE * fp = fopen("names.txt", "r");
for (i=0; i < 9; i++) {
fscanf(fp, "\"%s\",", names[i]);
}
The program comes up with a segmentation fault when I try to run it. I have debugged carefully, and I notice that the fault comes when I try and read in the second name.
Does anybody know why my code isn't working, and also why the segmentation fault is happening?
You have undefined behavior in your code, because you don't allocate memory for the pointers you write to in the fscanf call.
You have an array of nine uninitialized pointers, and as they are part of a local variable they have an indeterminate value, i.e. they will point to seemingly random locations. Writing to random locations in memory (which is what will happen when you call fscanf) will do bad things.
The simplest way to solve the problem is to use an array of arrays, like e.g.
char names[9][20];
This will gives you an array of nine arrays, each sub-array being 20 characters (which allows you to have names up to 19 characters long).
To not write out of bounds, you should also modify your call so that you don't read to many characters:
fscanf(fp, "\"%19s\",", names[i]);
There is however another problem with your use of the fscanf function, and that is that the format to read a string, "%s", reads until it finds a whitespace in the input (or until the limit is reached, if a field width is provided).
In short: You can't use fscanf to read your input.
Instead I suggest you read the whole line into memory at once, using fgets, and then split the string on the comma using e.g. strtok.
One way of handling arbitrarily long lines as input from a file (pseudoish-code):
#define SIZE 256
size_t current_size = SIZE;
char *buffer = malloc(current_size);
buffer[0] = '\0'; // Terminator at first character, makes the string empty
for (;;)
{
// Read into temporary buffer
char temp[SIZE];
fgets(temp, sizeof(temp), file_pointer);
// Append to actual buffer
strcat(buffer, temp);
// If last character is a newline (which `fgets` always append
// if it reaches the end of the line) then the whole line have
// been read and we are done
if (last_character_is_newline(buffer))
break;
// Still more data to read from the line
// Allocate a larger buffer
current_size += SIZE;
buffer = realloc(buffer, current_size);
// Continues the loop to try and read the next part of the line
}
// After the loop the pointer `buffer` points to memory containing the whole line
[Note: The above code snippet doesn't contain any error handling.]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char *names[9], buff[32];
int i = 0;
FILE *fp = fopen("names.txt", "r");
for(i = 0; i < 9; i++) {
if(1==fscanf(fp, "\"%31[^\"]\",", buff)){//"\"%s\"," does not work like that what you want
size_t len = strlen(buff) + 1;
names[i] = malloc(len);//Space is required to load the strings of each
memcpy(names[i], buff, len);
}
}
fclose(fp);
//check print & deallocate
for(i = 0; i< 9; ++i){
puts(names[i]);
free(names[i]);
}
return 0;
}
try this...
for (i=0; i < 9; i++)
{
names[i]=malloc(15);// you should take care about size
fscanf(fp, "\"%s\",", names[i]);
}

Trying to load text file into an array, getting a seg fault. Any ideas why?

The task of this function is fairly straightforward. Given an array of char*, a pointer to a file, and a maximum word size, it reads through the file and copies each word one by one into the char* array. Since there's one word per line in the file, it makes sense to use \n as the break between words. So with that in mind, the code should be fairly simple to interpret:
void loadDictionary(char* strDictionary[], FILE* filePointer, int nMaxLetters)
{
int nNameCount= 0, nCursor = 0;
char* strCurrent;
char cCurrent;
//allocate space for a word
strCurrent = malloc(nMaxLetters * sizeof(char));
while ((cCurrent = fgetc(filePointer)) != EOF) {
if(cCurrent != '\n')
{
strCurrent[nCursor] = cCurrent;
nCursor++;
} else { //then we've reached the end of the line (word)
//add null termination to string
strCurrent[nCursor] = '\0'; //SEG FAULT
//copy string to dictionary
memcpy(strDictionary[nNameCount], strCurrent, strlen(strCurrent)+1);
//increment count
nNameCount++;
//reset the cursor
nCursor = 0;
}
}
}
This code generates a segmentation fault at the line where I call strCurrent[nCursor] = '\0';. I'm not sure why, because on the face of it, it seems like this operation should be no different from the operation in the other block, where I call strCurrent[nCursor] = cCurrent;. strCurrent should have allocated more than enough space to store all necessary characters. So, I'm somewhat at a loss. Help me figure this one out, guys.
Note: I think I would probably have an easier time using fgets instead of fgetc to accomplish this task. I might well switch to that; however, since I have encountered an error I don't understand, I don't want to leave it alone until I've understood it.
EDIT:
Someone pointed out that the error might occur in the memcpy operation, possibly due to strDictionary being improperly allocated. Here's the main block where strDictionary gets allocated. Perhaps I have made an error:
int main(int argc, char* argv[])
{
char** strDictionary;
FILE* filePointer;
int nResults = 0, nLines = 0, nNumLines, nMaxChars, i;
filePointer = fopen("dictionary.txt", "r");
//obtain the number of lines and the maximum word size of the dictionary
countLines(filePointer, &nNumLines, &nMaxChars);
//allocate memory for strDictionary
strDictionary = malloc(nNumLines * nMaxChars * sizeof(char));
printf("%d words in dictionary. Longest word is %d letters\n",
nNumLines, nMaxChars);
//Output here correctly prints: 1000 and 21
//reset the file pointer (not sure if this is a necessary step, but oh well)
filePointer = fopen("dictionary.txt", "r");
//load dictionary into memory
loadDictionary(strDictionary, filePointer, nMaxChars);
for (i=0; i<10; i++)
printf("%dth element of dictionary: %s\n", i, strDictionary[i]);
return 0;
}
EDIT 2:
OK, I decided to use fgets() instead of fgetc() to greatly simplify my function. I've also done what I thought was a correct malloc() operation for strDictionary. However, I'm still getting a seg fault. Here's the updated code:
void loadDictionary(char* strDictionary[], FILE* filePointer, int nMaxLetters)
{
printf("Call to loadDictionary. nMaxLetters = %d\n", nMaxLetters);
int nWordCount= 0, nCursor = 0;
char* strCurrent;
char cCurrent;
strCurrent = malloc(nMaxLetters); //allocate space for a word
while (fgets(strCurrent, nMaxLetters, filePointer) != NULL)
{
memcpy(strDictionary[nWordCount], strCurrent, strlen(strCurrent)+1);
nWordCount++;
}
}
int main(int argc, char* argv[])
{
char** strDictionary;
FILE* filePointer;
int nResults = 0, nLines = 0, nNumLines, nMaxChars, i;
filePointer = fopen("dictionary.txt", "r");
//count the lines in the file (works fine)
countLines(filePointer, &nNumLines, &nMaxChars);
//allocate space for the dictionary
strDictionary = malloc(nNumLines * sizeof(char*));
for (i = 0; i<nLines; i++)
strDictionary[i] = malloc(nMaxChars * sizeof(char));
printf("%d words in dictionary. Longest word is %d letters\n",
nNumLines, nMaxChars);
//load dictionary into array
filePointer = fopen("dictionary.txt", "r");
loadDictionary(strDictionary, filePointer, nMaxChars);
for (i=0; i<10; i++)
printf("%dth element of dictionary: %s\n", i, strDictionary[i]);
return 0;
}
Here:
char cCurrent;
...
while ((cCurrent = fgetc(filePointer)) != EOF) {
You are truncating the fgetc()'s value of type int to char. This may lead to the while condition not correctly recognizing EOF. cCurrent has to be int.
Here:
//allocate space for a word
strCurrent = malloc(nMaxLetters * sizeof(char));
nMaxLetters has to account for one extra character representing the string NUL terminator. Is it accounted for?
Btw, sizeof(char) is always 1.
Now, this parameter declaration:
char* strDictionary[]
is equivalent to this:
char** strDictionary
or, IOW, a pointer to a pointer to a char. That's because in C, arrays are never passed as parameters, only pointers to their first elements are, despite the deceptive syntax with the brackets suggesting something is an array.
This line:
memcpy(strDictionary[nNameCount], strCurrent, strlen(strCurrent)+1);
is going to take nNameCount'th pointer to a char and write character data where it points to.
But does the calling function allocate at least as many string buffers (of length nMaxLetters) as there are going to be lines in the file? Does it populate some array of pointers to char with the pointers to these buffers before passing this array into loadDictionary()? IOW, this code is expecting the caller to do something like this:
#define nMaxEntries 1000
char* dictionary[nMaxEntries];
int i;
FILE* f;
...
for (i = 0; i < nMaxEntries; i++)
dictionary[i] = malloc(nMaxLetters);
loadDictionary(dictionary, f, nMaxLetters);
Memory allocation failures must be checked in the above code. Also, I'd strongly suggest passing nMaxEntries into or using it in loadDictionary() so you don't overrun the array of pointers if the file has more lines than nMaxEntries. nNameCount should not grow beyond nMaxEntries.
UPDATE to the updated question...
Here:
char** strDictionary;
...
strDictionary = malloc(nNumLines * nMaxChars * sizeof(char));
You are not creating an array of pointers to char as loadDictionary() expects per the above analysis, you are creating a 2d array of char. And because of that the segfault most probably occurs not on this line:
strCurrent[nCursor] = '\0'; //SEG FAULT
but on the very next one, which may not be apparent in the debugger until you zoom in and look at the disassembly of the code:
//copy string to dictionary
memcpy(strDictionary[nNameCount], strCurrent, strlen(strCurrent)+1);
UPDATE2:
I don't understand why you now allocate space for nNumLines pointers:
strDictionary = malloc(nNumLines * sizeof(char*));
but of those nNumLines pointers you initialize nLines pointers (and nLines never becomes anything other than 0 if I'm reading your latest code correctly):
for (i = 0; i<nLines; i++)
strDictionary[i] = malloc(nMaxChars * sizeof(char));
What's the trick? Typo?

Resources