Splitting string from file and then storing into a structure - c

I have data structure I have to add into a linked list. The data structure would come from a file with an input like this for example:
I0001|Item 1|Item 1 Desc|3.50|50
I0002|Item 2|Item 2 Desc|3.00|20
I0003|Item 3|Item 3 Desc|4.00|10
The structure:
typedef struct stock
{
char id[ID_LEN + NULL_SPACE];
char name[NAME_LEN + NULL_SPACE];
char desc[DESC_LEN + NULL_SPACE];
Price price;
unsigned onHand;
} Stock;
My code so far is this:
Boolean loadStock(VmSystem * system, const char * fileName)
{
Stock data;
char id[ID_LEN + NULL_SPACE], name[NAME_LEN + NULL_SPACE], desc[DESC_LEN + NULL_SPACE];
FILE *fp;
char str[200], *token;
if((fp = fopen(fileName, "r")) != NULL)
{
printf("File loaded\n");
}
else
{
perror("Cannot open file");
return FALSE;
}
if (fgets(str,sizeof(str),fp) == NULL)
{
perror("failed to read from file");
return FALSE;
}
while(fgets(str,sizeof(str),fp) != NULL)
{
token = strtok(str, "|");
while(token != NULL)
{
/** DO SOMETHING HERE **/
printf("%s\n", token);
token = strtok(NULL,"|");
}
}
fclose(fp);
return TRUE;
}
I wrote this but it doesn't work:
if(i%5 == 0)
{
strcpy(id, token);
}
else if(i%5 == 1)
{
strcpy(name, token);
}
else if(i%5 == 2)
{
strcpy(desc, token);
}
printf("%s\n", id);
token = strtok(NULL,"|");
i++;
memset(id, '\0', sizeof(id));
memset(name, '\0', sizeof(name));
memset(desc, '\0', sizeof(desc));
I am having some issues taking the token and using it to store values into the structure

You could read each line from the file with fgets() into a string str and use sscanf() to read from that string.
I assume that Price is a typedef for float.
Let s be a variable of type struct stock.
char str[200], pt[2][20];
Stock s;
fgets(str, sizeof(str), fp);
sscanf(str, "%[^|]|%[^|]|%[^|]|%[^|]|%[^|]", s.id, s.name, s.desc, pt[0], pt[1]);
The %[^|] means read till encountering a |. Read more about it here
The price and onHand elements are stored in pt[0] and pt[1] respectively in string form.
String conversion to float is done using strtof() while conversion to unsigned long is done using strtoul()
s.price=strtof(pt[0], NULL);
s.onHand=strtoul(pt[1], NULL, 10);
If you are worried about using strtoul(), which returns an unsigned long int instead of an unsigned int, you could first check if the value returned by strtoul() is greater than UINT_MAX.
UINT_MAX is the maximum value that can be stored in an unsigned int.
It is defined in limits.h.

Related

Reading dynamic length comma separated values using fscanf

I have a txt file which contains patient details separated by commas
I want to read each value store that in a structure. But, the problem is that some of the entries contain 3 values and the others contain 4.
ENTRIES IN TXT FILE are:
1032,Pugsley Yanson,CELL,3048005191
1048,Banjo Codi,TBD,
1056,Lettuce Peas,WORK,7934346809
My Code looks like :
`struct Phone
{
char description[PHONE_DESC_LEN];
char number[PHONE_LEN];
};
// Data type: Patient
struct Patient
{
int patientNumber;
char name[NAME_LEN];
struct Phone phone;
};
void importPatients(const char* datafile, struct Patient patients[], int max){
FILE *fp = fopen(datafile, "r");
int i = 0;
int read = 0;
while (!feof(fp) && i < max){
read = fscanf(fp,"%d,%14[^,],%4[^,],%10[^,]\n",&patients[i].patientNumber,patients[i].name,patients[i].phone.description,patients[i].phone.number);
if(read == 0 && !feof(fp)){
fclose(fp);
return;
}
i++;
}
fclose(fp);
}
This code works perfectly when reading entries with 4 values but fails as soon as it encounters an entry with 3 values like: 1048,Banjo Codi,TBD,
How can this be fixed or is there a better approach to solve this problem?
At least these issues
Inconsistent ,
Sometimes a line of data ends with a final field, sometimes not.
1032,Pugsley Yanson,CELL,3048005191
1048,Banjo Codi,TBD,
Avoid line ending problems: read the line with fgets() and then parse.
Why is “while( !feof(file) )” always wrong?
Be sure char buffers are big enough
#define NAME_LEN (14 + 1)
#define PHONE_DESC_LEN ( 4 + 1)
#define PHONE_LEN (10 + 1)
Weak test
Do not test against 1 possible undesired return value. read could be other than 0 or 4. Test against desired return value.
// if(read == 0
if(read != 4
[Needs re-work, re-work done below]
Alternate:
char buf[100];
while (i < max && fgets(buf, sizeof buf, fp)){
int read = sscanf(buf,"%d , %14[^,], %4[^,], %10[^,]",
&patients[i].patientNumber, patients[i].name,
patients[i].phone.description, patients[i].phone.number);
if (read != 4) {
report_error();
} else {
i++;
}
}
fclose(fp);
[Update]
Untested sample code to better handle empty fields. Likely deserves more testing - later.
// Return patient count. -1 implies error
int importPatients(const char *datafile, struct Patient patients[], int max) {
FILE *fp = fopen(datafile, "r");
if (fp == NULL) {
return -1;
}
char buf[100];
int i = 0;
while (i < max && fgets(buf, sizeof buf, fp)) {
const char *token = strtok(buf, ',');
if (token == NULL) {
return -1;
}
patients[i].patientNumber = aoti(token); // Better code would use strtol()
token = strtok(buf, ',');
if (token == NULL) {
return -1;
}
snprintf(patients[i].name, sizeof patients[i].name, "%s", token); // TBD, check return value to buffer fit.
token = strtok(buf, ',');
if (token == NULL) {
return -1;
}
snprintf(patients[i].phone.description,
sizeof patients[i].phone.description, "%s", token);
token = strtok(buf, '\n');
if (token == NULL) {
return -1;
}
snprintf(patients[i].phone.number, sizeof patients[i].phone.number, "%s",
token);
i++;
}
fclose(fp);
return i;
}

How to edit .csv files in C

I'm new at programming, and I need help in my C project. I have to search for a city, confirm it exists in the first file (city.csv), and take its id from there. Then I have to match that id with the corresponding one in the second file (meteo.csv), and then edit its weather information, that is in that second file. However, I don't know how I can take the city id from the first file, and then how to edit the second file after obtaining all the new weather informations. Here is the code:
void addInfo() {
FILE * fp;
char id_city[100];
char city[100];
char humidity[100];
char temp_max[100];
char temp_min[100];
char pressure[100];
char date[100];
printf("Name of the city: ");
scanf("%s", city);
// I think it's here that I have to write the code for take the city's id from the first file
if (id_city != NULL) {
printf("Maximun temperature: ");
scanf("%s", temp_max);
printf("Minimun temperature: ");
scanf("%s", temp_min);
printf("Humidity: ");
scanf("%s", humidity);
printf("Pressure: ");
scanf("%s", pressure);
printf("Date, in the format YYYY-MM-DD: ");
scanf("%s", date);
fp = fopen ("meteo.csv", "a");
fprintf(fp, "%s, %s, %s, %s, %s \n", temp_max, temp_min, humidity, pressure, date); //I think there's something wrong here too...
fclose(fp);
printf("Information edited successfully");
}
The file city.csv has 152 lines and 4 columns:
(id_city,city,county,district)
such as
(56,Lisbon,Lisbon,Lisbon)
The file meteo.csv has 152 lines and 7 columns:
(id_meteo_city,id_city,temp_max,temp_min,humidity,pressure,date)
such as
(56,56,14,5,62,1025,2018-02-12)
The first thing I would do is encapsulate the data in a struct, that makes it
easier to map a line of a CSV file into an object representing a line.
If both files city.csv and meteo.csv have different columns, I'd create a
different struct for each file. If both files have the same columns, you could
use the struct. I assume that both files are different and that city has the
format meteo_id,city_id,name.
typedef struct city_t {
int meteo_id;
int city_id;
char name[100]; // no city should have
// longer than 100 chars
} city_t;
typedef struct meteo_t {
int meteo_id;
int city_id;
int tempt_max;
int tempt_mix;
double humidity;
double preassure;
char date[11];
} meteo_t;
Let's assume that both files are well formatted, otherwise you would have to
write code that checks for errors and handles them, that would be the next step
in the exercise, so I'm going to write only the basic version with basic error
recognition.
#include <stdio.h>
#include <string.h>
#include <errno.h>
// takes 2 params, the filename and a pointer
// to size_t where the number of cities is stored
city_t *read_cities(const char *filename, size_t *len)
{
if(filename == NULL || len == NULL)
return NULL;
FILE *fp = fopen(filename, "r");
if(fp == NULL)
{
fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
return NULL;
}
city_t *arr = NULL, *tmp;
*len = 0;
// assuming that no line will be longer than 1023 chars long
char line[1024];
while(fgets(line, sizeof line, fp))
{
tmp = realloc(arr, (*len + 1) * sizeof *arr);
if(tmp == NULL)
{
fprintf(stderr, "could not parse the whole file %s\n", filename);
// returning all parsed cities so far
if(*len == 0)
{
free(arr);
arr = NULL;
}
return arr;
}
arr = tmp;
// %99[^\n] is to read up to 99 characters until the end of the line
if(sscanf(line, "%d,%d,%99[^\n]", &(arr[*len].meteo_id),
&(arr[*len].city_id), arr[*len].name) != 3)
{
fprintf(stderr, "Invalid line format (skipping line):\n%s\n", line);
// skip this line, and decrement *len
(*len)--;
continue;
}
// incrementing only when parsing of line was OK
(*len)++;
}
fclose(fp);
// file is empty or
// all lines have wrong format
if(*len == 0)
{
free(arr);
arr = NULL;
}
return arr;
}
void print_cities(city_t *cities, size_t len, FILE *fp)
{
if(cities == NULL || fp == NULL)
return;
for(size_t i = 0; i < len; ++i)
fprintf(fp, "%d,%d,%s\n", cities[i].meteo_id, cities[i].citiy_id,
cities[i].name);
}
Now I've written the read and write functions for the file citiy.csv assuming the
format meteo_id;city_id;name. The print_cities allows you to print the CSV
content on the screen (passing stdout as the last argument) or to a file
(passing a FILE object as the last argument).
You can use these functions as templates for reading and writing meteo.csv, the
idea is the same.
You can use these function as follows:
int main(void)
{
size_t cities_len;
city_t *cities = read_cities("city.csv", &cities_len);
// error
if(cities == NULL)
return 1;
do_something_with_cities(cities, cities_len);
// update csv
FILE *fp = fopen("city.csv", "w");
if(fp == NULL)
{
fprintf(stderr, "Could not open city.csv for reading: %s\n",
strerror(errno));
free(cities);
return 1;
}
print_cities(cities, cities_len, fp);
fclose(fp);
free(cities);
return 0;
}
Now for your exercise: write a similar function that parses meteo.csv (using
my function as a template shouldn't be that difficult) and parse both files. Now
that you've got them in memory, it's easy to manipulate the data (insert,
update, delete). Then write the files like I did in the example and that's it.
One last hint: how to search for a city:
// returns the index in the array or -1 on error or when not found
int search_for_city_by_name(city_t *cities, size_t len, const char *name)
{
if(cities == NULL || name == NULL)
return -1;
for(size_t i = 0; i < len; ++i)
if(strcmp(name, cities[i].name) == 0)
return i;
// not found
return -1;
}
Now I have given you almost all parts of the assignment, all you have to do is
stick them together and write the same functions for the meteo.csv file.
To edit one field:
void _ERR(char a) {
if (a == "f") printf("\n\tError File !!\n\n");
if (a == "m") printf("\n\tError Memory !!\n\n");
exit(1); }
char* stmm(const char* src) {
char* dst = malloc(strlen(src) + 1);
if (dst == NULL) return NULL;
strcpy(dst, src);
return dst; }
const char* getfield(char* line, int num) {
const char* tok;
for (tok = strtok(line, ",");
tok && *tok;
tok = strtok(NULL, ",\n"))
{
if (!--num)
return tok;
}
return NULL; }
void edit_file(char* FName, char* NewValue, int row, int col) {
int i, r = 0, c;
char line[1024];
FILE* fr, * fw;
fr = fopen(FName, "r");
fw = fopen(FName, "r+");
if (fr == NULL|| fw == NULL) _ERR("f");
while (fgets(line, 1024, fr))
{
char* tmp = stmm(line);
if (tmp == NULL) _ERR("m");
for (i = 0, c = 1; i < strlen(tmp); i++) {
if (tmp[i] == 44) c++;
}
for (i = 0; i < c; i++) {
if (r == row && i+1 == col) {
fprintf(fw,"%s", NewValue);
} else {
free(tmp);
tmp = stmm(line);
if (tmp == NULL) _ERR("m");
fprintf(fw,"%s", getfield(tmp, i + 1));
}
(i < c - 1) ? fprintf(fw,",") : fprintf(fw,"\n");
}
free(tmp);
r++;
}
fclose(fr);
fclose(fw); }
edit_file(".\FileName.csv","NewValue",Row,Column);

Segmentation Fault in C using fgets(), strtok(), strcpy()

I am getting a seg fault from the code shown below. I am trying to create a simple database that reads a stdin from a bin file chops it up by commas, throws each value into an array and throws it in a struct. I want to do this for every line in the standard input and then write the struct to a file at the end.
I am calling this loadDatabase function from main.
The data looks like the following in one line and is about 14 lines long:
34156155,MILES,NORMA,TAMMY,n/a,9/16/1964,FEMALE,123-45-6789,LAGUARDIA RD,SHLT,10915,n/a,n/a,CHESTER,NY,848-896-8296,n/a,NMILES#AMGGT.COM,n/a
Here is my current code. Please excuse me if my C is really bad. First time...:
struct _record {
char ID[25];
char lname[25]; // last name
char fname[25]; // first name
char mname[25]; // middle name
char suffix[25];
char bday[25];
char gender[25];
char SSN[25];
char add1[25]; //address 1
char add2[25]; //address 2
char zip[25];
char maiden[25];
char MRN[25];
char city[25];
char state[25];
char phone1[25];
char phone2[25];
char email[25];
char alias[25];
};
bool loadDatabase(char *db_name) {
printf("Loading Database...");
char buffer[400];
FILE *fp;
int x;
fp = fopen(db_name, "wb"); //write & binary option
if (fp == NULL) {
puts(" ERROR: FILE CANNOT BE OPENED");
return false;
} else {
struct _record record;
while (fgets(rec, sizeof(rec), stdin) != NULL) {
value = strtok(NULL, ",");
flds[0] = strdup(value);
//load lname
value = strdup(NULL, ",");
flds[1] = strdup(value);
// load fname
value = strdup(NULL, ",");
flds[2] = strdup(value);
// load mname
value = strtok(NULL, "\n");
flds[3] = strdup(value);
// did not write the rest bc of the seg fault
strcpy(record.ID, flds[0]);
strcpy(record.lname, flds[1]);
strcpy(record.fname, flds[2]);
strcpy(record.mname, flds[3]);
strcpy(record.suffix, flds[4]);
strcpy(record.bday, flds[5]);
strcpy(record.gender, flds[6]);
strcpy(record.SSN, flds[7]);
strcpy(record.add1, flds[8]);
strcpy(record.add2, flds[9]);
strcpy(record.zip, flds[10]);
strcpy(record.maiden, flds[11]);
strcpy(record.MRN, flds[12]);
strcpy(record.city, flds[13]);
strcpy(record.state, flds[14]);
strcpy(record.phone1, flds[15]);
strcpy(record.phone2, flds[16]);
strcpy(record.email, flds[17]);
strcpy(record.alias, flds[18]);
}
printf("ID: %s", record.ID);
fwrite(record, sizeof(struct _record), 1, fp);
fclose(fp);
}
return true;
}
There are multiple problems in your code:
the definition of fld is not provided. It should be defined as a local array of 19 char *:
char *fld[19];
you have some cut+paste bugs: value = strdup(NULL, ","); instead of value = strtok(NULL, ",");
many lines are missing.
you never test if strtok() returns NULL. Invalid input will cause undefined behavior
memory for the strings is unnecessary: you can just copy the string directly into the record field.
you do not check the length of the strings before copying them with strcpy. Invalid input may cause buffer overflows.
the argument to fwrite should be the address of the record, not its value:
fwrite(&record, sizeof(struct _record), 1, fp);
using strtok() (or sscanf() with %[^,] conversion specifiers) does not handle empty fields correctly: strtok() will consider any sequence of , as a single separator (%[^,] will not match an empty field either). I suggest using a function for this.
the record structure should be cleared before each line to avoid storing uninitialized contents into the database file.
To avoid some of these problems, you should raise the warning level and let the compiler produce diagnostics for common programming errors: gcc -Wall -Wextra -Werror or clang -Weverything or cl /W4.
Here is an improved version:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
struct _record {
char ID[25];
char lname[25]; // last name
char fname[25]; // first name
char mname[25]; // middle name
char suffix[25];
char bday[25];
char gender[25];
char SSN[25];
char add1[25]; //address 1
char add2[25]; //address 2
char zip[25];
char maiden[25];
char MRN[25];
char city[25];
char state[25];
char phone1[25];
char phone2[25];
char email[25];
char alias[25];
};
bool loadField(char *dest, int size, char **cursorp) {
bool truncated = false;
int i = 0;
char *p;
for (p = *cursorp; *p != '\0' && *p != '\n'; p++) {
if (*p == ',') {
p++; // skip the comma separator
break;
}
if (i + 1 < size) {
dest[i] = *p;
} else {
truncated = 1;
}
i++;
}
// pad the field with null bytes
while (i < size) {
dest[i++] = '\0';
}
*cursorp = p;
if (truncated) {
fprintf(stderr, "field too long: %.*s\n", i, *cursorp);
return false;
} else {
return true;
}
}
bool loadDatabase(const char *db_name) {
char buffer[1000];
FILE *fp;
printf("Loading Database...");
fp = fopen(db_name, "wb"); //write & binary option
if (fp == NULL) {
fprintf(stderr, "error: cannot open file %s: %s\n", db_name, strerror(errno));
return false;
} else {
struct _record record; // clear the record
while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
char *cursor = buffer;
memset(&record, 0, sizeof(record)); // clear the record
loadField(record.ID, sizeof(record.ID), &cursor);
loadField(record.lname, sizeof(record.lname), &cursor);
loadField(record.fname, sizeof(record.fname), &cursor);
loadField(record.mname, sizeof(record.mname), &cursor);
loadField(record.suffix, sizeof(record.suffix), &cursor);
loadField(record.bday, sizeof(record.bday), &cursor);
loadField(record.gender, sizeof(record.gender), &cursor);
loadField(record.SSN, sizeof(record.SSN), &cursor);
loadField(record.add1, sizeof(record.add1), &cursor);
loadField(record.add2, sizeof(record.add2), &cursor);
loadField(record.zip, sizeof(record.zip), &cursor);
loadField(record.maiden, sizeof(record.maiden), &cursor);
loadField(record.MRN, sizeof(record.MRN), &cursor);
loadField(record.city, sizeof(record.city), &cursor);
loadField(record.state, sizeof(record.state), &cursor);
loadField(record.phone1, sizeof(record.phone1), &cursor);
loadField(record.phone2, sizeof(record.phone2), &cursor);
loadField(record.email, sizeof(record.email), &cursor);
loadField(record.alias, sizeof(record.alias), &cursor);
printf("ID: %s\n", record.ID);
if (fwrite(&record, sizeof(record), 1, fp) != 1) {
fprintf(stderr, "error: cannot write record: %s\n", strerror(errno));
break;
}
}
fclose(fp);
}
return true;
}
int main(void) {
if (loadDatabase("database.bin"))
return 1;
return 0;
}

c program fails when trying to print value using pointer

I don't get any error yet when I am trying to get value from array the program fails. The program contains a function to read products from file and store them in array of of type typedef structure item.
This is how the program looks like:
item *displayProducts(int balance){
int row=0;
char line[MAX_LINE_SIZE + 1]; // ptr to the current input line
static item products[8];
FILE *fp;
fp = fopen("machinedata.txt", "r");
if (fp == NULL)
{
printf("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
while (fgets(line, MAX_LINE_SIZE, fp)) {
char *next_ptr = NULL;
char *next_item = strtok_s(line, ",;", &next_ptr);
while (next_item != NULL){
char *item_ptr = NULL;
char *name = strtok_s(next_item, "-", &item_ptr);
if (name == NULL)
{
fprintf(stderr, "Failed to scan name out of [%s]\n", next_item);
break;
}
int price;
next_item = strtok_s(NULL, " ,", &item_ptr);
//assert(next_item != NULL);
if (strcmp(name," ")){
if (sscanf(next_item, "%d", &price) != 1)
fprintf(stderr, "Failed to convert [%s] to integer\n", next_item);
else if (balance > price){
products[row].name = name;
products[row].price = price;
products[row].product_code = row + 1;
printf("%d) %s:%d\n",products[row].product_code, products[row].name, products[row].price);
row++;
}
next_item = strtok_s(NULL, ",;", &next_ptr);
}
}
}
fclose(fp);
return products;
}
void main( int argc, char *argv[]){
int *ptr_to_balance;
int balance = atoi(argv[2]);
ptr_to_balance = &balance;
item *ptr_to_products;
Init(argv[1], balance);
ptr_to_products = displayProducts(balance);
printf("%s", *(ptr_to_products[2].name));
}
the program will print out all of the products from the file but for some reason the last line of the program fails. Any idea why?
I think, you need to change
printf("%s", *(ptr_to_products[2].name));
to
printf("%s", ptr_to_products[2].name);
as %s expects a pointer-to-null-terminated char array.
All the pointers in your products array point into the line array. This has two problems:
This array is local to displayProducts, and it's destroyed when the function returns.
Each element of products is has pointers to the same line array. So when you read a new line from the file, you're overwriting the values that were saved in the previous elements of products.
You need to make a copy of name in the heap before you save it in products[row].
char *name_copy = malloc(strlen(name)+1);
strcpy(name_copy, name);
products[row].name = name_copy;
You also need to fix the printing code, as in the other answer:
printf("%s", ptr_to_products[2].name);

Read tab delimited file to Structure in C

I have a file with tab delimited data. I want to read the every line into a Structure. I have a code to read the data to char buffer. But I want to load the data into a Structure.
This is My sample data.
empname1\t001\t35\tcity1
empname2\t002\t35\tcity2
My Structure definition .
struct employee
{
char *empname;
char *empid;
int age;
char *addr;
};
My sample program to read data to a char array buffer
char buffer[BUF_SIZE]; /* Character buffer */
input_fd = open (fSource, O_RDONLY);
if (input_fd == -1) {
perror ("open");
return 2;
}
while((ret_in = read (input_fd, &buffer, BUF_SIZE)) > 0){
// Do Some Process
}
Here I want to load the content to a structure variable instead of the character buffer. How I can achieve that?
Well, a possible solution could be
Read a complete line from the file using fgets().
tokenize the input buffer based on the required delimiter [tab in your case] using strtok().
allocate memory (malloc()/ realloc()) to a pointer variable of your structure.
copy the tokenized inputs into the member variables.
Note:
1. fgets() reads and stores the trailing \n.
2. Please check carefully how to use strtok(). The input string should be mutable.
3. Allocate memory to pointers before using them. IMO, use statically allocated array as struct employee member variables.
You can use the fscanf function. Open a file as a stream then use the fscanf to get a input from the file.
int fscanf(FILE *stream, const char *format, ...);
FILE *fp=fopen(fsource,"r+");
struct employee detail;
fscanf(fp,"%s %s %d %s",detail.empname,detail.empid,&detail.age,detail.addr);
Make sure that allocation of memory to the variables.
Or else you can use the strtok function. That time you have to use the sscanf function.
You can use fscanf to read each line from file, strtok to tokenize the line read.
Since your structure members are pointers, allocate memory appropriately.
The following minimal code does exactly what you want.
#define SIZE 50
FILE *fp = NULL;
int i = 0;
struct employee var = {NULL, NULL, 0, NULL};
char line[SIZE] = {0}, *ptr = NULL;
/* 1. Open file for Reading */
if (NULL == (fp = fopen("file.txt","r")))
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
/* 2. Allocate Memory */
var.empname = malloc(SIZE);
var.empid = malloc(SIZE);
var.addr = malloc(SIZE);
/* 3. Read each line from the file */
while (EOF != fscanf(fp, "%s", line))
{
/* 4. Tokenise the read line, using "\" delimiter*/
ptr = strtok(line, "\\");
var.empname = ptr;
while (NULL != (ptr = strtok(NULL, "\\")))
{
i++;
/* 5. Store the tokens as per structure members , where (i==0) is first member and so on.. */
if(i == 1)
var.empid = ptr;
else if(i == 2)
var.age = atoi(ptr);
else if (i == 3)
var.addr = ptr;
}
i = 0; /* Reset value of i */
printf("After Reading: Name:[%s] Id:[%s] Age:[%d] Addr:[%s]\n", var.empname, var.empid, var.age, var.addr);
}
Working Demo: http://ideone.com/Kp9mzN
Few things to Note here:
This is guaranteed to work, as long as your structure definition (and order of members) remains the same (see manipulation of value i).
strtok(line, "\\");, Second argument is just escaping (first \) the actual \ character.
Clarification from the OP:
In your structure definition, third member is an int, however you're trying to read t35 into it (which is a string).
So var.age = atoi(ptr); will give you 0,
You could change the structure definition, making third member as char * and allocating memory like other members.
Or change file contents, making sure an int is present as the third value.
I think this may be what you are looking for
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
struct employee
{
char *empname;
char *empid;
int age;
char *addr;
};
int readEmploee(char *line, struct employee *employee)
{
char *token;
char *saveptr;
char *endptr;
if ((employee == NULL) || (line == NULL))
return 0;
token = strtok_r(line, "\t", &saveptr);
if (token == NULL)
return 0;
employee->empname = strdup(token);
token = strtok_r(NULL, "\t", &saveptr);
if (token == NULL)
return 0;
employee->empid = strdup(token);
token = strtok_r(NULL, "\t", &saveptr);
if (token == NULL)
return 0;
employee->age = strtol(token, &endptr, 10);
if (*endptr != '\0')
return 0;
token = strtok_r(NULL, "\t", &saveptr);
if (token == NULL)
return 0;
employee->addr = strdup(token);
return 1;
}
char *mygetline(int fd)
{
char *line;
size_t length;
size_t count;
char character;
line = malloc(128);
if (line == NULL)
return NULL;
length = 0;
count = 1;
do
{
if (read(fd, &character, 1) != 1) /* end of file probably reached */
{
free(line);
return NULL;
}
else if (character != '\n')
{
if (length > 128 * count)
{
char *temp;
temp = realloc(line, 128 * count);
if (temp == NULL)
{
free(line);
return NULL;
}
line = temp;
count += 1;
}
line[length++] = character;
}
} while (character != '\n');
line[length] = 0;
return line;
}
struct employee *readFile(const char *const fSource, size_t *count)
{
struct employee *employees;
int employeeCount;
int input_fd;
char *line;
if ((count == NULL) || (fSource == NULL))
return NULL;
*count = 0;
employees = NULL;
employeeCount = 0;
input_fd = open (fSource, O_RDONLY);
if (input_fd == -1)
{
perror ("open");
return NULL;
}
while ((line = mygetline(input_fd)) != NULL)
{
struct employee employee;
if (readEmploee(line, &employee) != 0)
{
struct employee *temp;
temp = realloc(employees, (1 + employeeCount) * sizeof(struct employee));
if (temp != NULL)
employees = temp;
employees[employeeCount++] = employee;
}
free(line);
}
*count = employeeCount;
return employees;
}
int
main()
{
size_t count;
size_t index;
struct employee *employees;
employees = readFile("somesamplefile.txt", &count);
if (employees == NULL)
return 1;
for (index = 0 ; index < count ; index++)
{
struct employee current;
current = employees[index];
fprintf(stderr, "%s, %s, %d, %s\n", current.empname, current.empid, current.age, current.addr);
if (current.empname != NULL)
free(current.empname);
if (current.empid != NULL)
free(current.empid);
if (current.addr != NULL)
free(current.addr);
}
free(employees);
return 0;
}

Resources