How to parse table from txt file in C variables? - c

I have a text file in this format:
#Name #Company #ID
Name1 Brand1 1234
Name2 Brand2 5678
And a struct:
struct MyStruct{
char name[TEXT_LEN];
char company[TEXT_LEN];
char ID[TEXT_LEN];
};
typedef struct MyStruct Data_t;
What I want... is to load the data from text file in appropriate variables. It should ignore first line because those are headers...
This is what I've been trying so far but without success:
int loadDataFromFile(Data_t *items, long len, char *inputFile)
{
FILE *fp;
if ((fp = fopen(inputFile, "r")))
{
for (long i = 0; i < len; i++)
{
/*fscanf(fp, "%s %s %s\n", items[i].name, items[i].company, items[i].ID);*/
//this is commented part was not working part... More about this in EDIT
fscanf(fp, "%s %s %s\n", items[i].name, items[i].company, items[i].ID);
printf("Name: %s", items[i].name); // For first item it prints:
// Name: #Name
}
}
return 0;
}
What is wrong here?
EDIT
I've replaced the code but now it reads first line as well. Is there a way to ignore header of file (first line)?

Try This,
#include <stdio.h>
#define TEXT_LEN 100
typedef struct
{
char name[TEXT_LEN];
char company[TEXT_LEN];
char ID[TEXT_LEN];
}Data_t;
int loadDataFromFile(Data_t *items, long len, char *inputFile) // change len as unsigned
{
FILE *fp;
char ch;
long i;
if ( ( fp = fopen(inputFile, "r") ) )
{
while( ( ch = getc(fp) != '\n') && ch!=EOF ); //To ignore first line
printf("Reading...\n");
for (i = 0; i < len && (fscanf(fp, "%s %s %s", items[i].name, items[i].company, items[i].ID) == 3); i++)
{
printf("\n#Name: %s #Company: %s #ID: %s", items[i].name, items[i].company, items[i].ID);
}
}
else
{
printf("File Error");
return 0;
}
return i;
}
int main()
{
Data_t data[2];
int n;
if(n=loadDataFromFile(data,2,"Txt")) //2 is number of line
{
printf("\n\nReaded !\n");
for(int i=0;i<n;i++)
printf("\n#Name: %s #Company: %s #ID: %s",data[i].name,data[i].company,data[i].ID);
}
return 0;
}
Txt:
#Name #Company #ID
Name1 Brand1 1234
Name2 Brand2 5678
Output:
Reading...
#Name: Name1 #Company: Brand1 #ID: 1234
#Name: Name2 #Company: Brand2 #ID: 5678
Readed !
#Name: Name1 #Company: Brand1 #ID: 1234
#Name: Name2 #Company: Brand2 #ID: 5678
[Done] exited with code=0 in 1.227 seconds

the following proposed code:
cleanly compiles
performs the desired functionality
properly discards the first line of the input file (the column headers)
properly checks for errors
properly checks that the data array is not overflowed
assures the fields in the data array are not overflowed when calling sscanf()
properly assures the input file can be read
and now, the proposed code:
#include <stdio.h>
#include <stdlib.h>
#define TEXT_LEN 21
struct MyStruct
{
char name[TEXT_LEN];
char company[TEXT_LEN];
char ID[TEXT_LEN];
};
typedef struct MyStruct Data_t;
long loadDataFromFile( Data_t *items, long len, char *inputFile )
{
FILE *fp = fopen(inputFile, "r");
if( ! fp )
{
perror( "fopen to read file failed" );
exit( EXIT_FAILURE );
}
// read/discard first line:
char buffer[1024];
if( ! fgets( buffer, sizeof( buffer ), fp ) ) // column header line
{
perror( "fgets failed to read column headers from input file" );
exit( EXIT_FAILURE );
}
long i = 0;
while( i < len && fgets( buffer, sizeof( buffer ), fp ) )
{
if( sscanf(buffer, "%20s %20s %20s", items[i].name, items[i].company, items[i].ID) != 3 )
{
break;
}
printf("Name: %s", items[i].name);
i++;
}
return i;
}

you coult try changin
fscanf(fp, "%s %s %s\n", items[i].name, items[i].company, items[i].ID);
to
fscanf(fp, "%s\t%s\t%s\n", items[i].name, items[i].company, items[i].ID);
and also iterating on the file lines could be done better by using something like this
while (!EOF) {/*Code*/}

Related

Save structure function leaves a spare place in a file instead of writing an array

#include <stdio.h>
struct BirdHome{
char area[500];
char heightcm[100];
char feederquantity[10];
char hasNest[5];
};
struct Bird{
char isRinged[5];
char nameSpecies[50];
char birdAgeMonths[500];
struct BirdHome hom;
char gender[6];
};
struct Bird birds;
int main(void){
FILE *oput;
int max=100;
int count = 0;
char filename[100];
printf("file name? : ");
scanf("%s", &filename);
count = load(filename, &birds, max);
if (count == 0)
printf("No structures loaded\n");
else (
printf("Data loaded\n")
);
save(&birds, oput);
return 0;
}
int load(char *filename, struct Bird *birds, int max){
int count = 0;
FILE *fp = fopen(filename, "r");
char line[100 * 4];
if (fp == NULL)
return 1;
while (count < max && fgets(line, sizeof(line), fp) != NULL){
sscanf(line, "%s %s %s %s %s %s %s %s", birds[count].isRinged, birds[count].nameSpecies,
birds[count].birdAgeMonths, birds[count].hom.area,
birds[count].hom.heightcm, birds[count].hom.feederquantity,
birds[count].hom.hasNest,birds[count].gender);
count++;
}
fclose(fp);
return count;
}
int save (struct Bird *birds, FILE *oput){
int i;
oput=fopen("birdssave.txt","w");
for (i=0;i<3;i++){
fprintf(oput,"%s %s %s %s %s %s %s %s\n",birds[i].isRinged, birds[i].nameSpecies,
birds[i].birdAgeMonths, birds[i].hom.area,
birds[i].hom.heightcm, birds[i].hom.feederquantity,
birds[i].hom.hasNest,birds[i].gender);
}
fclose(oput);
}
Well, the problem was said in the description of the question. Somehow, the load function works properly (at least I think so, because it runs properly and the success message is always displayed) and the save function runs without errors, but it doesn't write the needed info inside a file and just leaves gaps.
True sparrow 3 30 20 2 False Male
False crane 24 200 100 6 True Female
False griffin 14 300 80 1 False Male
This is a text file which my program used to write and load. I think this can somehow help you to find my mistakes in this code.
The load function is made unproperly so it doesn't work. The normal functions does a lot more things to do. Here is the text of it with the needed commentaries
int load(char * filename){
FILE * fp;
char *c;
int m = sizeof(int);
int n, i;
/*prepare memory for info*/
int *pti = (int *)malloc(m);
if ((fp = fopen(filename, "r")) == NULL){
perror("Error occured while opening file");
return 1;
}
/*read the quantity of structures*/
c = (char *)pti;
while (m>0){
i = getc(fp);
if (i == EOF) break;
*c = i;
c++;
m--;
}
/*get the number of elements*/
n = *pti;
/*prepare memory for read massive of structures*/
struct bird * ptr = (struct bird *) malloc(3 * sizeof(struct bird));
c = (char *)ptr;
/*after save we read massive by symbols*/
while ((i= getc(fp))!=EOF){
*c = i;
c++;
}
/*sort the elements and printing in console*/
printf("\n%d birds in the file stored\n\n", n);
for (int k = 0; k<n; k++){
printf("%d %s %s %d %d %d %d %s %s \n", k + 1,
ptr[k].isRinged,ptr[k].nameSpecies,ptr[k].birdAgeMonths,ptr[k].homearea,
ptr[k].homeheightcm,ptr[k].homefeederquantity,ptr[k].homehasNest,ptr[k].gender);
}
free(pti);
free(ptr);
fclose(fp);
return 0;
}
At least, the save function can be untouched only because algorhytmically it does the same as the normal code.

fopen reading Invalid argument C

I can't seem to find an answer to the fopen issue. It seems to be common, but everything I'm trying is not working, from what I have read this seems to be caused by a trailing newline, but I'm not sure:
The aim is to move from the hardcoded filename (which is commented) to the command line input for the file name
any help would be much appreciated
My code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
setbuf(stdout, NULL);
struct Person { char lname[20]; char fname[20]; int id; };
int N1, i ;
struct Person *p;
// char filename[] = "../src/students.csv" ;
//
// FILE *str = fopen( filename, "r") ;
// if (str==NULL) {
// perror(filename) ;
// exit(-1) ;
// }
printf("Please input file name:"); // Asks user to enter file name.
FILE *str2 = fopen(argv[1], " r"); // File opened for reading
printf("%p", str2);
if (str2 == NULL) { // If issue opening file display the error.
perror(argv[1]);
exit(-1);
}
fscanf( str2, "%d\n", &N1 ) ;
p = (struct Person*)calloc( N1 , sizeof(struct Person) ) ;
if (p==NULL) {
fprintf(stderr, "Can't allocate %d structs -- exiting.\n", N1 ) ;
exit(-1) ;
}
for ( i=0 ; i<N1 ; i++ ) {
fscanf( str2, " %[^,],%[^,],B%d", p[i].lname, p[i].fname, &(p[i].id) );
}
fclose(str2) ;
/* Access the array... Just like a static array */
printf("%s, %s, B000%d\n", p[4].lname, p[4].fname, p[4].id) ;
free(p) ;
return 0;
}
studnets.csv

sscanf till end of file in c

I have a C program that creates a binary file from a text file.
/*makeBinry.c*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char *argv[]){
char *ptext, *btext="file.bin";
if(argc != 2){
printf("Using default \"text.txt\" file to create mnemonics table\n");
ptext = "text.txt";
}else{
ptext = argv[2];
}
FILE *fp, *fb;
if(!(fp=fopen(ptext, "r"))){
fprintf(stdout, "Error: File %s is not available\n", ptext);
exit(1);
}
if(!(fb = fopen(btext, "wb"))){
fprintf(stdout, "Error: File %s is cannot be opened to write\n", btext);
exit(1);
}
int i, j, k;
char s[8], c, stringed[20];
while(!feof(fp)){
memset(stringed, '\0', sizeof(stringed));
fscanf(fp, "%X %d %c %d %[^\n]s", &i, &j, &c, &k, s);
sprintf(stringed, "%X %d %c %d %[^\n]s", &i, &j, &c, &k, s);
fwrite(stringed, 1, strlen(stringed), fb);
}
fprintf(stdout, "Success: %s file successfully created\n", btext);
fclose(fp);
fclose(fb);
return 0;
}
I have another program that reads the data in the binary file and stores into an array.
/*mainProg.c*/
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
typedef struct opStruct{
int hexv, fv, kv;
char str[8], key;
} node;
node* makeTable(char *filename){
FILE *fp;
if(!(fp = fopen(filename, "rb"))){
fprintf(stdout, "Error: Unable to open file %s\n", filename);
exit(1);
}
int hv, fv, kv;
char s[8], c, str[20];
while(!(feof(fp))){
sscanf(fp,"%X %d %c %d %[^\n]s", &hv, &fv, &c, &kv, str);
fprintf(stdout, "%X %d %c %d %s", hv, fv, c, kv, str);
}
fclose(fp);
return NULL;
}
int main(){
int i;
char *filename = "file.bin";
node *t_table = makeTable(filename);
return 0;
}
When I run the mainProg.c the program goes into an infinite loop. I figured it is because fp is never increased. How could I increase the file pointer and still use sscanf to read the binary file in the formatted manner? I'm not allowed to use fread(). Since currently, I'm not creating the table the function makeTable returns NULL.
Also, since the number of lines in the binary file would be unknown, how can I create the array dynamically using realloc?
the following code
properly handles error conditions
actually produces a binary file, rather than just another text file
uses the returned value from fscanf() rather than the faulty feof()
uses perror() so system error message is displayed on stderr
follows the axiom: only one statement per line and (at most) one variable declaration per statement
error checking for the calls to fwrite(), fclose() could be added but they are VERY unlikely to produce an error
and now the code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct record
{
unsigned int hv;
int fv;
int kv;
char c;
char s[8];
};
int main(int argc, char *argv[])
{
char *ptext, *btext="file.bin";
if(argc != 2)
{
printf("Using default \"text.txt\" file to create mnemonics table\n");
ptext = "text.txt";
}
else
{
ptext = argv[1];
}
FILE *fp;
FILE *fb;
if(!(fp=fopen(ptext, "r")))
{
perror( "fopen for read of text file failed" );
fprintf(stdout, "Error: File %s is not available\n", ptext);
exit(1);
}
if(!(fb = fopen(btext, "wb")))
{
perror( "fopen for write of binary file failed" );
fprintf(stdout, "Error: File %s is cannot be opened to write\n", btext);
fclose( fp ); // cleanup
exit(1);
}
struct record myRecord;
// produce binary file from text input
// note: leading space in format string, to consume any left over newline, etc
while(5 == fscanf(fp, " %X %d %c %d %7[^\n]",
&myRecord.hv,
&myRecord.fv,
&myRecord.c,
&myRecord.kv,
myRecord.s) )
{
fwrite( &myRecord, sizeof myRecord, 1, fb );
}
fprintf(stdout, "Success: %s file successfully created\n", btext);
fclose(fp);
fclose(fb);
return 0;
}
/*mainProg.c*/
#include <stdio.h>
#include <stdlib.h>
//#include <malloc.h>
#include <string.h>
//typedef struct opStruct
//{
// int hexv, fv, kv;
// char str[8], key;
//} node;
struct record
{
unsigned int hv;
int fv;
int kv;
char c;
char s[8];
};
//node* makeTable(char *filename)
void makeTable( char *filename )
{
FILE *fp;
if(!(fp = fopen(filename, "rb")))
{
fprintf(stdout, "Error: Unable to open file %s\n", filename);
exit(1);
}
// implied else, fopen successful
struct record myRecord;
// use fscanf() not sscanf()
while( fread( &myRecord, sizeof myRecord, 1, fp) )
{
//sprintf( , "%X %d %c %d %s\n" hv, fv, c, kv, s );
//fprintf(stdout, "%s", str );
fprintf( stdout, "\n%X", myRecord.hv );
fprintf( stdout, " %d", myRecord.fv );
fprintf( stdout, " %c", myRecord.c );
fprintf( stdout, " %d", myRecord.kv );
fprintf( stdout, " %8.8s", myRecord.s );
}
fprintf( stdout, "\n" ); // force flush
fclose(fp);
//return NULL;
} // end function: makeTable
int main( void )
{
//int i;
char *filename = "file.bin";
//node *t_table = makeTable(filename); // raises compiler warning about unused variable
makeTable(filename);
return 0;
} // end function: main

How to properly use fscanf in this file

I have this file with the following contents:
Bob Human, 1
John Cat, 3
Mary Dog, 2
How can I properly use fscanf to have each string and integer in a struct.
typedef struct {
char name[20];
char surname[20];
int code;
} entry;
Then I create an array of _entry_
entry a[3];
How will _a_ get each value properly using fscanf?
EDIT :
I have tried this:
while(TRUE) {
nscan=fscanf(infile, "%s %s d%c", temp.name, temp.surname, &temp.code, &termch);
if(nscan==EOF) break;
if(nscan!=4 || termch!='\n') {
printf("Error\n");
}
RecBSTInsert(&a, temp);
}
But it seems to pass the last line twice.
You're close, but you're not handling the comma properly.
As usual, it's much easier to read whole lines, then parse them. So let's do that.
Try:
char line[1024];
if(fgets(line, sizeof line, infile) != NULL)
{
nscan = sscanf(line, "%s %[^,], %d", temp.name, temp.surname, &temp.code);
}
The return value will be 3 if all the fields converted, else you have an error.
#include <stdio.h>
typedef struct{
char name[20];
char surname[20];
int code;
} entry;
int main(){
entry temp, a[3];
FILE *infile = fopen("data.txt", "r");
int i=0, n;
while(fscanf(infile, "%19s %19[^,], %d", temp.name, temp.surname, &temp.code)==3){
a[i++] = temp;
if(i==3)break;
}
fclose(infile);
n = i;
for(i=0;i<n;++i){
printf("%s %s, %d\n", a[i].name, a[i].surname, a[i].code);
}
return 0;
}

c, 2d char array and fopen

I'm trying to make a program that reads a file with list of names. The number of those names can vary, as well as the names lengths. I want to store them in an array of arrays of char, and read each row as a string to later open the file that corresponds to the name in question. But when I try to open the first one, I have an error opening file.
I'm totally out of ideas.
Help, please?
Here is the code relevant to this action:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int glimps(char *fname);
int write_av(char *fname, int NumbFiles);
int clr(char *fname);
int readFile(char *fname, int i);
double *dalpha, *alpha, *Ln_t, *LnLnA, Conc;
long *time, *weights, *Lmax, Nmax;
char *av_file, **in_files, *antetka;
/****************************************************************************/
int main(int argc, char *farg[])
{
int i, NumbFiles, flag;
long row;
char *a1;
FILE *fp;
av_file = farg[1];
printf("av_file = %s\n",av_file);
NumbFiles = glimps(av_file);
in_files = (char **) malloc (sizeof(char *) * NumbFiles);
for (i=0 ; i<NumbFiles ; i++)
in_files[i] = (char *) malloc (sizeof(char) * 200);
Lmax = (long *) calloc((size_t) NumbFiles, sizeof(long));
if((in_files == NULL)||(Lmax==NULL)) printf("Грешка при read алок.\n, "), exit(-1);
if (flag = readFile(av_file, -1))
printf("Error in read av_file %s\n", av_file), exit(-1);
weights = (long *) calloc((size_t) Nmax, sizeof(long));
for(i = 0; i<Nmax; i++) weights = 0;
for(i = 0; i<NumbFiles; i++)
{
//if (flag = readFile(&(*in_files[i]), i))
if (flag = readFile(in_files[i], i))
printf("Error in in_files[%d], %s\n",i, &(*in_files[i])), exit(-1);
}
if (flag = write_av(av_file, NumbFiles))
printf("Error in write_av(%s)\n,", av_file), exit(-1);
exit(0);
}
/****************************************************************************/
int glimps(char *fname)
{
FILE *fp;
char buf[140];
int cnt=0;
fp = fopen (fname, "r");
while (fgets(buf,140,fp) )
{
cnt++;
}
fclose(fp);
return (cnt);
}
/****************************************************************************/
int readFile(char *fname, int k)
{
int cnt=0;
FILE *fp;
char buf[200], dummy[13];
printf("fname is %s\n", fname); getchar();
fp = fopen (fname, "r");
if(fp==(NULL)) return(-1);
if(!strcmp(fname,av_file) )
{
while (fgets(in_files[cnt++],200,fp) );
}
else
{
printf("read TUK!\n"); getchar();
fgets(buf,200,fp);
sscanf(buf,"%s %s %s %s %s %s %s %ld %s %s %lf\n",
dummy, dummy,dummy,dummy,dummy,dummy,dummy, &Lmax[k],
dummy, dummy, &Conc);
fgets(buf,200,fp);
sscanf(buf,"%s\n", antetka);
printf("read TUK!\n"); getchar();
while (fgets(buf,200,fp))
{
sscanf(buf,"%ld %lf %lf %s %lf %lf\n",
&time[cnt], &dalpha[cnt], &alpha[cnt], dummy, &Ln_t[cnt],
&LnLnA[cnt]);
weights[cnt++]++;
}
}
fclose(fp);
return (0);
}
...
Console Output:
> ./avr alpha_cubeL.C0.010
av_file = alpha_cubeL.C0.010
fname is alpha_cubeL.C0.010
fname is alpha_cubeL100C0.010
Error in read in_files[0], alpha_cubeL100C0.010
> ls alpha_cubeL100C0.010
alpha_cubeL100C0.010
What happens is that in the readFile function, you read the main file given as argument to make (from the content) several file names in in_files[i], but fgets reads lines including the CR or CRLF (ie the end of line character(s)). Thus later in the program, readFile fails as it tries to open filename + CR [LF].
You may just add a trim function near the top of your program, like
void trim(char *s) {
int i,l = strlen(s);
for (i=l-1 ; i>=0 && (s[i]==10 || s[i]==13) ; i--) s[i] = 0;
}
that removes CR and/or LF that end a string s, and then change the readFile function to trim the file names read in each line, like
while (fgets(in_files[cnt++],200,fp) ) {
trim(in_files[cnt-1]); // cnt-1, or do the cnt++ here (and not above...)
}
Then the files can be opened...
(this is probably not the only problem in this program, but this is a good start)

Resources