Read variables from a file and store them in structs - C - c

I'm having some serious trouble with this program.
Pretty much I need to read from a file that has a set of first and last name, a cookie type, the amount purchased, the cost, and whether is was paid for or not.
I'm fairly confident that my functions are correct.
When I run the program, it runs correctly but there looks to be extra digits in between certain numbers. What I mean is, if the input file is:
John Green mint 1 1.00 Y
Jane Blue chip 2 2.00 N
The output file will be something like:
John Green 12 20000 mint 455 1 etc...
Any ideas? I'm guessing I messed up in reading the file/storing them into the struct.
#include <stdio.h>
#include <ctype.h>
/*structure definition*/
struct customer{
char first[12], last[12], type[10], paid;
int boxes;
float cost;
};
/*prototypes*/
void readCustomerData(FILE*, struct customer[]);
void printCustomerData(FILE*, int, struct customer[]);
float moneyReceived(int, struct customer[]);
int custWhoOwe(int, struct customer[]);
float moneyOutstanding(int, struct customer[]);
int moneyReceivedPercent(int, struct customer[]);
int main (){
int numCustomers;
float money, money2;
int cust, perc;
FILE*input;
FILE*output;
input = fopen("custInfo.txt", "r");
output = fopen("output.txt", "w");
fscanf(input, "%d", &numCustomers);
struct customer customerData[numCustomers];
readCustomerData(input, customerData);
printCustomerData(output, numCustomers, customerData);
fprintf(output, "Summary:\n\n");
money = moneyReceived(numCustomers, customerData);
fprintf(output, "Total Cash Received: $%.2f\n\n", money);
cust = custWhoOwe(numCustomers, customerData);
fprintf(output, "Num customers who have not paid: %d\n\n", cust);
money2 = moneyOutstanding(numCustomers, customerData);
fprintf(output, "Total Amount Outstanding: $%.2f\n\n", money2);
perc = moneyReceivedPercent(numCustomers, customerData);
fprintf(output, "Percentage of Sales outstanding: %d%%\n\n", perc);
fclose(input);
fclose(output);
return 0;
}
void readCustomerData(FILE*file, struct customer cdata[]){
int numCustomers, i;
file = fopen("custInfo.txt", "r");
fscanf(file, "%d", &numCustomers);
for (i=0; i<numCustomers; i++){
fscanf(file, "%s%s%s%d%f%c", &cdata[i].first, &cdata[i].last, &cdata[i].type, &cdata[i].boxes, &cdata[i].cost, &cdata[i].paid);
}
fclose(file);
}
void printCustomerData(FILE*file, int num, struct customer cdata[]){
int i;
fprintf(file, "Customers:\n\n");
fprintf(file, "Name\t\tType of Cookie\t\tNum of Boxes\tCost of Box\tPaid\n");
fprintf(file, "--------------------------------------------------------------------------------\n\n");
for (i=0; i<num; i++){
fprintf(file, "%s %s\t", cdata[i].first, cdata[i].last);
fprintf(file, "%s\t\t", cdata[i].type);
fprintf(file, "%d\t\t", cdata[i].boxes);
fprintf(file, "$%.2f\t\t", cdata[i].cost);
fprintf(file, "%c", cdata[i].paid);
fprintf(file, "\n\n");
}
fprintf(file, "\n\n\n\n\n");
}
float moneyReceived(int num, struct customer cdata[]){
int i, sum=0;
for (i=0; i<num; i++){
if(cdata[i].paid=='Y'){
sum= sum+(cdata[i].cost*cdata[i].boxes);}
}
return sum;
}
int custWhoOwe(int num, struct customer cdata[]){
int count=0, i;
for (i=0; i<num; i++){
if (cdata[i].paid=='N'){
count++;}
}
return count;
}
float moneyOutstanding(int num, struct customer cdata[]){
int i, sum=0;
for (i=0; i<num; i++){
if (cdata[i].paid=='N'){
sum= sum+(cdata[i].cost*cdata[i].boxes);}
}
return sum;
}
int moneyReceivedPercent(int num, struct customer cdata[]){
int answ;
float money, moneyOut;
money = moneyReceived(num, cdata);
moneyOut = moneyOutstanding(num, cdata);
answ=(moneyOut/money)*100;
return answ;
}

Input white-space characters (as specified by the isspace function) are skipped, unless the specification includes a [, c, or n specifier. C11 §7.21.6.2 8
1) Add a space before "%c" to consume white-space. "%c" does not do it by itself. The other used specifiers do that even without a leading space.
2) Check the return value of *scanf() functions. Unless the return value if 6, in this case, do not trust that the scan completed successfully.
3) Limit string input by declaring a width one less than the size for '%s'. Code certainly should be prevented from overrunning the arrays.
for (i=0; i<numCustomers; i++){
// fscanf(file, "%s%s%s%d%f%c", &cdata[i].first, &cdata[i].last,
// &cdata[i].type, &cdata[i].boxes, &cdata[i].cost, &cdata[i].paid);
if (6 != fscanf(file, "%11s%11s%9s%d%f %c",
&cdata[i].first, &cdata[i].last, &cdata[i].type,
&cdata[i].boxes, &cdata[i].cost, &cdata[i].paid)) {
printf("Bad input!");
}
}

Related

Printing out values in an array not working as expected

I was tasked with inputting student information based on a given struct, where each field of information is to be typed in one line, separated by a space, then the student id is sorted incrementally, and then print out the information, each student on a new line. The problem is while I thought my code was good, the print part keeps giving fractured results and overall just not printing out the correct values. Where should I fix this?
Here's my code:
#include <stdio.h>
typedef struct
{
char id[8];
int year;
}student;
int main() {
student std[100];
int i, j, num, tmp;
printf("So sinh vien:\n");
scanf("%d", &num);
printf("Nhap thong tin sinh vien:\n");
for(i=0; i <= num; i++)
{
scanf("%c %d\n", &std[i].id, &std[i].year);
}
for(i=0; i < num; i++)
{
for (j=1; j< num; j++)
{
if (std[i].id > std[j].id)
{
tmp = *std[i].id
*std[i].id = *std[j].id;
*std[j].id = tmp;
}
}
}
for(i=0; i < num; i++)
{
printf("%c ", std[i].id);
printf("%d\n", std[i].year);
}
return 0;
}
My output is
So sinh vien:
3
Nhap thong tin sinh vien:
12324521 2003
12341552 2002
12357263 2001
Σ 12324521
≡ 3
ⁿ 2341552
Check the return value of scanf() otherwise you may be operating on uninitialized variables.
Check that num less than the 100 records you allocated for student, or even better use a vla along with a check to avoid large input from smashing the stack.
You input num then read num+1 records but later you only print num records.
As you read a character with "%c" the first input with be the \n from the previous scanf().
The struct contains a char id[8] but you only read a single character into it. Read a string instead.
In sort you use > to compare the first letter of id. You probably want to use strcmp() to compare strings.
In sort section you use a int tmp for storing a character of id (which is ok) but then you write an int which is no good.
In sort you only swap the ids. You probably want to swap the entire record not just the ids.
It seems to be an exchange sort. Use a function, and also at least for me the algorithm didn't work as the inner loop variable should start at j=i+1 not 1.
In your print char id[8] as a single char instead of string.
Moved print functionality to a function. This allows you, for instance, to print the students before and after the sort() during debugging.
Minimizing scope of variables (i and j are now loop local, tmp is only used in the swap() function). This makes code easier to reason about.
#include <stdio.h>
#include <string.h>
#define ID_LEN 7
#define str(s) str2(s)
#define str2(s) #s
typedef struct {
char id[ID_LEN+1];
int year;
} student;
void swap(student *a, student *b) {
student tmp = *a;
*a = *b;
*b = tmp;
}
void print(size_t num, student std[num]) {
for(size_t i=0; i < num; i++)
printf("%s %d\n", std[i].id, std[i].year);
}
// exchange sort
void sort(size_t num, student std[num]) {
for(size_t i=0; i < num - 1; i++)
for (size_t j=i+1; j < num ; j++)
if(strcmp(std[i].id, std[j].id) > 0)
swap(&std[i], &std[j]);
}
int main() {
printf("So sinh vien:\n");
size_t num;
if(scanf("%zu", &num) != 1) {
printf("scanf() failed\n)");
return 1;
}
if(num > NUM_MAX) {
printf("Too many students\n");
return 1;
}
student std[num];
printf("Nhap thong tin sinh vien:\n");
for(size_t i=0; i < num; i++)
if(scanf("%" str(ID_LEN) "s %d", std[i].id, &std[i].year) != 2) {
printf("scanf() failed\n");
return 1;
}
sort(num, std);
print(num, std);
}
and here is an example run:
So sinh vien:
3
Nhap thong tin sinh vien:
aaa 1
zzz 2
bbb 3
aaa 1
bbb 3
zzz 2
printf("%c ", std[i].id);
should be
printf("%s ", std[i].id);
%c means a single char.

value in loop doesnt return

i have this data in file
ATOM 1 N MET A 1 25.909 16.164 -8.037
ATOM 2 CA MET A 1 25.498 14.786 -8.206
ATOM 3 C MET A 1 26.612 13.934 -8.806
ATOM 4 O MET A 1 27.442 14.402 -9.588
this is my full code
#include<stdio.h>
#include<math.h>
typedef struct prot {
char atom[10];
int atomno;
char site[10];
char residue[10];
char chain;
int residueno;
float x, y, z;
} Td;
int main()
{
FILE*fd;
fd=fopen("2zoi.pdb","r+");
Td data[1300];
char buffer[1300];
int a=0;
while(fgets(buffer, 1300, fd))
{
sscanf(buffer, "%s %d %s %s %c %d %f %f %f",data[a].atom,&data[a].atomno,data[a].site,
data[a].residue,&data[a].chain,&data[a].residueno,&data[a].x, &data[a].y, &data[a].z);
printf("%s %d %s %s %c %d %6.3f %6.3f %6.3f \n",data[a].atom,data[a].atomno,data[a].site,
data[a].residue,data[a].chain,data[a].residueno,data[a].x, data[a].y, data[a].z);
a++;
}
//---user input
int fr,sr;
int fa,sa;
int i=0;
float x1,x2,y1,y2,z1,z2;
float distance=0;
printf("Enter first no of atom :");
scanf("%d",&fa);
printf("Enter second no of atom :");
scanf("%d",&sa);
while(data[i].atomno>=0)
{
if(fa==data[i].atomno)
{
x1=data[i].x;
y1=data[i].y;
z1=data[i].z;
}
else if(sa==data[i].atomno)
{
x2=data[i].x;
y2=data[i].y;
z2=data[i].z;
}
i++;
}
printf("%f %f %f",x1,y1,z1);
printf("%f %f %f",x2,y2,z2);
//distance= sqrt(pow((x2 - x1), 2) + pow((y2 - y1), 2) + pow((z2 - z1), 2));
//printf("%6.3f",distance);
return 0;
}
the problem is at this part
printf("%f %f %f",x1,y1,z1);
printf("%f %f %f",x2,y2,z2);
i try to return to values from above loop where the value for x1,y1,z1 is for the first atom and x2,y2,z2 for second atom.
when i input 3 and 4, it gives answer
26.612 13.934 -8.806
27.442 14.402 -9.588
which is correct. but when i input 1 and 2, it gives rubbish answer. it seems like i cant input number 2 also number 10.did i do any mistake?
You have a big problem with data array values: not all elements of the array are set to 0 then the final loop can be broken.
You can use memset to reset to 0 all bytes of data array.
#include<stdio.h>
#include<math.h>
#include <string.h>
typedef struct prot
{
char atom[10];
int atomno;
char site[10];
char residue[10];
char chain;
int residueno;
float x, y, z;
} Td;
int main()
{
FILE*fd;
Td data[1300];
char buffer[1300];
size_t a=0;
fd=fopen("2zoi.pdb","r+");
if (fd != NULL)
{
memset(data, 0x00, sizeof(data));
while ((fgets(buffer, 1300, fd)) && (a < sizeof(data)/sizeof(data[0])))
{
sscanf(buffer, "%s %d %s %s %c %d %f %f %f",data[a].atom,&data[a].atomno,data[a].site,
data[a].residue,&data[a].chain,&data[a].residueno,&data[a].x, &data[a].y, &data[a].z);
printf("%s %d %s %s %c %d %6.3f %6.3f %6.3f \n",data[a].atom,data[a].atomno,data[a].site,
data[a].residue,data[a].chain,data[a].residueno,data[a].x, data[a].y, data[a].z);
a++;
}
//---user input
int fr,sr;
int fa,sa;
size_t i=0;
float x1,x2,y1,y2,z1,z2;
float distance=0;
printf("Enter first no of atom :");
scanf("%d",&fa);
printf("Enter second no of atom :");
scanf("%d",&sa);
while ((data[i].atomno>=0) && (i < sizeof(data)/sizeof(data[0])))
{
if(fa==data[i].atomno)
{
x1=data[i].x;
y1=data[i].y;
z1=data[i].z;
}
else if(sa==data[i].atomno)
{
x2=data[i].x;
y2=data[i].y;
z2=data[i].z;
}
i++;
}
printf("%f %f %f\n",x1,y1,z1);
printf("%f %f %f\n",x2,y2,z2);
}
else
{
fprintf(stderr, "Error opening file\n");
exit(1);
}
return 0;
}
You should check the fopen return value (as you can see in code posted), but as a standard rule: you should always check functions return values.

Issue with FILE I/O and using data within

This code for tolerance analysis compiles and runs, but the output is incorrect and I believe it to be the incorrect handling of the file and the data within the file.
The data in the file is:
PART,2.000,-1,0.050,V
PART,0.975,-1,0.025,V
PART,3.000,+1,0.010,F
GAP,0.000,0.080
The code:
#include <stdlib.h>
#include <string.h>
#include <math.h>
void parsePart(char input[], float*pnom, int*pinp, float*ptol, char*pFV);
void parseGap(char input[], float *pmin, float *pmax);
float meanGap(float nom[], float imp[], int size);
float tolGap(float tol[], int size);
int main()
{
FILE *ptable;
int i, num_of_parts;
int impact[10];
float nominal[10], tolerance[10];
char FV[10];
char input_str[30];
float max, min, gap, tol;
float curr_max, curr_min;
ptable=fopen("D:\\Input.txt", "r");
for(i=0; i<11; i++);
{
fgets(input_str, 30, ptable);
if(input_str[0] == 'P')
{
parsePart(input_str, &nominal[i], &impact[i], &tolerance[i], &FV[i]);
}
else
{
parseGap(input_str, &min, &max);
num_of_parts = i;
}
}
gap = meanGap(nominal, impact, num_of_parts);
tol = tolGap(tolerance, num_of_parts);
curr_max = gap+tol;
curr_min = gap-tol;
printf("Gap mean is: %f inches\n", gap);
printf("Gap tolerance is: %f inches\n", tol);
if(fabs(max-curr_max)< 0.0001 && curr_max > (gap*2)) //they are equal
{
printf("The maximum gap is %f which is greater than the allowed %f\n", curr_max, gap*2);
}
else
{
printf("The maximum gap is %f which is within the allowed %f\n", curr_max, gap*2);
}
if(fabs(min+curr_min)<0.0001 && curr_min < gap-gap)
{
printf("The minimum gap is %f which is less than the allowed %f\n", curr_min, gap-gap);
}
else
{
printf("The minimum gap is %f which is within the allowed %f\n", curr_min, gap-gap);
}
return 0;
}
void parsePart(char input[], float*pnom, int*pinp, float*ptol, char*pFV)
{
int i;
char * field[5];
field[0]=strtok(input, ",");
for(i=1; i<5; i++);
{
field[i] = strtok(NULL, ",");
}
*pnom = atof(field[1]);
*pinp = atoi(field[2]);
*ptol = atof(field[3]);
*pFV = *field[4];
}
void parseGap(char input[], float *pmin, float *pmax)
{
char *field[2];
field[0] = strtok(input, ",");
field[1] = strtok(NULL, ",");
field[2] = strtok(NULL, ",");
*pmin = atof(field[1]);
*pmax = atof(field[2]);
}
float meanGap(float nom[], float imp[], int size)
{
int i;
float sum=0;
for(i=0; i<size; i++);
{
sum += nom[i]*imp[i];
}
return sum;
}
float tolGap(float tol[], int size)
{
int i;
float sum=0;
for(i=0; i<size; i++);
{
sum += tol[i];
}
return sum;
}
The output should look something like:
Actual Gap Mean: 0.025”
Actual Gap Tolerance: 0.085”
The Maximum Gap (0.110”) is (Greater) than specified (0.080”)
The Minimum Gap (-0.060”) is (Less) than the specified (0.000”)
I get a 0 for gap mean and all the other values are incredibly large numbers.
Any and all hints as to where I could be going wrong or need improvement are great. Thank you.
In line 85, char *field[2]; should be char *field[3];.
Firstly arrays impact et al are sized at 10, so
for(i=0; i<11; i++);
Is wrong for 2 reasons:
1) loop should go from 0 to 9
2) a for statement shouldn't have a ; after it, that terminates the whole statement.
typedef struct{char c[6];} String;
String field1,field2,… …;
String *pf1,*pf2,… …;
pf1=field1;
pf2=field2;
…
…
pf1=strtok(input,…
Is the correct (outline) way to code parseGap assuming the longest data in the input file is 5 characters long,

Reading from a File to an Array - C

int main()
{
FILE* infile1;
int stockCode[15];
char stockName[100];
int stockQuantity[15];
int stockReorder[15];
int unitPrice[15];
int i;
infile1 = fopen("NUSTOCK.TXT", "r");
while(fscanf(infile1, "%d %s %d %d %f",
&stockCode, stockName, &stockQuantity, &stockReorder, &unitPrice) != EOF)
{
printf(" %3d %-18s %3d %3d %6.2f \n",
stockCode, stockName, stockQuantity, stockReorder, unitPrice);
}
fclose(infile1);
}
What I'm trying to do is to take information from a file and store it into 5 separate arrays. However, when printing out, it only prints out the name correctly.
1394854864 Prune-Basket 1394854688 1394854624 0.00
1394854864 Pear-Basket 1394854688 1394854624 0.00
1394854864 Peach-Basket 1394854688 1394854624 0.00
1394854864 Deluxe-Tower 1394854688 1394854624 0.00
The original file looks like this. So all the numbers aren't being scanned in and I can't figure out why...
101 Prune-Basket 065 060 25.00
105 Pear-Basket 048 060 30.00
107 Peach-Basket 071 060 32.00
202 Deluxe-Tower 054 040 45.00
I think what you want to do is designing a structure for saving many personal records.
And each record contain:
code
name
quantity
reorder
unitPrice
You should know the meaning of each type in C language.
I suggest you rewrite your codes like these:
#include <stdio.h>
#include <stdlib.h>
struct OneRecord{
int code;
char name[100];
int quantity;
int recorder;
float unitPrice;
};
int main(){
struct OneRecord* records = (struct OneRecord*)calloc(15, sizeof(struct OneRecord));
int i = 0;
FILE* infile1 = fopen("NUSTOCK.TXT", "r");
int max=0;
//%99s is used for max string length, because of we can protect the out of string's memory length
while((max<15)&&(fscanf(infile1, "%d %99s %d %d %f",
&records[i].code, records[i].name, &records[i].quantity, &records[i].recorder, &records[i].unitPrice) == 5))
{
i++;
max++;
}
for(i=0;i<max;i++){
printf(" %3d %-18s %3d %3d %6.2f \n",
records[i].code,records[i].name,records[i].quantity,records[i].recorder,records[i].unitPrice);
}
fclose(infile1);
free(records);
}
And how to use the C Structure in functions or many other places?
In C programming language, there are different types such as int, char, struct and so on. You can use struct like many other types.
void printRecords(const struct OneRecord* records, int max)
{
int i;
for(i=0;i<max;i++){
printf(" %3d %-18s %3d %3d %6.2f \n",
records[i].code,records[i].name,records[i].quantity,records[i].recorder,records[i].unitPrice);
}
}
You are using those arrays incorrectly. Try this:
i = 0;
while(fscanf(infile1, "%d %s %d %d %f",
stockCode+i, stockName, stockQuantity+i, stockReorder+i, unitPrice+i) != EOF)
{
printf(" %3d %-18s %3d %3d %6.2f \n",
stockCode[i], stockName, stockQuantity[i], stockReorder[i], unitPrice[i]);
i++;
}
Also, the unitPrice should be a array of float, not of int.

Segmentation Error in C program When Run

I've tried malloc, and no malloc and it will build but not run or compile. When I run the code on codepad.org it gives me a segmentation error. I have an array of structures I'm inputting and I'm searching through them for a specific item. That's as far as I got and no compile. The code is as follows (I used netbeans, codeblocks, and visual basic 2012 programs):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 20
#define BLOODTYPESIZE 4
#define MAX 120000
typedef struct {
int month;
int day;
int year;
} dateT;
typedef struct {
int hour;
int minute;
} timeT;
typedef struct {
char name[SIZE];
char organname[SIZE];
char bloodtype[BLOODTYPESIZE];
dateT dateAdded;
timeT timeAdded;
int received;
} organT;
int main(void) {
int i, n, k, j;
int c;
int *ptr;
char organ[SIZE];
char bloodkind[BLOODTYPESIZE];
organT patient[MAX];
scanf("%d",&n);
ptr = (int *)malloc(n * sizeof(*ptr));
printf("Enter patient information\n");
for(i=1; i<=n; i++){
scanf("%s", patient[i].name[SIZE]);
scanf("%s", patient[i].organname[SIZE]);
scanf("%s", patient[i].bloodtype[BLOODTYPESIZE]);
scanf("%d %d %d", patient[i].dateAdded);
scanf("%d %d", patient[i].timeAdded);
patient[i].received = 0;
}
scanf("%d", &k);
for(j=0; j<k; j++) {
gets(organ);
printf("Organ received: %s", organ);
gets(bloodkind);
printf("Organ has blood type: %s", bloodkind);
}
for (c=0; c<n; c++){
if(patient[i].organname == organ){
if(patient[i].bloodtype == bloodkind){
if(patient[i].received == 0) {
printf("Patient(s) Found!\n");
printf("%s", patient[i].name[SIZE]);
printf("Organ received: %s", organ);
patient[i].received = 1;
}
if(patient[i].received == 1)
printf("Patient already received organ\n");
}
else("Not correct blood type\n");
}
else("No match found\n");
}
return (EXIT_SUCCESS);
}
Looks like you are not using the address correctly. For example, when you say
scanf("%s", &patient[i].name[SIZE]);
you are actually reading past the allocated space for patient[i].name. You should change the statement to
scanf("%s",patient[i].name);
and fix other statements similarly.
First check n compare to MAX
here you access to bloodtype[BLOODTYPESIZE] but the last item in this tab is bloodtype[BLOODTYPESIZE-1]
scanf("%s", &patient[i].bloodtype[BLOODTYPESIZE]);
The same problem is tru for other acces in the pararagraph.

Resources