read csv file into 2-d array in c - c

I'm not familiar with C at all. I just need to input my data into an already well-developed model in C, put the data in arrays, get my output and put that output back into my program in Python. My data is in a CSV file and I'm just trying to put it in a 2-D array to run through some functions. When I run the following code to make sure I created my array, I get a random single value in the output that does not match the original data at all. Sometimes it prints 0.00000. I'm trying to view the entire array to make sure it's ready to be input.
Also, this is just a sample; my real data set will have >3000 rows. I understand I will need to use malloc() for this when I run my real data, correct?
#user3629249 thank you and #Cool Guy for all your comments. Here's what I have now. I think sprintf() is still having trouble converting my array values back to a float. I've searched all over and I still cant tell what I doing wrong but the error is telling me that data[l][k] and todata are still incompatible, could you tell me if I'm on the right track and what I'm doing wrong with the sprintf() function?
#include <stdio.h>
int main() {
FILE *fp;
fp=fopen("airvariablesSend.csv", "r");
if(fp == NULL){
printf("cannot open file\n\n");
return -1;
}
// Headers removed for simplicity. Still found in airvariables.csv to see which //column means what
float data[9][6]; //for putting into array
int k , l;
float num; //for using getline() function
char *memory;
int nbytes = 500;
// space for using malloc? Is this enough or too much?
char *token; //for parsing through line using strtok()
char *search = ","; //delimiter for csv
char *todata; //for
//asking for space on heap
memory = (char *) malloc (nbytes + 1);
// Don;t need to use realloc() because getline() does it automatically? //http://crasseux.com/books/ctutorial/getline.html
for(k = 0; k < 6 ; k++) //repeats for max number of columns
{
for (l=0; l< 9; l++) //modify for number of rows that you have
{
num = getline (&memory, &nbytes, fp); //reading line by line
token = strtok(num, search); //separating lines by comma in csv
//Apparently strtok() will only use whitespace and I'm getting warnings here too. Is there another function for separating by commas?
sprintf(todata, "%f", token);
data[l][k] = todata;
printf("%f\n", data[l][k]);
}
}
fclose(fp);
free(memory);
return 0;
}

Change
for (l=1; l< 11; l++)
To
for (l=0; l< 10; l++)
And
printf("%f\n", data[10][7]);
To
printf("%f\n", data[l][k]);
And move the printf just after
data[l][k] = num;
The former is done because array indices start from 0 and end at length-1.
The latter is done because you need to loop through the array to get each value that is stored in each index of the array and print it. You can't just use data[10][7] and expect the whole array to be printed. data[10][7] is an invalid location and accessing it invokes Undefined Behavior which means that anything can happen including segmentation faults, runtime errors, crashes etc.
Also, add a return -1; in the end of the body of the first if to end the execution of the program if the fopen failed to open its first argument.

Related

How do I read multiple floats from one line of a file

I have the following code which reads from a given input file into and then into struct I have made.
OFFFile ReadOFFFile(OFFFile fileData, FILE* srcFile)
{
int nvert, nfaces;
fscanf(srcFile, "%s\n");
fscanf(srcFile, "%d %d %s\n", &nvert, &nfaces);
fileData.nvert = nvert;
fileData.nfaces = nfaces;
fileData.vertices = (int *) malloc(fileData.nvert * sizeof(float));
fileData.triFaces = (int *) malloc(fileData.nfaces * sizeof(int));
// Print to check correct size was allocated
printf("%d\n", (fileData.nvert * sizeof(float)));
printf("%d\n", (fileData.nfaces * sizeof(int)));
int i;
float ftemp1, ftemp2, ftemp3;
int itemp1, itemp2, itemp3;
fscanf(srcFile, "%f", &ftemp1);
printf("%lf", ftemp1);
fscanf(srcFile, "%f", &ftemp2);
// fscanf(srcFile, " %lf", &ftemp3);
/* for (i = 0; i < nvert; ++i)
{
fscanf(srcFile, "%f %f %f\n", &ftemp1, &ftemp2, &ftemp3);
fileData.vertices[i].x = ftemp1;
fileData.vertices[i].y = ftemp2;
fileData.vertices[i].z = ftemp3;
}
*/
return(fileData);
}
The problem I am having is with the whole last section that is currently in quotes (The 2 fscanf lines above it are me attempting to test). If I have just one float being read it works fine, but when I add the second or third the whole function fails to even run, although it still compiles. I believe it to be caused by the negative sign in the input, but I don't know how I can fix it.
The data is in the form
OFF
4000 7000 0
0.8267261981964111 -1.8508968353271484 0.6781123280525208
0.7865174412727356 -1.8490413427352905 0.7289819121360779
With the floats continuing on for 4000 lines (hence for loop). These are the structs I have made
typedef struct
{
float x;
float y;
float z;
} Point3D;
typedef struct
{
int face1;
int face2;
int face3;
} triFace;
typedef struct
{
int nvert;
int nfaces;
Point3D *vertices;
triFace *triFaces;
} OFFFile;
Text dump of another file with a lot less lines, also does not work in the for loop. Only using this for testing. https://justpaste.it/9ohcc
Your main problem is the first line in the readOFFFile function:
fscanf(srcFile, "%s\n");
This tries to read a string (presumably the string OFF on the first line of the file), but you don't give fscanf any place to store the string, so it crashes. (As an aside, your compiler really should have warned you about this problem. If it didn't, it's old-fashioned, and there are lots of easy mistakes that it's probably not going to warn you about, and learning C is going to be much harder than it ought to be. Or perhaps you just need to find an option flag or checkbox to enable more warnings.)
You can tell fscanf to read and discard something, without storing it anywhere, using the * modifier. Here's a modified version of your program, that works for me.
void ReadOFFFile(OFFFile *fileData, FILE* srcFile)
{
fscanf(srcFile, "%*s");
if(fscanf(srcFile, "%d %d %*s", &fileData->nvert, &fileData->nfaces) != 2) {
exit(1);
}
fileData->vertices = malloc(fileData->nvert * sizeof(Point3D));
fileData->triFaces = malloc(fileData->nfaces * sizeof(triFace));
int i;
for (i = 0; i < fileData->nvert; ++i)
{
if(fscanf(srcFile, "%f %f %f", &fileData->vertices[i].x,
&fileData->vertices[i].y,
&fileData->vertices[i].z) != 3) {
exit(1);
}
}
}
I have made a few other changes. The other fscanf call, that reads three values but only stores two, also needs a * modifier. I check the return value of fscanf to catch errors (via a crude exit) if the input is not as expected. I got rid of the \n characters in the fscanf calls, since they're not necessary, and potentially misleading. I got rid of some unnecessary temporary variables, and I had the readOFFFile function accept a pointer to an OFFFile structure to fill in, rather than passing and returning it.
Here is the main program I tested it with:
int main()
{
OFFFile fd;
FILE *fp = fopen("dat", "r");
ReadOFFFile(&fd, fp);
for (int i = 0; i < fd.nvert; ++i)
printf("%f %f %f\n", fd.vertices[i].x, fd.vertices[i].y, fd.vertices[i].z);
}
This is still an incomplete program: there are several more places where you need to check for errors (opening the file, calling malloc, etc.), and when you do detect an error, you need to at least print a useful error message before exiting or whatever.
One more thing. As I mentioned, those \n characters you had in the fscanf format strings were unnecessary and misleading. To illustrate what I mean, once you get the program working, have it try to read a data file like this:
OFF 2 0
0 0.8267261981964111
-1.8508968353271484 0.6781123280525208
0.7865174412727356 -1.8490413427352905 0.7289819121360779
Totally malformed, but the program reads it without complaint! This is one reason (one of several dozen reasons, actually) why the scanf family of functions is basically useless for most things. These functions claim to "scan formatted data", but their definition of "formatted" is quite loose, in that they actually read free-form input, generally without any regard for line boundaries.
For some advice on graduating beyond scanf and using better, more reliable methods for reading input, see this question. See also this section and this section in some online C programming course notes.
The line:
fscanf(srcFile, "%s\n");
is invoking undefined behavior. The compiler should warn you about that. Once you've invoked UB, there's no point in speculating further about what is happening.
It's not clear to me what you intended that line to do, but if you use %s in a scanf, you need to give it a valid place to write data. You should always check the value returned by scanf to ensure that you have actually read some data, and you should never use "%s" without a width modifier. Perhaps you want something like:
char buf[256];
if( fscanf(srcFile, "%255s ", buf) == 1 ){
/* Do something with the string in buf */
}
From your comment, it seems that you are intending to use that scanf to skip a line. I strongly recommend using a while(fgetc) loop instead of scanf to do that. If you do want to use scanf, you could try something like fscanf(srcFile, "%*s\n"), but beware that it will stop at the first whitespace, and not necessarily consume an entire line. You could also do fscanf(srcFile, "%*[^\n]%*c"); to consume the line, but you are really better off using a fgetc in a while loop.
Addressing title question:
"How do I read multiple floats from one line of a file"
...with suggestions for a non-scanf() approach.
Assuming the file is opened, (and a file pointer) fp is obtained ) , the first two lines are already handled, and values into ints, say the lines value is converted to int lines;
And given your struct definition (modified to use double to accommodate type compatibility in code below):
typedef struct
{
double x;
double y;
double z;
} Point3D;
In a function somewhere here is one way to parse the contents of each data line into the 3 respective struct values using fgets(), strtok() and strtod():
char delim[] = " \n";
char *tok = NULL;
char newLine[100] = {0};
Point3D *point = calloc(lines, sizeof(*point));
if(point)
{
int i = 0;
while(fgets(newLine, sizeof newLine, fp))
{
tok = strtok(newLine, delim);
if(tok)
{
if(parseDbl(tok, &point[i].x))
{
tok = strtok(NULL, delim);
if(tok)
{
if(parseDbl(tok, &point[i].y))
{
tok = strtok(NULL, delim);
if(tok)
{
if(!parseDbl(tok, &point[i].z))
{
;//handle error
}else ;//continue
}else ;//handle error
}else ;//handle error
}else ;//handle error
}else ;//handle error
}else ;//handle error
i++;//increment for next read
}//end of while
}else ;//handle error
Where parseDbl is defined as:
bool parseDbl(const char *str, double *val)
{
char *temp = NULL;
bool rc = true;
errno = 0;
*val = strtod(str, &temp);
if (temp == str)
rc = false;
return rc;
}

Unable to write shell history to a text file

I'm currently writing a shell with basic functions in C, operating through Unix. I'm having difficulty transferring an array of history commands to a text file.
History is stored as a pointer to an array, with a capacity of 20 as not to over-complicate things. I got the basis of the method online so I've tried to tailor it to my needs, however it just feeds a bunch of weird characters to the text file.
Does anyone know why this may be happening?/What I could do to fix it?
I'm also not sure if the for loop is necessary.
Thanks in advance!
char *history[2];
void save(char ** history)
{
FILE *f;
f = fopen("history.txt", "w+");
for(int i = 0; i < 20; i++)
{
fwrite (history, sizeof(history[i]), sizeof(history)/sizeof(history[i]), f);
}
fclose(f);
}
history
is a char **, which is a pointertype.
history[i]
is char*, so still a pointertype
sizeof(history)/sizeof(history[i])
always returns one, since all pointertypes shall have the same size.
So your write statement will print sizeof(< anypointer >) random characters.
Solution
for(int i = 0; i < 20; i++){
fwrite (history[i], sizeof(*history[i]), strlen(history[i]) + 1, f);
}
Notice: This will include the '\0' for each string.
Notice: This will write the internal state into the file, so you should consider to open it in binary-mode or to use:
fputs(history[i], f);
fputc('\n', f); /*or anything similar*/

How do I read the contents of a file in C and store it into an array using fgets()?

So I need to create a word search program that will read a data file containing letters and then the words that need to be found at the end
for example:
f a q e g g e e e f
o e q e r t e w j o
t e e w q e r t y u
government
free
and the list of letters and words are longer but anyway I need to save the letters into an array and i'm having a difficult time because it never stores the correct data. here's what I have so far
#include <stdio.h>
int main()
{
int value;
char letters[500];
while(!feof(stdin))
{
value = fgets(stdin);
for(int i =0; i < value; i++)
{
scanf("%1s", &letters[i]);
}
for(int i=0; i<1; i++)
{
printf("%1c", letters[i]);
}
}
}
I also don't know how I am gonna store the words into a separate array after I get the chars into an array.
You said you want to read from a data file. If so, you should open the file.
FILE *fin=fopen("filename.txt", "r");
if(fin==NULL)
{
perror("filename.txt not opened.");
}
In your input file, the first few lines have single alphabets each separated by a space.
If you want to store each of these letters into the letters character array, you could load each line with the following loop.
char c;
int i=0;
while(fscanf(fin, "%c", &c)==1 && c!='\n')
{
if(c!=' ')
{
letters[i++]=c;
}
}
This will only store the letters and is not a string as there is no \0 character.
Reading the words which are at the bottom may be done with fgets().
Your usage of the fgets() function is wrong.
Its prototype is
char *fgets(char *str, int n, FILE *stream);
See here.
Note that fgets() will store the trailing newline(\n) into string as well. You might want to remove it like
str[strlen(str)-1]='\0';
Use fgets() to read the words at the bottom into a character array and replace the \n with a \0.
and do
fgets(letters, sizeof(letters, fin);
You use stdin instead of the fin here when you want to accept input from the keyboard and store into letters.
Note that fgets() will store the trailing newline(\n) into letters as well. You might want to remove it like
letters[strlen(letters)-1]='\0';
Just saying, letters[i] will be a character and not a string.
scanf("%1s", &letters[i]);
should be
scanf("%c", &letters[i]);
One way to store the lines with characters or words is to store them in an array of pointers to arrays - lines,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLET 500
#define MAXLINES 1000
int main()
{
char *lptr;
// Array with letters from a given line
char letters[MAXLET];
// Array with pointers to lines with letters
char *lineptr[MAXLINES];
// Length of current array
unsigned len = 0;
// Total number of lines
int nlines = 0;
// Read lines from stdin and store them in
// an array of pointers
while((fgets(letters,MAXLET,stdin))!=NULL)
{
len = strlen(letters);
letters[len-1] = '\0';
lptr = (char*) malloc(len);
strcpy(lptr, letters);
lineptr[nlines++]=lptr;
}
// Print lines
for (int i = 0; i < nlines; i++)
printf("%s\n", lineptr[i]);
// Free allocated memory
for (int i = 0; i < nlines; i++)
free(lineptr[i]);
}
In the following, pointer to every line from stdin is stored in lineptr. Once stored, you can access and manipulate each of the lines - in this simple case I only print them one by one but the examples of simple manipulation are shown later on. At the end, program frees the previously allocated memory. It is a good practice to free the allocated memory once it is no longer in use.
The process of storing a line consists of getting each line from the stdin, collecting it's length with strlen, stripping it's newline character by replacing it with \0 (optional), allocating memory for it with malloc, and finally storing the pointer to that memory location in lineptr. During this process the program also counts the number of input lines.
You can implement this sequence for both of your inputs - chars and words. It will result in a clean, ready to use input. You can also consider moving the line collection into a function, that may require making lineptr type arrays global. Let me know if you have any questions.
Thing to remember is that MAXLET and especially MAXLINES may have to be increased for a given dataset (MAXLINES 1000 literally assumes you won't have more than a 1000 lines).
Also, while on Unix and Mac this program allows you to read from a file as it is by using $ prog_name < in_file it can be readily modified to read directly from files.
Here are some usage examples - lineptr stores pointers to each line (array) hence the program first retrieves the pointer to a line and then it proceeds as with any array:
// Print 3rd character of each line
// then substitute 2nd with 'a'
char *p;
for (int i = 0; i < nlines; i++){
p = lineptr[i];
printf("%c\n", p[2]);
p[1] = 'a';
}
// Print lines
for (int i = 0; i < nlines; i++)
printf("%s\n", lineptr[i]);
// Swap first and second element
// of each line
char tmp;
for (int i = 0; i < nlines; i++){
p = lineptr[i];
tmp = p[0];
p[0] = p[1];
p[1] = tmp;
}
// Print lines
for (int i = 0; i < nlines; i++)
printf("%s\n", lineptr[i]);
Note that these examples are just a demonstration and assume that each line has at least 3 characters. Also, in your original input the characters are separated by a space - that is not necessary, in fact it's easier without it.
The code in your post does not appear to match your stated goals, and indicates you have not yet grasp the proper application of the functions you are using.
You have expressed an idea describing what you want to do, but the steps you have taken (at least those shown) will not get you there. Not even close.
It is always good to have a map in hand to plan to plan your steps. An algorithm is a kind of software map. Before you can plan your steps though, you need to know where you are going.
Your stated goals:
1) Open and read a file into lines.
2) Store the lines, somehow. (using fgets(,,)?)
3) Use some lines as content to search though.
4) Use other lines as objects to search for
Some questions to answer:
a) How is the search content distinguished from the strings to search
for?
b) How is the search content to be stored?
c) How are the search words to be stored?
d) How will the comparison between content and search word be done?
e) How many lines in the file? (example)
f) Length of longest line? (discussion and example) (e & f used to create storage)
g) How is fgets() used. (maybe a google search: How to use fgets)
h) Are there things to be aware of when using feof()? (discussion and examaple feof)
i) Why is my input not right after the second call to scanf? (answer)
Finish identifying and crystallizing the list of items in your goals, then answer these (and maybe other) questions. At that point you will be ready to start identifying the steps to get there.
value = fgets(stdin); is a terrible expression! You don't respect at all the syntax of the fgets function. My man page says
char *
fgets(char * restrict str, int size, FILE * restrict stream);
So here, as you do not pass the stream at the right place, you probably get an underlying io error and fgets returns NULL, which is converted to the int 0 value. And then the next loop is just a no-op.
The correct way to read a line with fgets is:
if (NULL == fgets(letters, sizeof(letters), stdin) {
// indication of end of file or error
...
}
// Ok letters contains the line...

how to read multiple files from a 2d array in C

i have to write a program that reads multiple files in a for loop and counts the words, sentences, and syllables of that file. My code in the function CountWords looks like this: (filenames is a 2d array with the names of the 17 files stored in it)
for (i = 0; i < 17; ++i) {
inputfile = fopen(filenames[i], "r");
if (inputfile == NULL) {
printf("File cannot be found, verify %s is in the correct location.\n", filenames[i]);
}
int c;
while (c != EOF) {
c = getc(inputfile);
//code to count words/syllables/sentences
}
fclose(inputfile);
While it successfully counts it for the file in the 0th element, the rest of them come out as zero words, zero sentences, zero syllables. Is there something I am doing wrong? thank you for your insight
You might try 'getc' rather than fscanf for reading single characters (if you're not reading UTF-8?) however I don't think that's the issue in this case.
If your current code is stopping after 2 files, perhaps the file doesn't exist or is not readable, in which case I believe the fopen would return null and set an error value in errno.
Your code (unless you've simplified it for the post) doesn't check for a failure result from the fopen, so it might crash with a segfault at that point.
To find out what's going on I'd suggest checking that all the filenames exist and are readable,
and in the code, add a check for the value of pInputFile
it's been a long time since I used C but something like this:
#include <errno.h>
pInputFile = fopen(inputFile,"r');
if(!pInputFile)
{
fprintf(STDERR, "Failed opening %s [error %d]",inputFile,errno());
return -1;
}
and then in your loop, check for the return value < 0
eg:
int count=0;
for (i = 0; i < 18; ++i) {
count = CountWords(filenames[i]);
if(count < 0)
{
//discard the result
}
else
{
// do something with the result
}
}
good luck
and as Hurlu pointed out, you've hard-coded the number of files in the loop as 18. perhaps that doesn't match the size of your array.
the usual convention in C would be to also pass to your function a number of items that are in the array, and use that in your for loop instead of the fixed number '18'
Also if your array of filenames is being populated by some other function,
it could have put an invalid name or null value into the array.
I can see two problems in the code you showed us here :
First, the way you cycle through your file names is hazardous, as you could very well run into a part of the 2D array that isn't initialized. Prefer filenames[i] != NULL as a stopping condition, and make sure the array is correctly initialized:
for (i = 0; filenames[i] != NULL; ++i) {
CountWords(filenames[i]);
}
Second, and that's the most important point, you are not checking your system call to fopen. Which means, your fscanf could very well be reading from a NULL pointer (what fopen returns in case the open failed).
If you get problems with your loops, try using printf to check your index, your fd, or whatever it is that could cause you problems; it is a good practice that will be useful to you in future debugging ;)

Array Not Filling Properly

I am trying to deconstruct a document into its respective paragraphs, and input each paragraphs, as a string, into an array. However, each time a new value is added, it overwrites all previous values in the array. The last "paragraph" read (as denoted by newline) is the value of each non-null value of the array.
Here is the code:
char buffer[MAX_SIZE];
char **paragraphs = (char**)malloc(MAX_SIZE * sizeof(char*));
int pp = 0;
int i;
FILE *doc;
doc = fopen(argv[1], "r+");
assert(doc);
while((i = fgets(buffer, sizeof(buffer), doc) != NULL)) {
if(strncmp(buffer, "\n", sizeof(buffer))) {
paragraphs[pp++] = (char*)buffer;
}
}
printf("pp: %d\n", pp);
for(i = 0; i < MAX_SIZE && paragraphs[i] != NULL; i++) {
printf("paragraphs[%d]: %s", i, paragraphs[i]);
}
The output I receive is:
pp: 4
paragraphs[0]: paragraph four
paragraphs[1]: paragraph four
paragraphs[2]: paragraph four
paragraphs[3]: paragraph four
when the program is run as follows: ./prog.out doc.txt, where doc.txt is:
paragraph one
paragraph two
paragraph three
paragraph four
The behavior of the program is otherwise desired. The paragraph count works properly, ignoring the line that contains ONLY the newline character (line 4).
I assume the problem occurs in the while loop, however am unsure how to remedy the problem.
Your solution is pretty sound. Your Paragraph array is supposed to hold each paragraph, and since each paragraph element is just a small 4 bytes pointer you can afford to define a reasonable max number of them. However, since this max number is a constant, it is of little use to allocate the array dynamically.
The only meaningful use of dynamic allocation would be to read the whole text once to count the actual number of paragraphs, allocate the array accordingly and re-read the whole file a second time, but I doubt this is worth the effort.
The downside of using fixed-size paragraph array is that you must stop filling it once you reach the maximal number of elements.
You can then re-allocate a bigger array if you absolutely want to be able to process the whole Bible, but for an educational exercise I think it's reasonable to just stop recording paragraphs (thus producing a code that can store and count paragraphs up to a maximal number).
The real trouble with your code is, you don't store the paragraph contents anywhere. When you read the actual lines, it's always inside the same buffer, so each paragraph will point to the same string, which will contain the last paragraph read.
The solution is to make a unique copy of the buffer and have the current paragraph point to that.
C being already messy enough as it is, I suggest using the strdup() function, which duplicates a string (basically computing string length, allocating sufficient memory, copying the string into it and returning the new block of memory holding the new copy). You just need to remember to free this new copy once you're done using it (in your case at the end of your program).
This is not the most time-efficient solution, since each string will require a strlen and a malloc performed internally by strdump while you could have pre-allocated a big buffer for all paragraphs, but it is certainly simpler and probably more memory-efficient (only the minimal amount of memory will be allocated for each string, though each malloc consumes a few extra bytes for internal allocator housekeeping).
The bloody awkward fgets also stores the trailing \n at the end of the line, so you'll probably want to get rid of that.
Your last display loop would be simpler, more robust and more efficient if you simply used pp as a limit, instead of checking uninitialized paragraphs.
Lastly, you'd better define two different constants for max line size and max number of paragraphs. Using the same value for both makes little sense, unless you're processing perfectly square texts :).
#define MAX_LINE_SIZE 82 // max nr of characters in a line (including trailing \n and \0)
#define MAX_PARAGRAPHS 100 // max number of paragraphs in a file
void main (void)
{
char buffer[MAX_LINE_SIZE];
char * paragraphs[MAX_PARAGRAPHS];
int pp = 0;
int i;
FILE *doc;
doc = fopen(argv[1], "r+");
assert(doc != NULL);
while((fgets(buffer, sizeof(buffer), doc) != NULL)) {
if (pp != MAX_PARAGRAPHS // make sure we don't overflow our paragraphs array
&& strcmp(buffer, "\n")) {
// fgets awkwardly collects the ending \n, so get rid of it
if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = '\0';
// current paragraph references a unique copy of the actual text
paragraphs[pp++] = strdup (buffer);
}
}
printf("pp: %d\n", pp);
for(i = 0; i != pp; i++) {
printf("paragraphs[%d]: %s", i, paragraphs[i]);
free(paragraphs[i]); // release memory allocated by strdup
}
}
What is the proper way to allocate the necessary memory? Is the malloc on line 2 not enough?
No, you need to allocate memory for the 2D array of strings you created. The following will not work as coded.
char **paragraphs = (char**)malloc(MAX_SIZE * sizeof(char*));
If you have: (for a simple explanation)
char **array = {0}; //array of C strings, before memory is allocation
Then you can create memory for it like this:
int main(void)
{
int numStrings = 10;// for example, change as necessary
int maxLen = MAX_SIZE; //for example, change as necessary
char **array {0};
array = allocMemory(array, numStrings, maxLen);
//use the array, then free it
freeMemory(array, numStrings);
return 0;
}
char ** allocMemory(char ** a, int numStrings, int maxStrLen)
{
int i;
a = calloc(sizeof(char*)*(numStrings+1), sizeof(char*));
for(i=0;i<numStrings; i++)
{
a[i] = calloc(sizeof(char)*maxStrLen + 1, sizeof(char));
}
return a;
}
void freeMemory(char ** a, int numStrings)
{
int i;
for(i=0;i<numStrings; i++)
if(a[i]) free(a[i]);
free(a);
}
Note: you can determine the number of lines in a file several ways, One way for example, by FILE *fp = fopen(filepath, "r");, then calling ret = fgets(lineBuf, lineLen, fp) in a loop until ret == EOF, keeping count of an index value for each loop. Then fclose(). (which you did not do either) This necessary step is not included in the code example above, but you can add it if that is the approach you want to use.
Once you have memory allocated, Change the following in your code:
paragraphs[pp++] = (char*)buffer;
To:
strcpy(paragraphs[pp++], buffer);//no need to cast buffer, it is already char *
Also, do not forget to call fclose() when you are finished with the open file.

Resources