What am I trying:
To Load a csv file into memory of 2d array, then print the array to output.
The format in which I planned to load can be represented like the below give image:

In simple terms, the rows will be in a array where, each element of that array will be a pointer pointing to the columns of the row.
The columns will be an array where each element of that array will be pointing to the actual data.
Let me try explaining the blocks of my code before I post the actual code:
load_csv() : Function that accepts file name to load and returns a struct containing the 2d array, no of rows, no of columns. ( struct is named as FUNCTION_RETURN )
print() : Function to print array of characters.
copy_str() : Function that copies charecter from one location to other
print_data() : Function to print the 2d array
column_counter() : Function to count no of colums present in the csv file
free_procedure() : To free the 2d arrray from the memory after usage
Actual Code :
typedef struct function_return
{
int rows;
int columns;
char*** data_structure;
} FUNCTION_RETURN;
void print(const char* string1)
{
int iterator070 = 0;
while(string1[iterator070] != '\0')
{
printf("%c",string1[iterator070]);
iterator070 += 1;
}
}
int copy_str(char* destination,char* source,int src_len)
{
int iterator = 0;
while(iterator != (src_len + 1))
{
destination[iterator] = source[iterator];
iterator += 1;
}
destination[iterator] = '\0';
return SUCCESS;
}
void print_data(FUNCTION_RETURN data)
{
int row_iterator = 0;
int column_iterator = 0;
while(row_iterator < data.rows)
{
while(column_iterator < data.columns)
{
print(data.data_structure[row_iterator][column_iterator]);
printf(",");
column_iterator += 1;
}
printf("\n");
row_iterator += 1;
}
printf("\n");
}
int column_counter(FILE* file_handle)
{
int ch;
int returnable = 0; //returns no of columns
while((ch = fgetc(file_handle)) != '\n')
{
if(ch == ',')
{
returnable += 1;
}
}
returnable += 1;
fseek(file_handle,0,SEEK_SET); //set the seeker to the start of the file
return returnable;
}
void free_procedure(char ***returnable,int rows,int columns)
{
int row_iterator = 0, column_iterator = 0;
while(row_iterator < rows)
{
while(column_iterator < columns)
{
free(returnable[row_iterator][column_iterator]);
column_iterator += 1;
}
free(returnable[row_iterator]);
row_iterator += 1;
}
free(returnable);
printf("free_procedure done \n");
}
FUNCTION_RETURN load_data_CSV_v02(const char *Filename)
{
//open file
FILE *file_handle;
if((file_handle = fopen(Filename,"r")) == NULL)
{
printf("cant open file\n");
exit(1);
}
FUNCTION_RETURN returnable_structure;
char ***returnable; //holds the actual data in a multidimentional structure in memory
int row_iterator = 0;
int column_iterator = 0;
int no_of_rows = 1;
int ch; //charecter iterator
char file_buffer[200]; //will hold the text temporarily before transferring to returnable
int file_buffer_iterator = 0; //iterator for file_buffer
//create array of rows
returnable = (char***)malloc(sizeof(char**) * no_of_rows);
if(*returnable == NULL)
{
printf("error in allocating first row\n");
exit(1);
}
//create array of columns for the first row
returnable[row_iterator] = (char**)malloc(sizeof(char*) * (column_counter(file_handle) + 1));
if(*returnable[row_iterator] == NULL)
{
printf("error in allocating first 4 columns\n");
exit(1);
}
int column_counter_variable = column_counter(file_handle);
//since column counter function seeks to the start of the file, using the function directly
//in loop will cause to read the first row for all the iteration.
while((ch = fgetc(file_handle)) != EOF)
{
printf("ch : %c\n",ch);
if(ch == ',')
{
file_buffer[file_buffer_iterator] = '\0'; //null terminate the string
printf("word recieved :");
print(file_buffer);
printf("\n");
printf("row : %d , column : %d\n",row_iterator,column_iterator);
returnable[row_iterator][column_iterator] = (char*)malloc(sizeof(char) * strlen(file_buffer));
if(returnable[row_iterator][column_iterator] == NULL)
{
printf("error in allocating string");
exit(1);
}
copy_str(returnable[row_iterator][column_iterator],file_buffer,strlen(file_buffer));
printf("word found in structure :");
print(returnable[row_iterator][column_iterator]);
printf("\n");
file_buffer_iterator = 0; //set iterator to 0 to start recieving next word
column_iterator += 1;
}
else if(ch == '\n')
{
//end of column
//first execute the same in if(ch == ',') to copy the word to the data_structure
file_buffer[file_buffer_iterator] = '\0'; //null terminate the string
printf("word recieved :");
print(file_buffer);
printf("\n");
printf("row : %d , column : %d\n",row_iterator,column_iterator);
returnable[row_iterator][column_iterator] = (char*)malloc(sizeof(char) * strlen(file_buffer));
if(returnable[row_iterator][column_iterator] == NULL)
{
printf("error in allocating string");
exit(1);
}
copy_str(returnable[row_iterator][column_iterator],file_buffer,strlen(file_buffer));
printf("word found in structure :");
print(returnable[row_iterator][column_iterator]);
printf("\n");
file_buffer_iterator = 0;
//indicate the row is done
returnable[row_iterator][column_iterator] = (char*)malloc(sizeof(char));
*returnable[row_iterator][column_iterator] = '\n';
//set values
column_iterator = 0;
row_iterator += 1;
no_of_rows += 1;
//realoc the row array
returnable = (char***)realloc(returnable,sizeof(char**) * no_of_rows);
if(*returnable == NULL)
{
printf("cant reallocate\n");
}
//allocate column array
returnable[row_iterator] = (char**)malloc(sizeof(char*) * (column_counter_variable + 1));
if(*returnable[row_iterator] == NULL)
{
printf("error in allocating the 4 columns\n");
exit(1);
}
}
else
{
//get a single word
file_buffer[file_buffer_iterator] = ch;
file_buffer_iterator += 1;
}
}
printf("returnable before returned : \n");
print_data2(returnable,no_of_rows,column_counter_variable);
printf("\n-------------\n");
print(returnable[2][3]);
returnable_structure.rows = no_of_rows;
returnable_structure.columns = column_counter_variable; //column_counter(file_handle);
returnable_structure.data_structure = returnable;
free_procedure(returnable,no_of_rows,column_counter_variable);
printf("function ends\n");
return returnable_structure;
}
int main()
{
printf("log : (main) : start\n");
FUNCTION_RETURN result = load_data_CSV_v02("data.csv");
print_data(result);
printf("what the heck is happening here :)");
return 0;
}
As I have described what I intend to do and my code implementation, Let me tell you what is the issue here:
Take a look at the output
:
log : (main) : start
ch : R
ch : e
ch : d
ch : ,
word recieved :Red
row : 0 , column : 0
word found in structure :Red
ch : S
ch : p
ch : o
ch : r
ch : t
ch : s
ch : ,
word recieved :Sports
row : 0 , column : 1
word found in structure :Sports
ch : D
ch : o
ch : m
ch : e
ch : s
ch : t
ch : i
ch : c
ch : ,
word recieved :Domestic
row : 0 , column : 2
word found in structure :Domestic
ch : Y
ch : e
ch : s
ch :
word recieved :Yes
row : 0 , column : 3
word found in structure :Yes
ch : R
ch : e
ch : d
ch : ,
word recieved :Red
row : 1 , column : 0
word found in structure :Red
ch : S
ch : p
ch : o
ch : r
ch : t
ch : s
ch : ,
word recieved :Sports
row : 1 , column : 1
word found in structure :Sports
ch : D
ch : o
ch : m
ch : e
ch : s
ch : t
ch : i
ch : c
ch : ,
word recieved :Domestic
row : 1 , column : 2
word found in structure :Domestic
ch : N
ch : o
ch :
word recieved :No
row : 1 , column : 3
word found in structure :No
ch : R
ch : e
ch : d
ch : ,
word recieved :Red
row : 2 , column : 0
word found in structure :Red
ch : S
ch : p
ch : o
ch : r
ch : t
ch : s
ch : ,
word recieved :Sports
row : 2 , column : 1
word found in structure :Sports
ch : D
ch : o
ch : m
ch : e
ch : s
ch : t
ch : i
ch : c
ch : ,
word recieved :Domestic
row : 2 , column : 2
word found in structure :Domestic
ch : Y
ch : e
ch : s
ch :
word recieved :Yes
row : 2 , column : 3
word found in structure :Yes
ch : Y
ch : e
ch : l
ch : l
ch : o
ch : w
ch : ,
word recieved :Yellow
row : 3 , column : 0
word found in structure :Yellow
ch : S
ch : p
ch : o
ch : r
ch : t
ch : s
ch : ,
word recieved :Sports
row : 3 , column : 1
word found in structure :Sports
ch : D
ch : o
ch : m
ch : e
ch : s
ch : t
ch : i
ch : c
ch : ,
word recieved :Domestic
row : 3 , column : 2
word found in structure :Domestic
ch : N
ch : o
ch :
word recieved :No
row : 3 , column : 3
word found in structure :No
ch : Y
ch : e
ch : l
ch : l
ch : o
ch : w
ch : ,
word recieved :Yellow
row : 4 , column : 0
word found in structure :Yellow
ch : S
ch : p
ch : o
ch : r
ch : t
ch : s
ch : ,
word recieved :Sports
row : 4 , column : 1
word found in structure :Sports
ch : I
ch : n
ch : t
ch : e
ch : r
ch : n
ch : a
ch : t
ch : i
ch : o
ch : n
ch : a
ch : l
ch : ,
word recieved :International
row : 4 , column : 2
word found in structure :International
ch : Y
ch : e
ch : s
ch :
word recieved :Yes
row : 4 , column : 3
word found in structure :Yes
ch : Y
ch : e
ch : l
ch : l
ch : o
ch : w
ch : ,
word recieved :Yellow
row : 5 , column : 0
word found in structure :Yellow
ch : S
ch : U
ch : V
ch : ,
word recieved :SUV
row : 5 , column : 1
word found in structure :SUV
ch : I
ch : n
ch : t
ch : e
ch : r
ch : n
ch : a
ch : t
ch : i
ch : o
ch : n
ch : a
ch : l
ch : ,
word recieved :International
row : 5 , column : 2
word found in structure :International
ch : N
ch : o
ch :
word recieved :No
row : 5 , column : 3
word found in structure :No
ch : Y
ch : e
ch : l
ch : l
ch : o
ch : w
ch : ,
word recieved :Yellow
row : 6 , column : 0
word found in structure :Yellow
ch : S
ch : U
ch : V
ch : ,
word recieved :SUV
row : 6 , column : 1
word found in structure :SUV
ch : I
ch : n
ch : t
ch : e
ch : r
ch : n
ch : a
ch : t
ch : i
ch : o
ch : n
ch : a
ch : l
ch : ,
word recieved :International
row : 6 , column : 2
word found in structure :International
ch : Y
ch : e
ch : s
ch :
word recieved :Yes
row : 6 , column : 3
word found in structure :Yes
ch : Y
ch : e
ch : l
ch : l
ch : o
ch : w
ch : ,
word recieved :Yellow
row : 7 , column : 0
word found in structure :Yellow
ch : S
ch : U
ch : V
ch : ,
word recieved :SUV
row : 7 , column : 1
word found in structure :SUV
ch : D
ch : o
ch : m
ch : e
ch : s
ch : t
ch : i
ch : c
ch : ,
word recieved :Domestic
row : 7 , column : 2
word found in structure :Domestic
ch : N
ch : o
ch :
word recieved :No
row : 7 , column : 3
word found in structure :No
ch : R
ch : e
ch : d
ch : ,
word recieved :Red
row : 8 , column : 0
word found in structure :Red
ch : S
ch : U
ch : V
ch : ,
word recieved :SUV
row : 8 , column : 1
word found in structure :SUV
ch : I
ch : n
ch : t
ch : e
ch : r
ch : n
ch : a
ch : t
ch : i
ch : o
ch : n
ch : a
ch : l
ch : ,
word recieved :International
row : 8 , column : 2
word found in structure :International
ch : N
ch : o
ch :
word recieved :No
row : 8 , column : 3
word found in structure :No
ch : R
ch : e
ch : d
ch : ,
word recieved :Red
row : 9 , column : 0
word found in structure :Red
ch : S
ch : p
ch : o
ch : r
ch : t
ch : s
ch : ,
word recieved :Sports
row : 9 , column : 1
word found in structure :Sports
ch : I
ch : n
ch : t
ch : e
ch : r
ch : n
ch : a
ch : t
ch : i
ch : o
ch : n
ch : a
ch : l
ch : ,
word recieved :International
row : 9 , column : 2
word found in structure :International
ch : Y
ch : e
ch : s
returnable before returned :
row : 0
column : 0
Red,
column : 1
Sports,
column : 2
Domestic,
column : 3
rN┼┴,
row : 1
row : 2
row : 3
row : 4
row : 5
row : 6
row : 7
row : 8
row : 9
-------------
N┼┴free_procedure done
function ends
PN┼┴,`$N┼┴,Domestic, sN┼┴,
what the heck is happening here :)
As you can see, the output prints the stuff happening in loop that iterates through the csv file, Such as:
- The character that is being read from the csv file.
- The string present in the buffer before copying it to the 2d array. The string only gets printed if the loop encounters a ',' (comma) in the csv file
- The current row and column in which the loop is in
- The string present in the 2d array after copy_str() has copied the string from buffer to the array
After this, the array prints the array before returning the struct.
Then we print the array from main() function
What am I missing here ?, why is the data not printing correctly ? From the output, can I infer that I am accessing wrong memory locations out of the 2d array? and thats why am I seeing some symbols here?
For reference, Let me provide the csv file that I am working with:
Red,Sports,Domestic,Yes
Red,Sports,Domestic,No
Red,Sports,Domestic,Yes
Yellow,Sports,Domestic,No
Yellow,Sports,International,Yes
Yellow,SUV,International,No
Yellow,SUV,International,Yes
Yellow,SUV,Domestic,No
Red,SUV,International,No
Red,Sports,International,Yes
Also is this a good way to load csv into memory? Is there better ways?
Have a good day :)
print_data(returnable,no_of_rows,column_counter_variable);wherereturnableischar ***whenprint_datatakes typeFUNCTION_RETURNas the first argument. (your code hasprint_data2- either a typo, or function you forgot to write) So yes, printing will be off. Also in C, there is no need to cast the return ofmalloc, it is unnecessary. See: Do I cast the result of malloc?. There are a number of other suggestions, but fix the type issue first.-Wall -Wextra -pedanticto yourgcc/clangcompile string (also consider adding-Wshadowto warn on shadowed variables and-Werrorto treat warnings as errors). For VS (cl.exeon windows), use/W3. All other compilers will have similar options. Read and understand each warning -- then go fix it. The warnings will identify any problems, and the exact line on which they occur. You can learn a lot by listening to what your compiler is telling you.returnableafter free? E.g.returnable_structure.data_structure = returnable;thenfree_procedure(returnable,no_of_rows,column_counter_variable);Now when youreturn returnable_structure;and attempt to use it,returnable_structure.data_structureis a MEMORY USE AFTER FREE bug.returnable = malloc (sizeof *returnable * no_of_rows);(fixed cast and using dereferenced pointer for type-size), your test should beif (returnable == NULL), NOTif (*returnable == NULL). You have the same problem with thereturnable[row_iterator]allocation and test.'\0'), e.g. you havereturnable[row_iterator][column_iterator] = (char*)malloc(sizeof(char) * strlen(file_buffer));which should bereturnable[row_iterator][column_iterator] = malloc (strlen(file_buffer) + 1);NOTE,sizeof(char)is defined as1so just remove it, it is superfluous.