reading csv to struct [duplicate] - c

This question already has answers here:
Reading and parsing lines from a file with fgets and strtok
(2 answers)
Closed 7 years ago.
I am trying to put textfile to the struct
have issues with assigning values form text file to the struct, it keeps printing me the last value being printed incompletely.
Can you kindly help me out with the issue?
Thank you in advance.
#include <stdio.h>
#include <stdlib.h>
#define MAX_LEN 422498
#define MAX_KEY 128
struct record
{
char* a;
char* b;
};
int main(int argc, char **argv){
char* input=argv[1];
char* output=argv[2];
char* buff[MAX_LEN];
char *delimiter = ";";
//printf("%s\n",input);
//printf("%s\n",output);
FILE *fp;
fp = fopen(input, "r"); //opening file*/
if( fp == NULL )
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
int rowsNum=0;
struct record* recArr = malloc(3 * sizeof (struct record));
//struct record recArr[4];
//recArr=malloc(1 * 2*sizeof(char*));
/*recArr[0].a="aa";
recArr[0].b="bb";
recArr[1].a="cc";
recArr[1].b="dd";
recArr[2].a="ee";
recArr[2].b="ff";
printf("%s\n", recArr[0].a);
printf("%s\n\n", recArr[0].b);
printf("%s\n", recArr[1].a);
printf("%s\n\n", recArr[1].b);
printf("%s\n", recArr[2].a);
printf("%s\n\n", recArr[2].b);*/
while (fgets(buff, MAX_LEN, (FILE*)fp)!=NULL)
{
//recArr=realloc(recArr, (rowsNum+1) * 2*sizeof(char*));
//char* Key = strtok(buff, delimiter);
//char* Value = strtok(NULL, delimiter);
recArr[rowsNum].a=strtok(buff, delimiter);
recArr[rowsNum].b=strtok(NULL, delimiter);
printf("%s\n", recArr[rowsNum].a);
printf("%s\n\n", recArr[rowsNum].b);
/*Key=NULL;
Value=NULL;*/
rowsNum++;
printf("%d\n", rowsNum);
}
fclose(fp);
int i;
for (i=0;i<3;i++)
{
printf("%s\n", recArr[i].a);
printf("%s\n\n", recArr[i].b);
}
//printf("%d\n", rowsNum);
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h> // this is needed to use strtok function (and strlen, strcpy)
#define MAX_LEN 422498
#define MAX_KEY 128
struct record
{
char* a;
char* b;
};
int main(int argc, char **argv){
char* input=argv[1];
char* output=argv[2];
char buff[MAX_LEN]; // buff should be char[MAX_LEN], not char*[MAX_LEN]
char *delimiter = ";";
//printf("%s\n",input);
//printf("%s\n",output);
FILE *fp;
fp = fopen(input, "r"); //opening file*/
if( fp == NULL )
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
int rowsNum=0;
struct record* recArr = malloc(3 * sizeof (struct record));
//struct record recArr[4];
//recArr=malloc(1 * 2*sizeof(char*));
/*recArr[0].a="aa";
recArr[0].b="bb";
recArr[1].a="cc";
recArr[1].b="dd";
recArr[2].a="ee";
recArr[2].b="ff";
printf("%s\n", recArr[0].a);
printf("%s\n\n", recArr[0].b);
printf("%s\n", recArr[1].a);
printf("%s\n\n", recArr[1].b);
printf("%s\n", recArr[2].a);
printf("%s\n\n", recArr[2].b);*/
while (fgets(buff, MAX_LEN, (FILE*)fp)!=NULL)
{
//recArr=realloc(recArr, (rowsNum+1) * 2*sizeof(char*));
//char* Key = strtok(buff, delimiter);
//char* Value = strtok(NULL, delimiter);
//recArr[rowsNum].a=strtok(buff, delimiter);
//recArr[rowsNum].b=strtok(NULL, delimiter);
// you have to COPY the string
char* a=strtok(buff, delimiter);
char* b=strtok(NULL, delimiter);
recArr[rowsNum].a = malloc(sizeof(char) * (strlen(a) + 1)); // +1 for terminating '\0'
recArr[rowsNum].b = malloc(sizeof(char) * (strlen(b) + 1));
strcpy(recArr[rowsNum].a, a);
strcpy(recArr[rowsNum].b, b);
printf("%s\n", recArr[rowsNum].a);
printf("%s\n\n", recArr[rowsNum].b);
/*Key=NULL;
Value=NULL;*/
rowsNum++;
printf("%d\n", rowsNum);
}
fclose(fp);
int i;
for (i=0;i<3;i++)
{
printf("%s\n", recArr[i].a);
printf("%s\n\n", recArr[i].b);
}
//printf("%d\n", rowsNum);
// you should free the allocated buffer
for (i=0;i<3;i++)
{
free(recArr[i].a);
free(recArr[i].b);
}
free(recArr);
}
string.h should be included to use strtok : GCC made some warnings about it.
the type of buff was not proper: it should be char buff[MAX_LEN], not char* buff[MAX_LEN](an extra asterisk is there)
the function strtok modifies the buffer given and returns the pointer that is pointing somewhere in the buffer. When reading the next line, the buffer is overwritten and the text previously read is lost unless it is copied to somewhere. For that reason, I added some code that copies the strings read and save pointers that points where the strings are copied instead of somewhere in buff.

Related

Dynamically increase array size in C using realloc

I'm trying to save the element of a file into an array of structs.
I want to dynamically increase the memory allocated in the array to fit just the total amount of lines (structs) in my file.
The .txt file looks like this:
R&B;6jvvpPJQJy5rMOEkLlADl6;Trey Songz
R&B;6p8JTP4A9NZHtxRVhkEo6s;T-Pain
R&B;3SwhPTNNU5hpF33bbCsji6;BJ The Chicago Kid
R&B;5yvhdo8FXbBsIllxv2Rr94;SZA
R&B;5Yq38evNk28qlTVHHtwBhT;James Blake
R&B;5yamjs92dcayRVlNuY116G;H.E.R.
R&B;4FjcZsKyGhhZnuYq0nzXpZ;T-Pain
R&B;22jnEneSABg4vRCR1vow7F;Daniel Caesar
R&B;57qiTKh8bVX0VtfUNTQqhw;The Weeknd
This is currently my code. (songFile and songsList does the same thing as genresList but is currently not implemented)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct genresFile{
char* genre;
char* idSong;
char* artist;
} genresFile;
typedef struct songsFile{
char* idSong;
int popularity;
char* mode;
} songsFile;
int main(int argc, char *argv[])
{
FILE* songs = fopen("songs.txt", "r");
FILE* genres = fopen("genres.txt", "r");
genresFile* genresList = NULL;
//songsFile* songsList = NULL;
char *buf = malloc(256);
char *tmp;
int i = 0;
while (fgets(buf, 255, genres)){
genresList = realloc(genresList, (i+1)*sizeof(genresFile));
if ((strlen(buf)>0) && (buf[strlen (buf) - 1] == '\n'))
buf[strlen (buf) - 1] = '\0';
genresFile object;
tmp = strtok(buf, ";");
object.genre = tmp;
tmp = strtok(NULL, ";");
object.idSong = tmp;
tmp = strtok(NULL, ";");
object.artist = tmp;
genresList[i] = object;
i++;
}
printf("%s, %s, %s\n",genresList[3].genre, genresList[3].idSong, genresList[3].artist);
free(genresList);
//free(songsList);
fclose(songs);
fclose(genres);
return 0;
}
This is the output I get from the print at the end:
Soul, qWZdkBl4UVPj9lK6HuuFM, r Thomas & The Volcanos
This is the last line of the .txt file and the artist's name is missing a letter at the beginning.
This is getting saved in every element of the array. Please help :D
Assigning pointers doesn't mean to copy strings.
The buffer buf is overwritten in the following lines, so what are pointed at by the pointers are also changed.
To avoid this, you should copy the strings instead of just assigning pointers.
It can be done like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct genresFile{
char* genre;
char* idSong;
char* artist;
} genresFile;
typedef struct songsFile{
char* idSong;
int popularity;
char* mode;
} songsFile;
char* copy_string(const char* str) {
char* copy = malloc(strlen(str) + 1); /* +1 for terminating null-character */
if (copy != NULL) strcpy(copy, str);
return copy;
}
int main(int argc, char *argv[])
{
FILE* songs = fopen("songs.txt", "r");
FILE* genres = fopen("genres.txt", "r");
genresFile* genresList = NULL;
//songsFile* songsList = NULL;
char *buf = malloc(256);
char *tmp;
int i = 0;
while (fgets(buf, 255, genres)){
genresList = realloc(genresList, (i+1)*sizeof(genresFile));
if ((strlen(buf)>0) && (buf[strlen (buf) - 1] == '\n'))
buf[strlen (buf) - 1] = '\0';
genresFile object;
tmp = strtok(buf, ";");
object.genre = copy_string(tmp);
tmp = strtok(NULL, ";");
object.idSong = copy_string(tmp);
tmp = strtok(NULL, ";");
object.artist = copy_string(tmp);
genresList[i] = object;
i++;
}
printf("%s, %s, %s\n",genresList[3].genre, genresList[3].idSong, genresList[3].artist);
free(genresList);
//free(songsList);
fclose(songs);
fclose(genres);
return 0;
}
You can use strdup() instead of this copy_string() if it is supported in your (target) environment.

strcpy giving me segmentation fault

I have code which is giving me a segmentation fault. I debugged it and and the error occurred when the strcpy executed. The code is attempting to extract data from a text file and store it into an array of structs. I plan to use strcpy to store the store the text file's data into the structs. Any idea why this is occurring?
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int input( char *s, int length);
void main(){
char *tok;
char *buffer;
size_t bufsize = 32;
size_t characters;
FILE *f;
char *file_name;
char line[255];
int currentRoom;
int count = 0;
typedef struct {
char room_n;
char description[100];
char room_north;
char room_south;
char room_west;
char room_east;
} room;
//Creating an array of structs
room record[1000];
while(1){
buffer = (char *)malloc(bufsize * sizeof(char));
if(buffer == NULL){
perror("Unable to allocate buffer");
exit(1);
}
printf("Enter a command: ");
characters = getline(&buffer, &bufsize, stdin);
if(strcmp(buffer,"exit\n") == 0){
printf("Exiting...\n");
exit(1);
}
tok = strtok(buffer, " \n"); // Tokenize input
printf("%s is the token \n", tok);
if (strcmp(tok,"loaddungeon") == 0){
file_name = strtok(NULL, "\n");
printf("file name : %s \n", file_name);
f = fopen(file_name,"r");
while (fgets(line, sizeof(line), f) != NULL)
{
char val1[128];
char val2[128];
char val3[128];
char val4[128];
char val5[128];
char val6[128];
strcpy(val1, strtok(line, "$"));
strcpy(val2, strtok(NULL, "$"));
strcpy(val3, strtok(NULL, " "));
strcpy(val4, strtok(NULL, " "));
strcpy(val5, strtok(NULL, " "));
strcpy(val6, strtok(NULL, " "));
//Segmentation fault error occurs here
strcpy(record[count].room_n, val1);
Definition of strcpy() is:
char *strcpy(char *dest, const char *src)
where-
dest -- This is the pointer to the destination array where the
content is to be copied.
src -- This is the string to be copied.
In your code arguments passed to strcpy() is char and char * :
strcpy(record[count].room_n, val1);
As defined in the structure:
typedef struct {
char room_n; //room_n declared as 'char'
char description[100];
char room_north;
char room_south;
char room_west;
char room_east;
} room;
Suggestion:
Allocate memory for room_n to point to. Change the declaration to
char room_n[128];

Parsing CSV data into structure

I have to put the data from a csv file (name, address, telephone...) to a structure of my C program. It's been unsuccessful, unfortunately. I tried using strtok function to break into tokens every time it finds a ";" (because we're dealing with a Comma Separated File).
Here's what I've done:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define MAX_STR_LEN 256
#define MAX_BOOKS 256
struct estrutura
{
int id;
char nome[40];
char endereco[40];
char cidade[40];
char pais[20];
char cep[10];
char nasc[12];
char telefone[14];
char total[20];
};
struct estrutura cliente[200];
FILE *pFile;
//allocate buffer in each line
char *buf = malloc(MAX_STR_LEN);
char *tmp;
void abrir();
/* Functions to be coded
int menu();
int menu2(); //manutencao de clientes
void adicionar();
void alterar();
void excluir();
void exibir();
void pesquisar(); */
main()
{
system("cls");
abrir();
//menu();
}
void abrir() //open the csv file and copy it to
{
/* FileStream for the Library File */
FILE *pFile;
/* allocation of the buffer for every line in the File */
char *buf = malloc(MAX_STR_LEN);
char *tmp;
/* if the space could not be allocated, return an error */
if (buf == NULL) {
printf ("No memory\n");
}
if ( ( pFile = fopen( "control.csv", "r" ) ) == NULL ) //Reading a file
{
printf( "File could not be opened.\n" );
}
int i = 0;
while (fgets(buf, 255, pFile) != NULL)
{
if ((strlen(buf)>0) && (buf[strlen (buf) - 1] == '\n')) //checa leitura
buf[strlen (buf) - 1] = '\0';
tmp = strtok(buf, ";");
cliente[i].id = atoi(tmp); //atoi for int
tmp = strtok(NULL, ";"); //use strcpy for char
strcpy(cliente[i].nome,tmp);
tmp = strtok(NULL, ";");
strcpy(cliente[i].endereco, tmp);
tmp = strtok(NULL, ";");
strcpy(cliente[i].cidade, tmp);
tmp = strtok(NULL, ";");
strcpy(cliente[i].pais, tmp);
tmp = strtok(NULL, ";");
strcpy(cliente[i].cep, tmp);
tmp = strtok(NULL, ";");
strcpy(cliente[i].nasc, tmp);
tmp = strtok(NULL, ";");
strcpy(cliente[i].telefone, tmp);
tmp = strtok(NULL, ";");
strcpy(cliente[i].total, tmp);
//tempBook.ID = atoi(buf); fix below
printf("%i, %s, %s, %s, %s, %s, %s, %s, %s \n",i, cliente[i].id , cliente[i].nome, cliente[i].endereco, cliente[i].cidade, cliente[i].pais, cliente[i].cep, cliente[i].nasc, cliente[i].telefone, cliente[i].total);
i++;
}
//free(buf);
fclose(pFile);
}
How can I solve this problem? I can't successfully copy the data from 100 clients in the csv to a structure.
Thank you since now!
There are three main problems here:
The format string in printf("%i, %s, %s, %s, ...) doesn't match the parameters, you need one more %i: printf("%i, %i, %s, %s, %s, ...).
In your code you never call abrir() but you call menu(), which doesn't exist, therefore your code doesn't even compile.
If you are on Windows (and only then) you need fopen(..., "rt")) instead of fopen(..., "r"))
Furthermore (not causing actual problems in your code):
char *buf = malloc(MAX_STR_LEN); can be replaced by char buf[MAX_STR_LEN];. It's pointless to allocate memory dynamically if the amount of memory is known at compile time. In that case you must of course not call free(buf) (which is commented out anyway).
Following declarations just after struct estrutura cliente[200]; are useless, you can remove them.
FILE *pFile;
//allocate buffer in each line
char *buf = (char*)malloc(MAX_STR_LEN);
char *tmp;
Otherwise the program should work fine unless your input file has fields that are larger than the field in your struct estrutura.

Pass array of struct and return array of struct using pointers - function

I realize this question has been asked often but I still dont really understand how it works. I want to try and read my file into my structures, inside a function and pass the structures through pointers to the function. I am unsure about how to even write the function prototype.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 90
#define STR 200
#define MAXLEN 40
struct human {
char name[MAXLEN];
char surname[MAXLEN];
int age;
float weight;
};
int main(int argc, char *argv[]) {
char *dlim= " ", *end = "\n";
char *string;
string = (char *)malloc(sizeof(char) * STR);
int i = 0, j = 0;
struct human *man = malloc(sizeof(struct human) * MAX);
FILE *fin = fopen("data.txt", "r");
if (fin == NULL) {
printf("Cannot open file\n");
exit(0);
}
while (fgets (string, STR, fin)){
read (string, &man[i], dlim, end);
i++;
}
fclose(fin);
free(string);
free(man);
return 0;
}
struct human *man read(char *fstring, struct *man, char *div, char *end){
int i=0;
char *tok;
tok = strtok(string, dlim);
strcpy(man[i].name, tok);
tok = strtok(NULL, dlim);
strcpy(man[i].surname,tok);
tok = strtok(NULL, dlim);
man[i].age = atoi(tok);
tok = strtok(NULL, end);
man[i].weight = atof(tok);
return man[i];
}
Whats the function meant to look like? And am i correct in assuming that through the use of pointers, the struct will be automatically be updated in main, without needing to return something in the function?
Can the function also return nothing (void), because the use of pointers will automatically pass onto main?
Thank you!
Your code is close but the pointer logic in the subroutine that fills in the human structure is incorrect. See if the following rework, and slight simplification, helps you understand how to pass the structure:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXIMUM_HUMANS 90
#define MAXIMUM_INPUT_STRING_LENGTH 200
#define MAXIMUM_STRING_LENGTH 40
struct human {
char name[MAXIMUM_STRING_LENGTH];
char surname[MAXIMUM_STRING_LENGTH];
int age;
float weight;
};
void initialize_human(char *string, struct human *man, char *delimiter, char *end) {
char *token;
token = strtok(string, delimiter);
strcpy(man->name, token);
token = strtok(NULL, delimiter);
strcpy(man->surname, token);
token = strtok(NULL, delimiter);
man->age = atoi(token);
token = strtok(NULL, end);
man->weight = atof(token);
}
int main(int argc, char *argv[]) {
char *dlim= " ", *end = "\n";
char string[MAXIMUM_INPUT_STRING_LENGTH];
struct human humans[MAXIMUM_HUMANS];
FILE *fin = fopen("data.txt", "r");
if (fin == NULL) {
fprintf(stderr, "Cannot open file\n");
exit(1);
}
int population; // after loop, this contains total body count
for (population = 0; fgets(string, MAXIMUM_INPUT_STRING_LENGTH, fin); population ++) {
initialize_human(string, &humans[population], dlim, end);
}
printf("population: %d\n", population);
printf("last added: %s who weighs %f\n", humans[population - 1].surname, humans[population - 1].weight); // test if we loaded it up correctly
fclose(fin);
return 0;
}

why segmentation fault? strtok and malloc

I have the following code which works perfectly when not using malloc, but when I want to add in dynamic memory allocation it says segmentation fault although it compiles without warnings or errors. Why?
Thanks in advance
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNUM 30
#define STR 200
#define MAXLEN 40
struct human { //Va
char name[MAXLEN];
char surname[MAXLEN];
int age;
float weight;
};
int main(int argc, char *argv[]) {
char *dlim= ",", *end = "\n", *stop = NULL;
char *tok, *string;
string = (char *)malloc(sizeof(char) * STR);
int i = 0, j = 0;
struct human man[MAXNUM];
FILE *fin = fopen("data.txt", "r");
if (string == NULL) {
printf("Memory not allocated");
}
if (fin == NULL) {
printf("Cannot open file\n");
exit(0);
}
while (fgets(string, sizeof(string), fin)) {
tok = strtok(string, dlim);
strcpy(man[i].name, tok);
tok = strtok(stop, dlim);
strcpy(man[i].surname,tok);
tok = strtok(stop, dlim);
man[i].age = atoi(tok);
tok = strtok(stop, dlim);
man[i].weight = atof(tok);
i++;
}
fclose(fin);
free(string);
j = i;
i = 0;
while (i < j) {
printf("%s %s %d %f \n", man[i].name, man[i].surname, man[i].age, man[i].weight);
i++;
}
return 0;
}
When you make string an allocated array of char, sizeof(string) no longer gives you the size of the array, it gives you the size of the pointer. Therefore you must change the loop to tell fgets the size of your array:
while (fgets(string, STR, fin)) {
...
Or better, if you reallocate the array to size size:
while (fgets(string, size, fin)) {
...

Resources