What can be done in order to insert arrays into another array. I do happen to have a file which I'm looping through so my goal by now is to take each line within the file and put it into an array (An array of lines). Each line has some data related to a student and his/her tests results, for instance:
Mark Zuckerberg 10.0 5.5 9.7
Bill Gates 10.0 1.5 6.7
Example code:
FILE* file;
char buffer[256];
char arrayOfLines[500];
char line[256];
file= fopen("I:\\students.txt","r+");
/* Helps to iterate through each line */
while (fgets(buffer, sizeof(buffer), file)) {
//some logic to-be-coded
line = buffer; // just an idea does not work
arrayOfLines[i] = line; // just an idea does not work
}
Expected result:
arrayOfLines[] = {" Mark Zuckerberg 10.0 5.5 9.7", "Bill Gates 10.0
1.5 6.7" };
I certainly know this is somehow easy to achieve but after working with java for a long time it turned out to be a little bit tricky, could someone please help me out with this matter?
Everything works just fine when it comes to iterating and reading. However, when it comes to "playing" with each line it gets creepy. Perhaps I need to change my approach, any help would be welcomed.
Array names decay into pointers when you try to assign them. In order to copy the contents of buffer to another char[] variable, you'll have to use memcpy, strcpy or strncpy
Apart from that, you do have an issue with your arrayOfLines variable. It's not an array of lines. It's an array of 500 characters, so it's not even big enough to hold 2 lines, what you need is:
char array_of_lines[500][256];
And to copy the data, I'd use:
memcpy(aray_of_lines[i], buffer, sizeof buffer);//where `i` is the current line, starting at 0
It might be worth looking into malloc-ing the array of lines here, because this code requires 128,000 bytes of stack space to be available, just to accommodate the array_of_lines array, so I'd write:
char *array_of_lines[500];
//in the loop:
array_of_lines[i] = malloc(strlen(buffer) + 1);
//check for NULL, and all that
strncpy(array_of_lines[i], buffer, strlen(buffer));
#include <stdio.h>
#include <string.h>
int main( void ){
FILE *file = fopen("I:\\students.txt","r");
char buffer[256*500];
char *arrayOfLines[500];
char *line = buffer;
size_t buf_siz = sizeof(buffer);
int i=0, n;
while (fgets(line, buf_siz, file)) {
char *p = strchr(line, '\n');
if(p)
*p = '\0';//remove newline
else
p = strchr(line, '\0');
arrayOfLines[i++] = line;
buf_siz -= p - line + 1;
if(p + 1 == buffer + sizeof(buffer))
break;//buffer full!
line = p + 1;
}
fclose(file);
n = i;
for(i=0; i<n; ++i)
puts(arrayOfLines[i]);
return 0;
}
Related
I want to approach the string as an array, cut it to a specific length, and store it in a two-dimensional array. For example, I have 20 lines of text file. like this "input.txt"
www.google.com
www.naver.com
kbphonemall.com
kbplant.com
k-bplus.com
kbpointreestore.com
kbprint.com
kbprism.com
kbprivatebanking.com
kbpstore.com
kbr9rtudaf5ppy.com
kbrafting.com
kbraille.com
kbrainbank.com
kbrainbow.com
kbrainc.com
kbrainglocal.com
kbrandexpo.com
kbrandingschool.com
kbrandmall.com
and Then, I read this file and tried to crop it on each line using "\n as the key.
For example If you want to cut four lines at a time, you should cut it to "kbplant.com" first. And the truncated string looks like this.
www.google.com\nwww.naver.com\nkbphonemall.com\nkbplant.com\n
and It will then be stored in a pointer array. like this
char *cutting[n];
cutting[0] = "www.google.com\nwww.naver.com\nkbphonemall.com\nkbplant.com\n"
cutting[1] = "k-bplus.com\nkbpointreestore.com\nkbprint.com\nkbprism.com\n"
.... more
So far, that's the explanation of the functions I want to implement and I'll show you the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define IPATH "input.txt"
int main(int argc, char *argv[]) {
char *ListBuffer;
int ListSize;
FILE *InputFile = fopen(IPATH, "r");
fseek(InputFile, 0, SEEK_END);
ListSize = ftell(InputFile);
ListBuffer = malloc(ListSize);
memset(ListBuffer, 0, ListSize);
fseek(InputFile, 0, SEEK_SET);
fread(ListBuffer, ListSize, 1, InputFile);
int count = 0;
ListBuffer[ListSize] = '\0'; //add NULL word
for (int i = 0; i <= ListSize; i++) {
if (ListBuffer[i] == '\n') {
count++;
if (count == 4) {
printf("c%d\n", i);
count = 0;
}
}
if (ListBuffer[i] == 0) {
printf("c%d\n", i);
count = 0;
}
}
fclose(InputFile);
free(ListBuffer);
ListBuffer = NULL;
}
this is my code I have used various functions such as strcpy function, strtok function, memcpy function, etc., but it was difficult to implement the desired function. Is there a better way or algorithm?
If you need more explanation, I'll answer it quickly.
I would appreciate it if you could reply. Have a good day.
It is unclear what you are trying to achieve in the main loop, but there are more problems:
you must allocate one extra byte to set the null terminator at ListSize:
ListBuffer = malloc(ListSize + 1);
it is useless to set the array to 0 with memset: allocating with calloc(1, ListSize + 1) would be more efficient for this purpose, but since you read the contents into the array, clearing it first is useless.
fread might return a short count, for example in text mode on legacy systems, converting CR/LR sequences to newline bytes \n reduces the number of bytes read:
ListSize = fread(ListBuffer, 1, ListSize, InputFile);
ListBuffer[ListSize] = '\0'; // set the null terminator
this is my first time asking questions here. I'm currently learning C and Linux at the same time. I'm working on a simple c program that use system call only to read and write files. My problem now is, how can I read the file and compare the string/word are the same or not. An example here like this:
foo.txt contains:
hi
bye
bye
hi
hi
And bar.txt is empty.
After I do:
./myuniq foo.txt bar.txt
The result in bar.txt will be like:
hi
bye
hi
The result will just be like when we use uniq in Linux.
Here is my code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define LINE_MAX 256
int main(int argc, char * argv[]){
int wfd,rfd;
size_t n;
char temp[LINE_MAX];
char buf[LINE_MAX];
char buf2[LINE_MAX];
char *ptr=buf;
if(argc!=3){
printf("Invalid useage: ./excutableFileName readFromThisFile writeToThisFile\n");
return -1;
}
rfd=open(argv[1], O_RDONLY);
if(rfd==-1){
printf("Unable to read the file\n");
return -1;
}
wfd=open(argv[2], O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
if(wfd==-1){
printf("Unable to write to the file\n");
return -1;
}
while(n = read(rfd,buf,LINE_MAX)){
write(wfd,buf,n);
}
close(rfd);
close(wfd);
return 0;
}
The code above will do the reading and writing with no issue. But I can't really figure out how to read char one by one in C style string under what condition of while loop.
I do know that I may need a pointer to travel inside of buf to find the next line '\n' and something like:
while(condi){
if(*ptr == '\n'){
strcpy(temp, buf);
strcpy(buf, buf2);
strcpy(buf2, temp);
}
else
write(wfd,buf,n);
*ptr++;
}
But I might be wrong since I can't get it to work. Any feedback might help. Thank you.
And again, it only can be use system call to accomplish this program. I do know there is a easier way to use FILE and fgets or something else to get this done. But that's not the case.
You only need one buffer that stores whatever the previous line contained.
The way this works for the current line is that before you add a character you test whether what you're adding is the same as what's already in there. If it's different, then the current line is marked as unique. When you reach the end of the line, you then know whether to output the buffer or not.
Implementing the above idea using standard input for simplicity (but it doesn't really matter how you read your characters):
int len = 0;
int dup = 0;
for (int c; (c = fgetc(stdin)) != EOF; )
{
// Check for duplicate and store
if (dup && buf[len] != c)
dup = 0;
buf[len++] = c;
// Handle end of line
if (c == '\n')
{
if (dup) printf("%s", buf);
len = 0;
dup = 1;
}
}
See here that we use the dup flag to represent whether a line is duplicated. For the first line, clearly it is not, and all subsequent lines start off with the assumption they are duplicates. Then the only possibility is to remain a duplicate or be detected as unique when one character is different.
The comparison before store is actually avoiding tests against uninitialized buffer values too, by way of short-circuit evaluation. That's all managed by the dup flag -- you only test if you know the buffer is already good up to this point:
if (dup && buf[len] != c)
dup = 0;
That's basically all you need. Now, you should definitely add some sanity to prevent buffer overflow. Or you may wish to use a dynamic buffer that grows as necessary.
An entire program that operates on standard I/O streams, plus handles arbitrary-length lines might look like this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
size_t capacity = 15, len = 0;
char *buf = malloc(capacity);
for (int c, dup = 0; (c = fgetc(stdin)) != EOF || len > 0; )
{
// Grow buffer
if (len == capacity)
{
capacity = (capacity * 2) + 1;
char *newbuf = realloc(buf, capacity);
if (!newbuf) break;
buf = newbuf;
dup = 0;
}
// NUL-terminate end of line, update duplicate-flag and store
if (c == '\n' || c == EOF)
c = '\0';
if (dup && buf[len] != c)
dup = 0;
buf[len++] = c;
// Output line if not a duplicate, and reset
if (!c)
{
if (!dup)
printf("%s\n", buf);
len = 0;
dup = 1;
}
}
free(buf);
}
Demo here: https://godbolt.org/z/GzGz3nxMK
If you must use the read and write system calls, you will have to build an abstraction around them, as they have no notion of lines, words, or characters. Semantically, they deal purely with bytes.
Reading arbitrarily-sized chunks of the file would require us to sift through looking for line breaks. This would mean tokenizing the data in our buffer, as you have somewhat shown. A problem occurs when our buffer ends with a partial line. We would need to make adjustments so our next read call concatenates the rest of the line.
To keep things simple, instead, we might consider reading the file one byte at a time.
A decent (if naive) way to begin is by essentially reimplementing the rough functionally of fgets. Here we read a single byte at a time into our buffer, at the current offset. We end when we find a newline character, or when we would no longer have enough room in the buffer for the null-terminating character.
Unlike fgets, here we return the length of our string.
size_t read_a_line(char *buf, size_t bufsize, int fd)
{
size_t offset = 0;
while (offset < (bufsize - 1) && read(fd, buf + offset, 1) > 0)
if (buf[offset++] == '\n')
break;
buf[offset] = '\0';
return offset;
}
To mimic uniq, we can create two buffers, as you have, but initialize their contents to empty strings. We take two additional pointers to manipulate later.
char buf[LINE_MAX] = { 0 };
char buf2[LINE_MAX] = { 0 };
char *flip = buf;
char *flop = buf2;
After opening our files for reading and writing, our loop begins. We continue this loop as long as we read a nonzero-length string.
If our current string does not match our previously read string, we write it to our output file. Afterwards, we swap our pointers. On the next iteration, from the perspective of our pointers, the secondary buffer now contains the previous line, and the primary buffer is overwritten with the current line.
Again, note that our initial previously read line is the empty string.
size_t length;
while ((length = read_a_line(flip, LINE_MAX, rfd))) {
if (0 != strcmp(flip, flop))
write(wfd, flip, length);
swap_two_pointers(&flip, &flop);
}
Our pointer swapping function.
void swap_two_pointers(char **a, char **b) {
char *t = *a;
*a = *b;
*b = t;
}
Some notes:
The contents of our file-to-be-read should never contains a line that would exceed LINE_MAX (including the newline character). We do not handle this situation, which is admittedly a sidestep, as this is the problem we wanted to avoid with the chunking method.
read_a_line should not be passed NULL or 0, to its first and second arguments. An exercise for the reader to figure out why that is.
read_a_line does not really handle read failing in the middle of a line.
I am newer in C language. I want to create an array for my code to make some operation. As I said above, I am trying to learn how to use C language efficiently. My problem is this: I have a input file, let's say input.txt. I know that every line have 4 different things, 2 of them are string and 2 of them number. Also, I want to create a 2D array. But I do not know how many lines will be in input file. It depends on the user. So, I have to use malloc to make my array dynamically. So, can you help me about this problem? Maybe this is so easy, but I think reading file and create some array in C more difficult than other languages. It was so easy in Python :( I am leaving my code below. If you tell me my mistakes, I will be happy :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[]) {
char *arrChar;
int i;
char *str;
char *token;
arrChar = (char *) malloc( sizeof( char ) );
str = (char *) malloc( sizeof( char ) );
FILE *FileChars;
FileChars = fopen( argv[1], "r");
i = 0;
while ( fgets(str, sizeof str, FileChars) != NULL) {
int j;
for ( j = 0; j < 4; j++ ) {
token = strtok(str, ",");
arrChar[i][j] = token;
}
i++;
}
}
You need to understand precisely what the sizeof operator does, it doesn't return the size of a dynamically allocated memory block, it returns the size of a type, in case of arrays — roughly speaking — the size is part of the type specification and so it returns the number of bytes the array occupies.
In your case sizeof(char) is the size of the type char which is required to be exactl 1 by the (c-standard C Standard).
And sizeof(str) is the size of the type of str which is char *, that is, the size of a pointer. It's probably 4 or 8 depending on your current platform.
To solve this, you have to define a length to be used throughout your program as the length of the allocated chunk of memory, that after you make sure that the allocation was successful (see below).
A pointer to char can point to a sequence of elements that can be interpreted as a string if it is the correct sequence. A sequence of "printable" characters followed by a '\0' or null character is considered a string.
You have to pass NULL to strtok() after the first time, if you are going to be processing the same string.
You should CHECK that fopen() did return a valid stream, by comparing the return value to NULL.
The same as (5), for malloc() when allocation is not possible NULL is returned and using it as a valid pointer is undefined behavior.
All that said, here is what you probably wanted to write
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_WORDS 100
int main(int argc, char const *argv[])
{
char *token;
char **words;
char line[100];
char *ptr;
size_t count;
FILE *file;
file = fopen( argv[1], "r");
// Check that we DID open the file
if (file == NULL) {
perror(argv[1]);
return EXIT_FAILURE;
}
// Allocate space for `NUM_WORDS' pointers
words = malloc(NUM_WORDS * sizeof(*words));
// Check that we did allocate enough memory
if (words == NULL) {
fclose(file);
return EXIT_FAILURE;
}
// We use `sizeof' here because `line' is an array
count = 0;
while ((count < NUM_WORDS) && (fgets(line, sizeof(line), file) != NULL)) {
ptr = line;
do {
token = strtok(ptr, ",");
// We need to copy the `token' because
// it lies within `line' and the '\0' will
// be replaced by the original character
// in subsequent callse to `strtok()'
//
// The `strdup()' will allocate enough space with
// `malloc()' then copy the contents of `token' to the
// allocated buffer, and return it, so we will
// have to call `free()' on every `words' element.
words[count++] = strdup(token);
// Subsequent calls to `strtok()' with the same
// string require that the first parameter is
// NULL
ptr = NULL;
} while ((count < NUM_WORDS) && (token != NULL));
}
// Now we may print the words and free the memory
for (size_t index = 0; index < count; ++index) {
puts(words[index]);
free(words[index]);
}
free(words);
return 0;
}
Note that the code above, makes sure that we don't exceed the capacity of the array of pointers words1. If you need to resize it, you will need to learn how to use realloc() and do it in a specialized routine so that your code doesn't become too complex.
1Note that the allocated space has no predefined interpretation, we do interpret it as an array but it's not an array in the c sense of an array definition, which line IS, having elements of type char, line can also be interpreted as a string given it has contents compatible with the defintion given in the (2) second point above.
I'm using C to read in an external text file. The input is not great and would look like;
0PAUL 22 ACACIA AVENUE 02/07/1986RN666
As you can see I have no obvious delimeter, and sometimes the values have no space between them. However I do know how long in character length each value should be when split. Which is as follows,
id = 1
name = 20
house number = 5
street name = 40
date of birth = 10
reference = 5
I've set up a structure I want to hold this information in, and have tried using fscanf to read in the file.
However I find something along the lines of just isn't doing what I need,
fscanf(file_in, "%1d, %20s", person.id[i], person.name[i]);
(The actual line I use attempts to grab all input but you should see where I'm going...)
The long term intention is to reformat the input file into another output file which would be made a little easier on the eye.
I appreciate I'm probably going about this all the wrong way, but I would hugely appreciate it if somebody could set me on the right path. If you're able to take it easy on me in regard to an obvious lack of understanding, I'd appreciate that also.
Thanks for reading
Use fgets to read each line at a time, then extract each field from the input line. Warning: no range checks is performed on buffers, so attention must be kept to resize buffers opportunely.
For example something like this (I don't compile it, so maybe some errors exist):
void copy_substr(const char * pBuffer, int content_size, int start_idx, int end_idx, char * pOutBuffer)
{
end_idx = end_idx > content_size ? content_size : end_idx;
int j = 0;
for (int i = start_idx; i < end_idx; i++)
pOutBuffer[j++] = pBuffer[i];
pOutBuffer[j] = 0;
return;
}
void test_solution()
{
char buffer_char[200];
fgets(buffer_char,sizeof(buffer_char),stdin); // use your own FILE handle instead of stdin
int len = strlen(buffer_char);
char temp_buffer[100];
// Reading first field: str[0..1), so only the char 0 (len=1)
int field_size = 1;
int filed_start_ofs = 0;
copy_substr(buffer_char, len, filed_start_ofs, filed_start_ofs + field_size, temp_buffer);
}
scanf is a good way to do it, you just need to use a buffer and call sscanf multiple times and give the good offsets.
For example :
char buffer[100];
fscanf(file_in, "%s",buffer);
sscanf(buffer, "%1d", person.id[i]);
sscanf(buffer+1, "%20s", person.name[i]);
sscanf(buffer+1+20, "%5d", person.street_number[i]);
and so on.
I feel like it is the easiest way to do it.
Please also consider using an array of your struct instead of a struct of arrays, it just feels wrong to have person.id[i] and not person[i].id
If you have fixed column widths, you can use pointer arithmetic to access substrings of your string str. if you have a starting index begin,
printf("%s", str + begin) ;
will print the substring beginning at begin and up to the end. If you want to print a string of a certain length, you can use printf's precision specifier .*, which takes a maximum length as additional argument:
printf("%.*s", length, str + begin) ;
If you want to copy the string to a temporary buffer, you could use strncpy, which will generate a null terminated string if the buffer is larger than the substring length. You could also use snprintf according to the above pattern:
char buf[length + 1];
snprintf(buf, sizeof(buf), "%.*s", length, str + begin) ;
This will extract leading and trailing spaces, which is probably not what you want. You could write a function to strip the unwanted whitespace; there should be plenty of examples here on SO.
You could also strip the whitespace when copying the substring. The example code below does this with the isspace function/macro from <ctype.h>:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int extract(char *buf, const char *str, int len)
{
const char *end = str + len;
int tail = -1;
int i = 0;
// skip leading white space;
while (str < end && *str && isspace(*str)) str++;
// copy string
while (str < end && *str) {
if (!isspace(*str)) tail = i + 1;
buf[i++] = *str++;
}
if (tail < 0) tail= i;
buf[tail] = '\0';
return tail;
}
int main()
{
char str[][80] = {
"0PAUL 22 ACACIA AVENUE 02/07/1986RN666",
"1BOB 1 POLK ST 01/04/1988RN802",
"2ALICE 99 WEST HIGHLAND CAUSEWAY 28/06/1982RN774"
};
int i;
for (i = 0; i < 3; i++) {
char *p = str[i];
char id[2];
char name[20];
char number[6];
char street[35];
char bday[11];
char ref[11];
extract(id, p + 0, 1);
extract(name, p + 1, 19);
extract(number, p + 20, 5);
extract(street, p + 25, 34);
extract(bday, p + 59, 10);
extract(ref, p + 69, 10);
printf("<person id='%s'>\n", id);
printf(" <name>%s</name>\n", name);
printf(" <house>%s</house>\n", number);
printf(" <street>%s</street>\n", street);
printf(" <birthday>%s</birthday>\n", bday);
printf(" <reference>%s</reference>\n", ref);
printf("</person>\n\n");
}
return 0;
}
There's a danger here, however: When you access a string at a certain position str + pos you should make sure that you don't go beyond the actual string length. For example, you string may be terminated after the name. When you access the birthday, you access valid memory, but it might contain garbage.
You can avoid this problem by padding the full string with spaces.
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?