Reading a text file line by line into a structure in c - c

I am kind of new to c programming but I want to create a c function that can read contents of a text file line by line separated by the tab delimiter(\t) and store them into a data structure, then after clear the file but have still failed. My code is
struct Busy_list{
int client_socket;
char JOB[1024];
int characters;
int No_jobs;
int IsReplace;
int Priority;
};
char** PriorityEvaluator(int client_socket){
struct Busy_list Array;
FILE *Ufptr;
Ufptr = fopen("Unsorted_busy_list.txt","r+");
for(int i;!EOF;i++){
fscanf(Ufptr, "%d\t%s\t%d\t%d\t%d\n",&Array.client_socket,&Array.JOB,&Array.characters,&Array.No_jobs,&Array.IsReplace);
}
fclose(Ufptr);
}
My Unsorted_busy_list file contains
/*
4 double fish 4 1 0
5 double praise 6 2 0
5 replace peter 2-o,4-o 5 2 1
*/

Try to replace your for loop with a while loop like this:
while((fscanf(Ufptr, "%d\t%s\t%d\t%d\t%d\n",&Arguments...)) != EOF){
}

Related

Can't read real numbers from Yale Bright Star Catalog

I'm currently trying to read some star data from the BSC. I've managed to read in the header and that shows up more or less correct, but I'm having trouble reading in the star data itself. The specification states that values are stored as 4/8-byte "Real" numbers, which I assumed meant floats/doubles, but the Ascension and Declination I get are all wrong, a good bit above the trillions for one and zero for the other. The magnitude is also wrong, despite it just being an integer, which I could read fine in the header. Here's and image of the output thus far. Any know what I'm doing wrong?
Alright, after some more testing, I managed to solve my problem. The crucial step was to abandon the binary file altogether and use the ASCII file instead. I had some problems reading from it before due to how it was formatted, but I came up with a method that worked:
/* Struct to store all the attributes I'm interested in */
struct StarData_t{
char Name[11];
char SpType[21];
float GLON, GLAT, Vmag;
};
int main()
{
/* Allocate a list of the structs
(the BSC has 9110 entries) */
struct StarData_t stars[9110];
/* Open the catalog */
FILE *fptr = fopen("catalog", "r");
if(fptr != NULL){
/* Create a buffer for storing the star entries.
The ASCII file has one entry per line.
Each line has a max length of 197,
which becomes 199 with the newline and null terminator,
so I round up to 200. */
size_t star_size = 200;
char *star_buffer;
star_buffer = (char *)malloc(star_size * sizeof(char));
/* Create a buffer for reading in the numbers.
The catalog has no numbers longer than 6 characters,
So I allocate 7 to account for the newline. */
char data_buffer[7];
/* For each entry in the BSC... */
for(int i = 0; i < 9110; i++){
/* Read the line to the buffer */
getline(&star_buffer, &star_size, fptr);
/* And put the data in the matching index,
Using the data buffer to create the floats */
// GLON
strncpy(data_buffer, &(star_buffer[90]), 6);
data_buffer[6] = '\0';
stars[i].GLON = fmod(atof(data_buffer)+180, 360)-180;
// GLAT
strncpy(data_buffer, &(star_buffer[96]), 6);
data_buffer[6] = '\0';
stars[i].GLAT = atof(data_buffer);
// Vmag
strncpy(data_buffer, &(star_buffer[102]), 5);
data_buffer[5] = '\0';
stars[i].Vmag = atof(data_buffer);
// Name
strncpy(stars[i].Name, &(star_buffer[4]), 10);
stars[i].Name[10] = '\0';
// Spectral Type
strncpy(stars[i].SpType, &(star_buffer[127]), 20);
stars[i].SpType[20] = '\0';
printf("Name: %s, Long: %7.2f, Lat: %6.2f, Vmag: %4.2f, SpType: %s\n", stars[i].Name, stars[i].GLON, stars[i].GLAT, stars[i].Vmag, stars[i].SpType);
}
free(star_buffer);
}
}
Hope this is useful!

Issues Reading a CSV file into a C Struct

I've just started learning C, and I'm currently trying to create a program to automate a fishing minigame I made for my D&D campaign. In order to do so, I created a CSV containing all the tables I had originally written up. I've been trying a variety of things for about a week now to just simply read the CSV into C so that I can call specific elements at will. I've finally gotten something to very nearly work, but I'm getting a strange problem. Firstly, the CSV is formatted as such:
bluefish,str,2,5
bluefish,str,2,5
bluefish,str,2,5
bluefish,str,2,5
kahawai,dex,2,1000
narrow barred mackerel,str,3,5
It goes on for another 400 lines, but you get the point. My current code looks like the following:
typedef struct{
char name[50];
char contest[5];
int modifier;
int value;
} fts_t;
/*Checking for the file and opening it*/
FILE *tpointer;
tpointer = fopen("fishing_tables.csv", "r");
printf("Accessing Fishing Tables...\n");
if(tpointer == NULL){
printf("Error: Missing fishing_tables.csv");
return 0;
} else{
printf("Success! Importing Data...\n");
}
/*Creating a struct array and initializing variables*/
fts_t ft[400];
char buffer[1024];
int count = 0;
char name[100];
char contest[3];
int modifier;
int value;
while(fgets(buffer, 1024, tpointer)){
sscanf(buffer, " %[^,],%[^,],%d,%d", name, contest, &modifier, &value);
strcpy(ft[count].name, name);
strcpy(ft[count].contest, contest);
ft[count].modifier = modifier;
ft[count].value = value;
printf("%s\t%s\t%d\t%d\n", ft[count].name, ft[count].contest, ft[count].modifier, ft[count].value);
count++;
}
So, following above, I'm having it print out the elements of the struct at each count as it loops, just to check that it's creating the struct correctly. The problem comes in that the output looks like this:
dex 2 15
dex 2 15
dex 2 15
dex 2 15
dex 2 15
next 0 0 0
next 0 0 0
next 0 0 0
next 0 0 0
next 0 0 0
Now, hilariously, the rows beginning with "next" are the only rows printing correctly. I have these added in for some extra shenanigans in the context of the minigame, but what's important is that those are correct. However, in every other row, the name variable is not being read, and I'm really lost as to why, when the "next" rows are functioning fine. I've checked the actual variable itself, and it appears there's some sort of problem in my sscanf statement.
Any help is appreciated.

Reading instructions from a text file

I need help with reading instructions from a text file. So for example:
Let's say this is my text file:
a 38
s 20
a 10
s 10
'a' stands for add, 's' stands for subtract, and the number separated by a tab is the number I want to either add or subtract from a total. So I want my program to read this line by line and perform the operation specified.
Example: If my total starts at 0, I want the program to read "a tab 38" on the first line and add 38 to the total, and then move on to the next line and read "s tab 20" on the second line and subtract 20 from the total. So on and so forth.
I know how to get the program to read the file, but I'm not sure how to get it to recognize the a/s, the tab, and the number, and then keep doing it for each line.
Any help would be greatly appreciated because I'm really stuck.
use fscanf(yourfileptr, "%c\t%d", &instruction, &operand) to get the instruction and the operand. then you can simply add or subtract the operand according to the instruction character.
Maybe you can try this . Code I haven't checked properly but that should be the line of coding. This is inside main function code.
FILE *fp;
char buff[255];
char numBuff[10];
int a;
int val = 0;
char op;
int len;
fp = fopen("/tmp/test.txt", "r");
while(fgets(buff, 255, file) != NULL){
len = strlen(buff);
strncpy (numBuff, buff+2, len-2);
numBuff[len-2] = '\0';
a = atoi(numBuff);
if(buff[0] == 's'){
val -= a;
}else if(buff[0]=='a'){
val += a;
}
}
printf("%d",val);

Adding Line break After Every Line

I have written the following piece of code:
#include<stdio.h>
void add_linebreak()
{
FILE *fp ;
char c, NEWL=10 ;
fp=fopen("text1.txt","a+") ;
if(fp==NULL)
{
printf("\nFile Not Found") ;
}
fseek(fp,0,SEEK_CURR) ;
while(!feof(fp))
{
//if(!feof(fp))
//{
c=fgetc(fp);
if(c==NEWL)
{
fprintf(fp,"%c",NEWL) ;
}
//}
}
fclose(fp) ;
}
int main()
{
add_linebreak() ;
printf("\nEditing Complete") ;
return 0 ;
}
The program took following data as input from a file named text1.txt :
1 this
2 is
3 a
4 text
5 file
6 to
7 test a
8 program
9 written
10 in c
Actual Output :
1 this
2 is
3 a
4 text
5 file
6 to
7 test a
8 program
9 written
10 in c
11
Expected Output:
1 this
2
3 is
4
5 a
6
7 text
8
9 file
10
11 to
12
13 test a
14
15 program
16
17 written
18
19 in c
20
I scratched my head on this for hours but wasn't able to get the expected output, please help me.
you gotta make a copyy of the file
Also fgetc returns int not char
void add_linebreak()
{
FILE *fin, *fout ;
char NEWL='\n' ;
fin=fopen("text1.txt","rb") ;
if(fp==NULL)
{
printf("\nFile Not Found") ;
}
fout = fopen("copy.txt","w");
while(1)
{
int c=fgetc(fin);
if(c==EOF)
break;
fprintf(fout, "%c", c);
if(c==NEWL)
{
fprintf(fout,"%c",NEWL) ;
}
}
fclose(fout) ;
fclose(fin);
}
renaming the file back to the original and adding some more error handling is left as a test :-)
You may not perform the modifications in-place. Not with stuff like text.
You have to instead read from one file, write to a temporary then perhaps rename the copy to overwrite the original update.
The other answer says almost everything besides the rename.
Oh, another thing: I have found often that newlines tended to get stripped in my old test programs; that may be another thing. But the modifying-in-place is the most likely culprit.

C Primer 5th - Task 14-6

A text file holds information about a softball team. Each line has data arranged as follows:
4 Jessie Joybat 5 2 1 1
The first item is the player's number, conveniently in the range 0–18. The second item is the player's first name, and the third is the player's last name. Each name is a single word. The next item is the player's official times at bat, followed by the number of hits, walks, and runs batted in (RBIs). The file may contain data for more than one game, so the same player may have more than one line of data, and there may be data for other players between those lines. Write a program that stores the data into an array of structures. The structure should have members to represent the first and last names, the at bats, hits, walks, and RBIs (runs batted in), and the batting average (to be calculated later). You can use the player number as an array index. The program should read to end-of-file, and it should keep cumulative totals for each player.
The world of baseball statistics is an involved one. For example, a walk or reaching base on an error doesn't count as an at-bat but could possibly produce an RBI. But all this program has to do is read and process the data file, as described next, without worrying about how realistic the data is.
The simplest way for the program to proceed is to initialize the structure contents to zeros, read the file data into temporary variables, and then add them to the contents of the corresponding structure. After the program has finished reading the file, it should then calculate the batting average for each player and store it in the corresponding structure member. The batting average is calculated by dividing the cumulative number of hits for a player by the cumulative number of at-bats; it should be a floating-point calculation. The program should then display the cumulative data for each player along with a line showing the combined statistics for the entire team.
team.txt (text file I'm working with):
4 Jessie Joybat 5 2 1 1
4 Jessie Joybat 7 3 5 3
7 Jack Donner 6 3 1 2
11 Martin Garder 4 3 2 1
15 Jaime Curtis 7 4 1 2
2 Curtis Michel 3 2 2 3
9 Gillan Morthim 9 6 6 7
12 Brett Tyler 8 7 4 3
8 Hans Gunner 7 7 2 3
14 Jessie James 11 2 3 4
12 Brett Tyler 4 3 1 3
Since I'm a beginner in C, either I misinterpreted the task from what was asked originally or it's unfairly complex (I believe the former is the case). I'm so lost that I can't think of the way how could I fill in by the criteria of index (player number) every piece of data, keep track of whether he has more than one game, calculate and fetch bat average and then print.
What I have so far is:
#define LGT 30
struct profile {
int pl_num;
char name[LGT];
char lname[LGT];
int atbat[LGT/3];
int hits[LGT/3];
int walks[LGT/3];
int runs[LGT/3];
float batavg;
};
//It's wrong obviously but it's a starting point
int main(void)
{
FILE *flx;
int i,jc,flow=0;
struct profile stat[LGT]={{0}};
if((flx=fopen("team.txt","r"))==NULL) {
fprintf(stderr,"Can't read file team!\n");
exit(1);
}
for( jc = 0; jc < 11; jc++) {
fscanf(flx,"%d",&i);
stat[i].pl_num=i;
fscanf(flx,"%s",&stat[i].name);
fscanf(flx,"%s",&stat[i].lname);
fscanf(flx,"%d",&stat[i].atbat[flow]);
fscanf(flx,"%d",&stat[i].hits[flow]);
fscanf(flx,"%d",&stat[i].walks[flow]);
fscanf(flx,"%d",&stat[i].runs[flow]);
flow++;
}
}
Advice 1: don't declare arrays like atbat[LGT/3].
Advice 2: Instead of multiple fscanf you could read the whole line in a shot.
Advice 3: Since the number of players is limited and the player number has a good range (0-18), using that player number as an index into the struct array is a good idea.
Advice 4: Since you need cumulative data for each player (no need to store his history points), then you don't need arrays of integers, just an integer to represent the total.
So:
#include <stdio.h>
#define PLAYERS_NO 19
typedef struct
{
char name[20+1];
char lastName[25+1];
int atbat;
int hits;
int walks;
int runs;
float batavg;
} Profile;
int main(int argc, char** argv)
{
Profile stats[PLAYERS_NO];
int i;
FILE* dataFile;
int playerNo;
Profile tmpProfile;
int games = 0;
for(i=0; i<PLAYERS_NO; ++i)
{
stats[i].name[0] = '\0';
stats[i].lastName[0] = '\0';
stats[i].atbat = 0;
stats[i].hits = 0;
stats[i].walks = 0;
stats[i].runs = 0;
}
dataFile = fopen("team.txt", "r");
if ( dataFile == NULL )
{
fprintf(stderr, "Can't read file team!\n");
exit(1);
}
for(i=0; i<PLAYERS_NO && !feof(dataFile); ++i, ++games)
{
fscanf(dataFile, "%d", &playerNo);
if ( playerNo <0 || playerNo > PLAYERS_NO )
{
fprintf(stderr, "Player number out of range\n");
continue;
}
fscanf(dataFile, "%s %s %d %d %d %d",
&tmpProfile.name,
&tmpProfile.lastName,
&tmpProfile.atbat,
&tmpProfile.hits,
&tmpProfile.walks,
&tmpProfile.runs);
printf("READ: %d %s %s %d %d %d %d\n",
playerNo,
tmpProfile.name,
tmpProfile.lastName,
tmpProfile.atbat,
tmpProfile.hits,
tmpProfile.walks,
tmpProfile.runs);
strcpy(stats[playerNo].name, tmpProfile.name);
strcpy(stats[playerNo].lastName, tmpProfile.lastName);
stats[playerNo].atbat += tmpProfile.atbat;
stats[playerNo].hits += tmpProfile.hits;
stats[playerNo].walks += tmpProfile.walks;
stats[playerNo].runs += tmpProfile.runs;
}
/* exercise: compute the average */
fclose(dataFile);
for(i=0; i<PLAYERS_NO; ++i)
{
if ( stats[i].name[0] == '\0' )
continue;
printf("%d %s %s %d %d %d %d\n",
i,
stats[i].name,
stats[i].lastName,
stats[i].atbat,
stats[i].hits,
stats[i].walks,
stats[i].runs);
}
return 0;
}
The first rule of programming: Divide and conquer.
So you need to identify individual operations. One such operation is "load one row of input", another is "look up a player". If you have some of those operations (more will come up as you go), you can start building your program:
while( more_input ) {
row = load_one_row()
player = find_player( row.name )
if( !player ) {
player = create_player( row.name )
add_player( player )
}
... do something with row and player ...
}
when you have that, you can start to write all the functions.
An important point here is to write test cases. Start with a simple input and test the code to read a row. Do you get the correct results?
If so, test the code to find/create players.
The test cases make sure that you can forget about code that already works.
Use a framework like Check for this.
If I were doing this, I'd start with a structure that only held one "set" of data, then create an array of those structs:
struct profile {
char name[NAMELEN];
char lname[NAMELEN];
int atbat;
int hits;
int walks;
int runs;
float batavg;
};
Since you're using the player's number as the index into an array, you don't need to store it into the structure too.
I think that will simplify the problem a little bit. You don't need to store multiple data items for a single player -- when you get a duplicate, you just ignore some of the new data (like the names, which should be identical) and sum up the others (e.g., at-bats, hits).

Resources