I've debugged the heck out of this and cannot figure why my fgets is not working. Before I changed my code such that it dynamically resizes arrays, fgets works perfectly well. As I am a beginner in C, this problem has baffled me for quite a long time.
Here is the faulty code:
int readNumbers(int **array, char* fname, int hexFlag) {
int numberRead = 0;
FILE* fp;
int counter = 0;
char arr[100];
char* ptr;
size_t curSize = 16;
int radix = hexFlag ? 16 : 10;
*array = malloc(0 * sizeof(*array));
fp = fopen(fname, "r");
if (fp == NULL) {
printf("Error opening file\n");
return -1;
}
while (fgets(arr, sizeof(arr), fp)) { //Seg faults here when it reaches end of file.
ptr = strtok(arr, " \n");
while(ptr) {
if (counter >= curSize) {
curSize += 16;
array = realloc(*array, curSize * sizeof(**array));
}
(*array)[counter++] = strtol(ptr, NULL, radix);
++numberRead;
ptr = strtok(NULL , " \n");
}
}
if (ferror(fp)) {
fclose(fp);
return -1;
}
Here is the working code before the changes to make the array resize:
int readNumbers(int array[], char* fname, int hexFlag) {
int numberRead = 0;
FILE* fp;
int counter = 0;
char arr[100];
char* ptr;
fp = fopen(fname, "r");
if (fp == NULL) {
printf("Error opening file\n");
return -1;
}
while (fgets(arr, sizeof(arr), fp)) {
ptr = strtok(arr, " \n");
while(ptr) {
if (hexFlag == 0) {
array[counter++] = strtol(ptr , NULL , 10);
} else {
array[counter++] = strtol(ptr, NULL, 16);
}
++numberRead;
ptr = strtok(NULL , " \n");
}
}
if (ferror(fp)) {
fclose(fp);
return -1;
}
The newly added changes seg faults when the end of file is reached. I strongly suspect that this has to do with the double pointers. Any help is strongly appreciated!
Didn't went through whole code. But *array = malloc(0 * sizeof(*array)) here this malloc call will not allocate any memory.
In addition to the problem Amit Sharma pointed out:
You initially allocate your dynamic array using:
*array = malloc(0 * sizeof(*array));
And when you store into the dynamic array, you use:
(*array)[counter++] = strtol(ptr, NULL, radix);
However, your subsequent reallocations use:
array = realloc(*array, curSize * sizeof(**array));
which should likely be:
*array = realloc(*array, curSize * sizeof(*array));
Note that it's OK (unusual, but not unheard of) to use malloc(0), as long as your code is prepared to deal with a NULL pointer return or an allocation that can't be read from or written to.
Related
I'm somehow having troubles creating a dynamic array of strings in C. I'm not getting the expected results and I want to know why ?
readLine() function will read each line seperately and will do some changes if necessary :
char *readLine(FILE *f, size_t *len)
{
char *line = NULL;
ssize_t nread;
if (f == NULL)
{
return NULL;
}
if ((nread = getline(&line, len, f)) != -1)
{
if (line[nread - 1] == '\n')
{
line[strlen(line)-1] = '\0';
*len = strlen(line);
}
return line;
}
else
{
return NULL;
}
}
readFile() function will return an array of strings after reading all of the lines using readLine and then storing them into an array of strings :
char **readFile(const char *filename, size_t *fileLen)
{
char *result;
int idx = 0;
char **array = calloc(1, sizeof(char*) );
if (filename == NULL || fileLen == NULL)
{
return NULL;
}
FILE *f = fopen(filename, "r");
if (f == NULL)
{
return NULL;
}
while (1)
{
result = readLine(f, fileLen);
if (result == NULL)
break;
else
{
*(array + idx) = malloc(LENGTH * sizeof(char *));
strncpy(array[idx], result, strlen(result) + 1);
idx++;
array = realloc(array, (idx + 1) * sizeof(char *));
}
}
return array;
}
In main I created a temporary file to test my functions but it didn't work properly :
int main()
{
char filename[] = "/tmp/prefXXXXXX";
int fd;
size_t len = 0;
FILE *f;
if (-1 == (fd = mkstemp(filename)))
perror("internal error: mkstemp");
if (NULL == (f = fdopen(fd, "w")))
perror("internal error: fdopen");
for (int i = 0; i < 10000; i++)
fprintf(f, "%d\n", i);
fclose(f);
char **number = readFile(filename, &len);
for (int i = 0; i < sizeof(number) / sizeof(number[0]); i++)
printf("number[%i] = %s\n", i, number[i]);
return 0;
}
When I execute the program, I get the following output:
number[0] = 0
What am I doing wrong here ?
There are lots of issues in that code, it's difficult to find where to start...
Let's look at each function.
char *readLine(FILE *f, size_t *len)
{
char *line = NULL;
ssize_t nread;
if (f == NULL)
{
return NULL;
}
if ((nread = getline(&line, len, f)) != -1)
{
if (line[nread - 1] == '\n')
{
line[strlen(line)-1] = '\0';
*len = strlen(line);
}
return line;
}
else
{
return NULL;
}
}
There is not much wrong here. But manpage for geline tells us:
If *lineptr is set to NULL before the call, then getline() will
allocate a buffer for storing the line. This buffer should be
freed by the user program even if getline() failed.
You do not free the buffer if nread==-1 but only do return NULL; possibly causing a memory leak.
You should also check whether len==NUL as you already do it with f.
Then look at the next function:
char **readFile(const char *filename, size_t *fileLen)
{
char *result;
int idx = 0;
char **array = calloc(1, sizeof(char*) );
if (filename == NULL || fileLen == NULL)
{
return NULL;
}
FILE *f = fopen(filename, "r");
if (f == NULL)
{
return NULL;
}
while (1)
{
result = readLine(f, fileLen);
if (result == NULL)
break;
else
{
*(array + idx) = malloc(LENGTH * sizeof(char *));
strncpy(array[idx], result, strlen(result) + 1);
idx++;
array = realloc(array, (idx + 1) * sizeof(char *));
}
}
return array;
}
In this function you fail to free(array) in case you hit a return NULL; exit.
readLine puts strlen(result) into filelen. Why don't you use it to allocate memory? Instead you take some unknown fixed length LENGTH that may or may not be sufficient to hold the string. Instead you should use fileLen+1 or strlen(result)+1 as you do it with strncpy.
You are also using size of wrong type. You allocate a pointer to char, not char*. As size of char is defined to be 1 you can just drop the size part here.
Then, the length parameter for strncpy should hold the length of the destination, not the source. Otherwise it is completely useless to use strncpy at all.
As you already (should) use the string length to allocate the memory, just use strncpy.
Then, just passing fileLen to the next function does not make sense. In readLine it means length of a line while in readFile that would not make any sense. Instead it should mean number of lines. And as we just came to the topic... You should pass some value to the caller.
Finally, you should not assign the return value of realloc directly to the varirable you passed into it. In case of an error, NULL is returned and you cannot access or free the old pointer any longer.
This block should look like this:
{
array[idx] = malloc(fileLen+1);
strcpy(array[idx], result);
idx++;
void *temp = realloc(array, (idx + 1) * sizeof(char *));
if (temp != NULL)
array = temp;
// TODO: else <error handling>
}
}
*fileLen = idx;
return array;
}
This still has the flaw that you have allocated memory for one more pointer that you do not use. You can change this as further optimization.
Lastly the main function:
int main()
{
char filename[] = "/tmp/prefXXXXXX";
int fd;
size_t len = 0;
FILE *f;
if (-1 == (fd = mkstemp(filename)))
perror("internal error: mkstemp");
if (NULL == (f = fdopen(fd, "w")))
perror("internal error: fdopen");
for (int i = 0; i < 10000; i++)
fprintf(f, "%d\n", i);
fclose(f);
char **number = readFile(filename, &len);
for (int i = 0; i < sizeof(number) / sizeof(number[0]); i++)
printf("number[%i] = %s\n", i, number[i]);
return 0;
}
char **number = readFile(filename, &len); You get an array holding all the lines of a file. number is a very poor name for this.
You return NULL from readFile in case of an error. You should check for that after calling.
Then you forgot that arrays are not pointers and pointers are not arrays. They behave similar in many places but are very different at the same time.
i < sizeof(number) / sizeof(number[0])
Here number is a pointer and its size of the size of a pointer. Also number[0] is a pointer again. Different type, but same size.
What you want is the number of lines which you get from readFile. Use that variable.
This part should look like this:
char **all_lines = readFile(filename, &len);
if (all_lines != NULL)
{
for (int i = 0; i < len; i++)
printf("all_lines[%i] = %s\n", i, all_lines[i]);
And you should not forget that you have allocated a lot of memory which you should also free.
(This might not strictly be necessary when you terminate your program, but you should keep in mind to clean up behind you)
if (all_lines != NULL)
{
for (int i = 0; i < len; i++)
printf("all_lines[%i] = %s\n", i, all_lines[i]);
for (int i = 0; i < len; i++)
free(all_lines[i];
free(all_lines);
}
I'm trying to read the following file line by line into an array of strings where each line is an element of the array:
AATGC
ATGCC
GCCGT
CGTAC
GTACG
TACGT
ACGTA
CGTAC
GTACG
TACGA
ACGAA
My code is as follows:
void **get_genome(char *filename) {
FILE *file = fopen(filename, "r");
int c;
int line_count = 0;
int line_length = 0;
for (c = getc(file); c != EOF; c = getc(file)) {
if (c == '\n') line_count++;
else line_length++;
}
line_length /= line_count;
rewind(file);
char **genome = calloc(line_length * line_count, sizeof(char));
for (int i = 0; i < line_count; i++) {
genome[i] = calloc(line_length, sizeof(char));
fscanf(file, "%s\n", genome[i]);
}
printf("%d lines of %d length\n", line_count, line_length);
for (int i = 0; i < line_count; i++)
printf("%s\n", genome[i]);
}
However, for some reason I get garbage output for the first 2 elements of the array. The following is my output:
`NP��
�NP��
GCCGT
CGTAC
GTACG
TACGT
ACGTA
CGTAC
GTACG
TACGA
ACGAA
You seem to assume that all lines have the same line length. If such is the case, you still have some problems:
the memory for the row pointers is allocated incorrectly, it should be
char **genome = calloc(line_count, sizeof(char *));
or better and less error prone:
char **genome = calloc(line_count, sizeof(*genome));
the memory for each row should be one byte longer the the null terminator.
\n is the fscanf() format string matches any sequence of whitespace characters. It is redundant as %s skips those anyway.
it is safer to count items separated by white space to avoid miscounting the items if the file contains any blank characters.
you do not close file.
you do not return the genome at the end of the function
you do not check for errors.
Here is a modified version:
void **get_genome(const char *filename) {
FILE *file = fopen(filename, "r");
if (file == NULL)
return NULL;
int line_count = 1;
int item_count = 0;
int item_length = -1;
int length = 0;
int c;
while ((c = getc(file)) != EOF) {
if (isspace(c)) {
if (length == 0)
continue; // ignore subsequent whitespace
item_count++;
if (item_length < 0) {
item_length = length;
} else
if (item_length != length) {
printf("inconsistent item length on line %d\", line_count);
fclose(file);
return NULL;
}
length = 0;
} else {
length++;
}
}
if (length) {
printf("line %d truncated\n", line_count);
fclose(file);
return NULL;
}
rewind(file);
char **genome = calloc(item_count, sizeof(*genome));
if (genome == NULL) {
printf("out of memory\n");
fclose(file);
return NULL;
}
for (int i = 0; i < item_count; i++) {
genome[i] = calloc(item_length + 1, sizeof(*genome[i]));
if (genome[i] == NULL) {
while (i > 0) {
free(genome[i]);
}
free(genome);
printf("out of memory\n");
fclose(file);
return NULL;
}
fscanf(file, "%s", genome[i]);
}
fclose(file);
printf("%d items of %d length on %d lines\n",
item_count, item_length, line_count);
for (int i = 0; i < item_count; i++)
printf("%s\n", genome[i]);
return genome;
}
char **genome = calloc(line_length * line_count, sizeof(char));
must be
char **genome = calloc(line_count, sizeof(char*));
or more 'secure'
char **genome = calloc(line_count, sizeof(*genome));
in case you change the type of genome
else the allocated block if not enough long if you are in 64b because line_count is 5 rather than 8, so you write out of it with an undefined behavior
You also need to return genome at the end of the function
It was also possible to not count the number of lines and to use realloc to increment your array when reading the file
As I see the lines have the same length. Your function should inform the caller how many lines have been read. There is no need of reading the file twice. There is no need of calloc (which is more expensive function). Always check the result of the memory allocation functions.
Here is a bit different version of the function:
char **get_genome(char *filename, size_t *line_count) {
FILE *file = fopen(filename, "r");
int c;
size_t line_length = 0;
char **genome = NULL, **tmp;
*line_count = 0;
if(file)
{
while(1)
{
c = getc(file);
if( c == EOF || c == '\n') break;
line_length++;
}
rewind(file);
while(1)
{
char *line = malloc(line_length + 1);
if(line)
{
if(!fgets(line, line_length + 1, file))
{
free(line);
break;
}
line[line_length] = 0;
tmp = realloc(genome, (*line_count + 1) * sizeof(*genome));
if(tmp)
{
genome = tmp;
genome[*line_count] = line;
*line_count += 1;
}
else
{
// do some memory free magic
}
}
}
fclose(file);
}
return genome;
}
So I have this bit of code
int main(int argc, char *argv[]) {
char *vendas[1];
int size = 1;
int current = 0;
char buffer[50];
char *token;
FILE *fp = fopen("Vendas_1M.txt", "r");
while(fgets(buffer, 50, fp)) {
token = strtok(buffer, "\n");
if (size == current) {
*vendas = realloc(*vendas, sizeof(vendas[0]) * size * 2);
size *= 2;
}
vendas[current] = strdup(token);
printf("%d - %d - %s\n", current, size, vendas[current]);
current++;
}
}
Here's the thing... Using GDB it's giving a segmentation fault on
vendas[current] = strdup(token);
but the weirdest thing is it works up until the size it at 1024. The size grows up to 1024 and then it just spits a segmentation fault at around the 1200 element.
I know the problem is on the memory reallocation, because it worked when I had a static array. Just can't figure out what.
You cannot reallocate a local array, you want vendas to be a pointer to an allocated array of pointers: char **vendas = NULL;.
You should also include the proper header files and check for fopen() and realloc() failure.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
void free_array(char **array, size_t count) {
while (count > 0) {
free(array[--count]);
}
free(array);
}
int main(int argc, char *argv[]) {
char buffer[50];
char **vendas = NULL;
size_t size = 0;
size_t current = 0;
char *token;
FILE *fp;
fp = fopen("Vendas_1M.txt", "r");
if (fp == NULL) {
printf("cannot open file Vendas_1M.txt\n");
return 1;
}
while (fgets(buffer, sizeof buffer, fp)) {
token = strtok(buffer, "\n");
if (current >= size) {
char **savep = vendas;
size = (size == 0) ? 4 : size * 2;
vendas = realloc(vendas, sizeof(*vendas) * size);
if (vendas == NULL) {
printf("allocation failure\n");
free_array(savep, current);
return 1;
}
}
vendas[current] = strdup(token);
if (vendas[current] == NULL) {
printf("allocation failure\n");
free_array(vendas, current);
return 1;
}
printf("%d - %d - %s\n", current, size, vendas[current]);
current++;
}
/* ... */
/* free allocated memory (for cleanliness) */
free_array(vendas, current);
return 0;
}
You only have room for one (1) pointer in you array of char *vendas[1]. So second time around you are outside the limits of the array and are in undefined behavior land.
Also, the first call to realloc passes in a pointer that was not allocated by malloc so there is another undefined behavior.
I want to sort strings from file; this code compiles well, but it stops working in line 29, when I do words_array[i] = strdup(line);.
From debugger I have "program received signal sigsegv segmentation fault"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int comparator ( const void * elem1, const void * elem2 )
{
return strcmp( *(const char**) elem1, *(const char**) elem2);
}
int main()
{
char filename[]="dane.txt";
FILE* fp;
char* line = NULL;
size_t len = 0;
char** words_array = NULL;
int i = 0,j; // number of elements
// read list from file
if( ( fp = fopen(filename, "r") ) == NULL ) {
fprintf(stderr, "Cannot open source file %s!\n", filename);
exit(1);
}
for(; fgets(line, len, fp) != NULL; ++i) {
// put word in array
words_array = realloc(words_array, sizeof(char*) * (i + 1) );
words_array[i] = strdup(line);
}
fclose(fp);
free(line);
// sort it
qsort(words_array, i, sizeof(char*), comparator);
if( ( fp = fopen(filename, "a+") ) == NULL ) {
fprintf(stderr, "Cannot open source file %s!\n", filename);
exit(1);
}
// write to file and free dynamically allocated memory
for(j = 0; j < i; ++j) {
fprintf(fp, "%s", words_array[j]);
free(words_array[j]);
}
free(words_array);
fclose(fp);
return 0;
}
You never allocated space for line to point to.
I have a csv file having values
1,A,X
2,B,Y
3,C,Z
I have to read the CSV file line by line and keep it in a Structure array.
The values are going fine each time in the for loop. But at the end when I am printing the Array, only the last value is being printed.
Somebody please tell me where am I doing the logical error?
struct proc
{
char *x;
char *y;
};
void main()
{
fflush(stdin);
fflush(stdout);
const char s[2] = ",";
char *token;
int rows=0,i,tokenVal=0,rowCount=0;
FILE *fpCount = fopen("data.csv","r");
if(fpCount != NULL)
{
char lineCount[20];
while(fgets(lineCount, sizeof lineCount, fpCount))
rows++;
}
struct proc *pi[rows];
for(i=0;i<rows;i++)
pi[i] = (struct proc*) malloc(sizeof(struct proc));
FILE *fp = fopen("data.csv", "r");
if(fp != NULL)
{
char line[20];
while(fgets(line, sizeof line, fp) != NULL)
{
printf("Start rowCount = %d\t",rowCount);
token = strtok(line, s);
while(token!=NULL)
{
if(tokenVal==0)
{
pi[rowCount]->Id =token;
}
if(tokenVal==1)
{
pi[rowCount]->act = token;
}
printf("\n");
tokenVal++;
token = strtok(NULL,s);
}
tokenVal = 0;
printf("end rowCount = %d\t",rowCount);
rowCount++;
}
fclose(fp);
} else {
perror("data.csv");
}
printf("total %d",rowCount);
int k=0;
for(k=0;k<rowCount;k++)
{
printf(" %d = %s----%s",k,pi[k]->Id,pi[k]->act);
}
}
Diagnosis
The fundamental problem you face is that you are saving pointers to the variable line in your structures, but each new line overwrites what was previously in line, so at the end, only data from the last line is present. It is fortuitous that your lines of data are all the same 'shape'; if the fields were of different lengths, you'd have more interesting, but equally erroneous, results.
Consequently, you need to save a copy of each field, not simply a pointer to the field. The simple way to do that is with POSIX function strdup(). If you don't have the function, you can create it:
char *strdup(const char *str)
{
size_t len = strlen(str) + 1;
char *rv = malloc(len);
if (rv != 0)
memmove(rv, str, len); // or memcpy
return rv;
}
Your code doesn't compile; your data structure has elements x and y but your code uses elements Id and act. You use a VLA of pointers to your struct proc, but it would be sensible to allocate an array of the structure, either as a VLA or via malloc() et al. You should check memory allocations — there isn't a way to check VLAs, though (one reason to use dynamic allocation instead). You could rewind the file instead of reopening it. (It's a good idea to use a variable to hold the file name, even if you only open it once; it makes error reporting better. Also, errors should stop the program, in general, though you did use perror() if the reopen operation failed — but not if the open failed.) You don't need two arrays into which to read the lines. It's a good idea to use far longer buffers for input lines. You should free dynamically allocated memory. Also, see What should main() return in C and C++?; the answer is int and not void (unless perhaps you are on Windows).
Here are three variants of your code, with various aspects of the issues outlined above more or less fixed.
VLA of pointers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct proc
{
char *x;
char *y;
};
int main(void)
{
const char datafile[] = "data.csv";
const char csv_delim[] = ",\n";
int rows = 0, rowCount = 0;
FILE *fpCount = fopen(datafile, "r");
if (fpCount == NULL)
{
fprintf(stderr, "Failed to open '%s' for reading\n", datafile);
exit(EXIT_FAILURE);
}
char lineCount[2000];
while (fgets(lineCount, sizeof(lineCount), fpCount))
rows++;
fclose(fpCount);
printf("Read %d rows from '%s'\n", rows, datafile);
struct proc *pi[rows];
for (int i = 0; i < rows; i++)
pi[i] = (struct proc *)malloc(sizeof(struct proc));
FILE *fp = fopen(datafile, "r");
if (fp == NULL)
{
fprintf(stderr, "Failed to reopen '%s' for reading\n", datafile);
exit(EXIT_FAILURE);
}
char line[2000];
while (fgets(line, sizeof(line), fp) != NULL)
{
printf("Start rowCount = %d\t", rowCount);
int tokenVal = 0;
char *token = strtok(line, csv_delim);
while (token != NULL)
{
if (tokenVal == 0)
{
pi[rowCount]->x = strdup(token);
}
else if (tokenVal == 1)
{
pi[rowCount]->y = strdup(token);
}
printf("[%s]", token);
tokenVal++;
token = strtok(NULL, csv_delim);
}
printf("\tend rowCount = %d\n", rowCount);
rowCount++;
}
fclose(fp);
/* Data validation */
printf("total %d\n", rowCount);
for (int k = 0; k < rowCount; k++)
{
printf("%d = [%s]----[%s]\n", k, pi[k]->x, pi[k]->y);
}
/* Release allocated memory */
for (int k = 0; k < rowCount; k++)
{
free(pi[k]->x);
free(pi[k]->y);
free(pi[k]);
}
return 0;
}
VLA of structures
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct proc
{
char *x;
char *y;
};
int main(void)
{
const char datafile[] = "data.csv";
const char csv_delim[] = ",\n";
int rows = 0, rowCount = 0;
FILE *fpCount = fopen(datafile, "r");
if (fpCount == NULL)
{
fprintf(stderr, "Failed to open '%s' for reading\n", datafile);
exit(EXIT_FAILURE);
}
char lineCount[2000];
while (fgets(lineCount, sizeof(lineCount), fpCount))
rows++;
fclose(fpCount);
printf("Read %d rows from '%s'\n", rows, datafile);
struct proc pi[rows];
FILE *fp = fopen(datafile, "r");
if (fp == NULL)
{
fprintf(stderr, "Failed to reopen '%s' for reading\n", datafile);
exit(EXIT_FAILURE);
}
char line[2000];
while (fgets(line, sizeof(line), fp) != NULL)
{
printf("Start rowCount = %d\t", rowCount);
int tokenVal = 0;
char *token = strtok(line, csv_delim);
while (token != NULL)
{
if (tokenVal == 0)
{
pi[rowCount].x = strdup(token);
}
else if (tokenVal == 1)
{
pi[rowCount].y = strdup(token);
}
printf("[%s]", token);
tokenVal++;
token = strtok(NULL, csv_delim);
}
printf("\tend rowCount = %d\n", rowCount);
rowCount++;
}
fclose(fp);
/* Data validation */
printf("total %d\n", rowCount);
for (int k = 0; k < rowCount; k++)
{
printf("%d = [%s]----[%s]\n", k, pi[k].x, pi[k].y);
}
/* Release allocated memory */
for (int k = 0; k < rowCount; k++)
{
free(pi[k].x);
free(pi[k].y);
}
return 0;
}
Dynamic array of structures
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct proc
{
char *x;
char *y;
};
int main(void)
{
const char datafile[] = "data.csv";
const char csv_delim[] = ",\n";
int num_rows = 0, rowCount = 0;
FILE *fp = fopen(datafile, "r");
if (fp == NULL)
{
fprintf(stderr, "Failed to open '%s' for reading\n", datafile);
exit(EXIT_FAILURE);
}
char line[2000];
while (fgets(line, sizeof(line), fp))
num_rows++;
rewind(fp);
printf("Read %d rows from '%s'\n", num_rows, datafile);
struct proc *pi = calloc(num_rows, sizeof(*pi));
if (pi == 0)
{
fprintf(stderr, "Failed to allocate %zu bytes of memory\n", num_rows * sizeof(*pi));
exit(EXIT_FAILURE);
}
while (fgets(line, sizeof(line), fp) != NULL)
{
printf("Start rowCount = %d\t", rowCount);
int tokenVal = 0;
char *token = strtok(line, csv_delim);
while (token != NULL)
{
if (tokenVal == 0)
{
pi[rowCount].x = strdup(token);
// null check
}
else if (tokenVal == 1)
{
pi[rowCount].y = strdup(token);
// null check
}
printf("[%s]", token);
tokenVal++;
token = strtok(NULL, csv_delim);
}
printf("\tend rowCount = %d\n", rowCount);
rowCount++;
}
fclose(fp);
/* Data validation */
printf("total %d\n", rowCount);
for (int k = 0; k < rowCount; k++)
{
printf("%d = [%s]----[%s]\n", k, pi[k].x, pi[k].y);
}
/* Release allocated memory */
for (int k = 0; k < rowCount; k++)
{
free(pi[k].x);
free(pi[k].y);
}
free(pi);
return 0;
}
Given a data file:
1,A,X
2,B,Y
3,C,Z
3192-2146-9913,Abelone,Zoophyte
all three programs produce the same output:
Read 4 rows from 'data.csv'
Start rowCount = 0 [1][A][X] end rowCount = 0
Start rowCount = 1 [2][B][Y] end rowCount = 1
Start rowCount = 2 [3][C][Z] end rowCount = 2
Start rowCount = 3 [3192-2146-9913][Abelone][Zoophyte] end rowCount = 3
total 4
0 = [1]----[A]
1 = [2]----[B]
2 = [3]----[C]
3 = [3192-2146-9913]----[Abelone]
In the printf(" %d = %s----%s----%s",k,pi[k]->Id,pi[k]->act);
There are four data
%d
%s
%s
%s
but you set only three
k
pi[k]->Id
pi[k]->act