I'm trying to write a program that reads in a .pdb file, which is a file type used in biology applications. This type of file has a standard format with varying white space between data. The file is of the form
ATOM 4 N ALA 1 2.670 1.801 1.072 0.00 0.00
ATOM 5 CA ALA 1 3.225 3.144 1.197 0.00 0.00
ATOM 6 C ALA 1 4.408 3.341 0.256 0.00 0.00
ATOM 7 O ALA 1 4.553 4.394 -0.363 0.00 0.00
.... . .. ... . ..... ..... ..... ..... ....
So my program (probably poorly written) defines a structure, reads in the data (which I stole from another post here http://www.daniweb.com/software-development/c/threads/65455/reading-a-file-using-fscanf#), and stores it into an indexed struct. Now if I print the values inside of the inner if-loop, it spits out the correct data. However, when I print out the same values outside the outer while-loop, it gives me the wrong atom[].name (which just so happens to be HA, the last value in the 3rd column of data in the input file. All other values are correct.
Here is my program
#include <stdio.h>
typedef struct
{
char *atm;
int serial;
char *name;
char *resName;
int resSeq;
double x;
double y;
double z;
double occupancy;
double tempFactor;
} pdb;
int main(int argc, char** argv)
{
int i, j;
pdb atom[28];
char atm[5];
char name[3];
char resName[4];
int serial;
int resSeq;
double x;
double y;
double z;
double occupancy;
double tempFactor;
char buff[BUFSIZ];
FILE *file = fopen("test.pdb", "r");
i = 0;
while (fgets(buff, sizeof buff, file) != NULL)
{
if (sscanf(buff, "%s %d %s %s %d %lf %lf %lf %lf %lf",
atm, &serial, name, resName, &resSeq, &x, &y, &z,
&occupancy, &tempFactor) == 10)
{
atom[i].atm = atm;
atom[i].serial = serial;
atom[i].name = name;
atom[i].resName = resName;
atom[i].resSeq = resSeq;
atom[i].x = x;
atom[i].y = y;
atom[i].z = z;
atom[i].occupancy = occupancy;
atom[i].tempFactor = tempFactor;
i++;
/*printf("%s ", atom[i].atm);
printf("%d ", atom[i].serial);
printf("%s ", atom[i].name);
printf("%s ", atom[i].resName);
printf("%d ", atom[i].resSeq);
printf("%lf ", atom[i].x);
printf("%lf ", atom[i].y);
printf("%lf ", atom[i].z);
printf("%lf ", atom[i].occupancy);
printf("%lf\n", atom[i].tempFactor);*/
}
}
fclose(file);
for (j = 0; j < i; j++)
printf("%d of %d: %s\n", j, i-1, atom[j].name);
return(0);
}
Any idea why this might be happening? In addition, any help on the program format/structure would also be appreciated. I'm more of a Fortran guy, so C structures are out of my realm of expertise.
Thanks in advance.
EDIT: jsn helped me out and Randy Howard refined it. Here is the updated and working program:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
char *atm;
int serial;
char *name;
char *resName;
int resSeq;
double x;
double y;
double z;
double occupancy;
double tempFactor;
} pdb;
int main(int argc, char** argv)
{
int i, j;
pdb atom[28];
int serial;
int resSeq;
double x;
double y;
double z;
double occupancy;
double tempFactor;
char buff[BUFSIZ];
FILE *file = fopen("test.pdb", "r");
i = 0;
while (fgets(buff, sizeof buff, file) != NULL)
{
char *atm = malloc(sizeof(char) * 5);
char *name = malloc(sizeof(char) * 3);
char *resName = malloc(sizeof(char) * 4);
if (sscanf(buff, "%s %d %s %s %d %lf %lf %lf %lf %lf",
atm, &serial, name, resName, &resSeq, &x, &y, &z,
&occupancy, &tempFactor) == 10)
{
atom[i].atm = atm;
atom[i].serial = serial;
atom[i].name = name;
atom[i].resName = resName;
atom[i].resSeq = resSeq;
atom[i].x = x;
atom[i].y = y;
atom[i].z = z;
atom[i].occupancy = occupancy;
atom[i].tempFactor = tempFactor;
i++;
}
}
fclose(file);
for (j = 0; j < i; j++)
{
printf("%s ", atom[j].atm);
printf("%d ", atom[j].serial);
printf("%s ", atom[j].name);
printf("%s ", atom[j].resName);
printf("%d ", atom[j].resSeq);
printf("%lf ", atom[j].x);
printf("%lf ", atom[j].y);
printf("%lf ", atom[j].z);
printf("%lf ", atom[j].occupancy);
printf("%lf\n", atom[j].tempFactor);
}
return(0);
}
Inside the while loop you need to allocate new memory for each char* for each name. You are overwriting them right now.
while (fgets(buff, sizeof buff, file) != NULL)
{
char *atm = malloc(sizeof(char) * 5);
char *name = malloc(sizeof(char) * 3);
char *resName = malloc(sizeof(char) * 4);
if (sscanf(buff, "%s %d %s %s %d %lf %lf %lf %lf %lf",
atm, &serial, name, resName, &resSeq, &x, &y, &z,
&occupancy, &tempFactor) == 10)
You are copying the char array (pointers), so all the names should be the same (the last entry).
Related
I'm trying to take inputs with fscanf and to give output to another file but fscanf doesn't give the input it should give.
Here is my code:
#include <stdio.h>
int main() {
FILE *a;
FILE *b;
int i;
int played_matches, points, goaldif, ranking;
int wins, draws, losses, goals_scored, goals_against;
char team[18];
a = fopen("source.docx", "r");
b = fopen("aim.doc", "w");
for (i = 0; i < 10; i++) {
fscanf(a, "%d %s %d %d %d %d %d", &ranking, &team, &wins, &draws, &losses, &goals_scored, &goals_against);
played_matches = wins + draws + losses;
points = (3 * wins) + draws;
goaldif = goals_scored - goals_against;
fprintf(b, "%d %s %d %d %d ", ranking, team, played_matches, points, goaldif);
}
fclose(a);
fclose(b);
return 0;
}
#include <stdio.h>
int main() {
FILE *a;
FILE *b;
int i;
int played_matches, points, goaldif, ranking;
int wins, draws, losses, goals_scored, goals_against;
char team[18];
a = fopen("source.txt", "r");
b = fopen("aim.txt", "w");
for (i = 0; i < 10; i++) {
fscanf(a, "%d %s %d %d %d %d %d", &ranking, team, &wins, &draws, &losses, &goals_scored, &goals_against);
played_matches = wins + draws + losses;
points = (3 * wins) + draws;
goaldif = goals_scored - goals_against;
fprintf(b, "%d %s %d %d %d \n", ranking, team, played_matches, points, goaldif);
}
fclose(a);
fclose(b);
return 0;
}
& is for integer values.
I have the following code for reading files in C. It's reading from files but not like its supposed to be. It is showing up like this:
instead of like this:
Although I am calling the same print function. We are taking records for 4 employees. I know it's a logical error but I am unable to solve it.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct employee {
float hoursWorked, hourlyRate, federalTax, stateTax;
char name[20];
};
struct calc
{
float grosspay, fto, sto, np;
};
void print(struct employee s[], struct calc c[], int n)
{
for (int i = 0; i < 4; i++)
{
printf("\n%s's gross pay: $%.02f\n", s[i].name, c[i].grosspay);
printf("Federal tax owed: $%.02f\n", c[i].fto);
printf("State tax owed: $%.02f\n", c[i].sto);
printf("Net pay: $%.02f \n\n", c[i].np);
printf("\n");
}
}
void savetext(struct employee s[], struct calc c[], int n)
{
FILE *f;
f = fopen("employee.txt", "w");
for (int i = 0; i < n; i++)
{
fprintf(f, "%s\n", s[i].name);
fprintf(f, "%f %f %f %f\n", s[i].hoursWorked, s[i].hourlyRate, s[i].federalTax, s[i].stateTax);
fprintf(f, "%.2f %.2f %.2f %.2f\n", c[i].grosspay, c[i].fto, c[i].sto, c[i].np);
}
fclose(f);
}
void retrievetext(struct employee s[], struct calc c[], int n)
{
FILE *f;
int length;
f = fopen("employee.txt", "r");
for (int i = 0; i < n; i++)
{
fgets(s[i].name, sizeof(s[i].name), f);
length = (int)strlen(s[i].name);
s[i].name[length - 1] = '\0';
fscanf(f, "%f %f %f %f\n", &s[i].hoursWorked, &s[i].hourlyRate, &s[i].federalTax, &s[i].stateTax);
fscanf(f, "%.2f %.2f %.2f %.2f\n", &c[i].grosspay, &c[i].fto, &c[i].sto, &c[i].np);
}
fclose(f);
}
void savebin(struct employee s[], int n)
{
FILE *f;
f = fopen("employee.bin", "wb");
for (int i = 0; i < n; i++) {
fwrite(&s, sizeof(s[n]), n, f);
}
fclose(f);
}
void retrievebin(struct employee s[], int n)
{
FILE *f;
f = fopen("employee.bin", "rb");
for (int i = 0; i < n; i++) {
fread(&s, sizeof(s[i]), n, f);
}
fclose(f);
}
int main(){
savetext(st, c, 4);
retrievetext(st, c, 4);
printf("After reading text file");
print(st, c, 4);
savebin(st, 4);
retrievebin(st, 4);
printf("After reading bin file");
print(st, c, 4);
return 0;
}
You didn't get a warning here from this?
fscanf(f, "%.2f %.2f %.2f %.2f\n", &c[i].grosspay, &c[i].fto, &c[i].sto, &c[i].np);
fscanf() will eat any float you throw at it, specifying the %.2f format like this doesn't really work.
https://en.wikipedia.org/wiki/Scanf_format_string
Try using it like this:
fscanf(f, "%f %f %f %f\n", &c[i].grosspay, &c[i].fto, &c[i].sto, &c[i].np);
It was probably reading the file wrong, and then using the wrong line as an employee name.
PS: Your print() might have a small error:
for (int i = 0; i < 4; i++) // It should probably be i < n, instead of i < 4
And try to include an example input file, so people can test the code. At main(), there is no definition of st, so it's hard for people to see what's really happening if they can't test it themselves.
I am having some trouble with an assignment. I am trying to read the lines from a txt file (line by line) split the values and calculate the quadratic formula from them; the lines always contain a, b and c. However, I came to a problem where it looks like when I come to the formula the values seem to be the pointer position instead of the value assigned. I don't think the finalArrayOfValues should be a char* but the code wouldn't compile without it. Is there any way to retrieve the value from the pointer or should I try a different solution?
Apologies in advance if this is trivial (coming from javascript and python) I am quite new to c,
Thank you.
#include <math.h>
#include <stdio.h>
#include <string.h>
int main(void) {
double a;
double b;
double c;
double d;
char arrayOfValues[100][128];
char lines[128];
char *finalArrayOfValues[3];
int i = 0;
double root1, root2;
FILE *file; /* declare a FILE pointer */
file = fopen("QFData1.txt", "r");
int count = 0;
while (fgets(lines, 128, file)) {
strcpy(arrayOfValues[count], lines);
printf("line %d: %s\n", count, arrayOfValues[count]);
count++;
}
char *string = arrayOfValues[1];
char *token = strtok(string, ",");
// loops through the string to extract all other tokens
for (int n = 0; n < 3; n++) {
finalArrayOfValues[i] = token;
printf(" %s\n", token);
token = strtok(NULL, ",");
i++;
}
printf(" %s\n", finalArrayOfValues[0]);
printf(" %s\n", finalArrayOfValues[1]);
printf(" %s\n", finalArrayOfValues[2]);
a = finalArrayOfValues[0] - "0";
b = finalArrayOfValues[1] - "0";
c = finalArrayOfValues[2] - "0";
printf(" %f\n", a);
printf(" %f\n", b);
printf(" %f\n", c);
d = b * b - (4 * a * c);
printf(" %f\n", d);
// real roots
root1 = (-b + sqrt(d)) / (2 * a);
root2 = (-b - sqrt(d)) / (2 * a);
printf("First root = %.2lf\n", root1);
printf("Second root = %.2lf\n", root2);
return 0;
}
I am trying to read from 2 files (f1.txt and f2.txt) using structures and print them out to the third file (f3.txt), but I seem to be getting some errors. Issues did not occur before I tried printing out the values to the file (fprintf command), and I cant seem to find a way to fix it..
This is for a homework assignment, but since I've been struggling to fix this issue for months now (yes, I'm pretty bad), I thought maybe anyone here knows how I can fix this.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAX_NIME_PIKKUS 100
#define MAX_AINE_PIKKUS 100
#define MAX_KOOD 10
#define MAX_HINNE 5
#define DEBUG 0
int n;
int m;
struct Tudeng{
char Nimi[MAX_NIME_PIKKUS];
char Kood[MAX_KOOD];
};
struct Tudeng *pTudeng;
struct Aine{
char Nimetus[MAX_AINE_PIKKUS];
char aineKood[MAX_KOOD];
};
struct Aine *pAine;
struct Tud{
char Tudengikood[MAX_KOOD];
int Hinne[MAX_HINNE];
};
struct Tud *pTud;
char f1[] = "f1.txt";
char f2[] = "f2.txt";
char f3[] = "f3.txt";
FILE *fp1,*fp2,*fp3;
int sisendf1_kontroll();
int sisendf2_kontroll();
void tekita_failid();
void andmed_failidesse(char Tudeng1, char Tudeng2, char Aine1, char Aine2, char Tud1, int Tud2);
int main(void){
int a;
int b;
int c;
n = sisendf1_kontroll();
printf("Failist %s loeti %d tudengi andmed.\n", f1, n);
m = sisendf2_kontroll();
printf("Failist %s loeti %d aine andmed.\n", f2, m);
fp1 = fopen(f1,"r");
fp2 = fopen(f2, "r");
int i = 0;
a = sizeof(struct Tudeng);
b = sizeof(struct Aine);
c = sizeof(struct Tud);
pTudeng = malloc(a * n);
pAine = malloc(b * m);
pTud = malloc(c * m);
if(DEBUG)printf("Struktuuri Tudeng baidi aadress on %p, ühe kirje andmeteks eraldati mälu %d baiti, mälu eraldati massiivile kokku %d baiti \n", pTudeng, a, a * n);
if(DEBUG)printf("Struktuuri Aine baidi aadress on %p, ühe kirje andmeteks eraldati mälu %d baiti, mälu eraldati massiivile kokku %d baiti \n", pAine, b, b * m);
if(DEBUG)printf("Struktuuri Tud baidi aadress on %p, ühe kirje andmeteks eraldati mälu %d baiti, mälu eraldati massiivile kokku %d baiti \n", pTud, c, c * m);
int loopiks;
while(loopiks == 0){
while(!feof(fp1)){
fscanf(fp1,"%s",(pTudeng+i)->Nimi);
fscanf(fp1,"%s",(pTudeng+i)->Kood);
i++;
}
while(!feof(fp2)){
fscanf(fp2,"%s",(pAine+i)->Nimetus);
fscanf(fp2,"%s",(pAine+i)->aineKood);
fscanf(fp2,"%s",(pTud+i)->Tudengikood);
fscanf(fp2,"%d",(pTud+i)->Hinne);
i++;
}
loopiks = 1;
tekita_failid();
andmed_failidesse((pTudeng+i->Nimi), (pTudeng+i)->Kood, (pAine+i)->Nimetus, (pAine+i)->aineKood, (pTud+i)->Tudengikood, (pTud+i)->Hinne);
free(pTudeng);
free(pAine);
free(pTud);
}
//fprintf(fp3, "%s %s\n",(pTudeng+i)->Nimi,(pTudeng+i)->Kood);
fclose(fp1);
fclose(fp2);
return 0;
}
int sisendf1_kontroll(void){
char rida[122];
int n = 0, p;
fp1 = fopen(f1,"r");
if(fp1 == NULL){
printf("Sisendfaili %s avamine ebaonnestus!", f1);
exit(1);
}else{
while(!feof(fp1)){
fgets(rida, 122, fp1);
p = strlen(rida);
if (p > 1) n++;
}
}
fclose(fp1);
return n;
}
int sisendf2_kontroll(void){
char rida2[122];
int m = 0, o;
fp2 = fopen(f2,"r");
if(fp2==NULL){
printf("Sisendfaili %s avamine ebaonnestus!", f2);
exit(1);
}else{
while(!feof(fp2)){
fgets(rida2, 122, fp2);
o = strlen(rida2);
if (o > 1) m++;
}
}
fclose(fp2);
return m;
}
void tekita_failid(){
fp3 = fopen(f3, "w");
fclose(fp3);
return;
}
void andmed_failidesse(char Tudeng1, char Tudeng2, char Aine1, char Aine2, char Tud1, int Tud2){
fp3 = fopen(f3, "a");
int i;
int j;
while(i < n && j < m){
for(i = 0; i < n; i++){
fprintf(fp3, "%s %s ",(pTudeng+i)->Nimi,(pTudeng+i)->Kood);
}
for(j = 0; j < m; j++){
fprintf(fp3, "%s %s %s %d \n",(pAine+i)->Nimetus,(pAine+i)->aineKood, (pTud+i)->Tudengikood, (pTud+i)->Hinne);
}
}
return;
}
I expected the program to output the information from f1.txt and f2.txt to f3.txt, but currently compiler tells me that I cannot do that, since I'm using * int in last function, but it says that regular int is required.
Compiler is right:
andmed_failidesse expects an int as last parameter and you're passing Hinne which is an array of int, aka int*.
As Tud2 is not used anyway in your current code you can remove it from function signature or rework your function to use it.
Your compiler should also warn you that you have other unused parameters in your function.
It is obviously a work in progress: take a break, re-read your C courses and try to figure out what your function is supposed to do, and which parameters it needs.
I am to read from a .ssv file and create a student database which contains: Name, ID, Exam1, Exam2, Project1, Project2, Average and Grade(letter). The average is not in the file, hence it having to be calculated. I am unsure of my average calculation and my structure declaration. Any other fixes would be welcomed.
#include <stdio.h>
typedef struct {
char name[26];
int I_D[25];
int exam[3];
int project[3]
float average[3];
char grade[3];
} STUDENT;
void printStuAry(int size, STUDENT stuAry[]);
int main(int argc, char* argv[])
{
if (argc != 2) {
printf("ERROR\n");
return 1;
}
STUDENT stuAry[5];
FILE* f = fopen(argv[1], "r");
if (f == NULL) {
printf("Error opening file %s.\n", argv[1]);
return 1;
}
char line[65];
int ind = 0;
while (fgets(line, sizeof(line), f) != NULL) {
sscanf(line, "%25[^;] ; %d %d %d %d %d %c",
stuAry[ind].name,
&stuAry[ind].I_D,
&stuAry[ind].exam[0],
&stuAry[ind].exam[1],
&stuAry[ind].project[0],
&stuAry[ind].project[1]
&stuAry[ind].grade);
float stuAry.average = stuAry.exam[0] + stuAry.exam[1] + stuAry.project[0] + stuAry.project[1]/4;
ind++;
}
printStuAry(5, stuAry);
if (fclose(f) == EOF) {
printf("Error closing file %s.\n", argv[1]);
return 1;
}
return 0;
}
void printStuAry(int size, STUDENT stuAry[])
{
for (int i=0; i<size; i++) {
printf("Student \"%s\" score %d, %d and %d and %d on midterms, "
"and %c on the final.\n",
stuAry[i].name, stuAry[i].exam[0],
stuAry[i].exam[1], stuAry[i].project[0],
stuAry[i].project[1], stuAry[i].average,
stuAry[i].final);
}
}
I will not rewrite the code for you, just indicate your errors.
int I_D[25];
why an array for the id, just an integer
int exam[3];
int project[3]
Since you have only 2 exams and 2 projects, the sizes should be 2.
missing ;
float average[3];
char grade[3];
should not be arrays...
while (fgets(line, sizeof(line), f) != NULL) {
sscanf(line, "%25[^;] ; %d %d %d %d %d %c", etc...
The correct way to read a well-formatted file is like this:
while(7 == fscanf(f, "%25[^;] ; %d %d %d %d %d %c", etc..))
float stuAry.average = stuAry.exam[0] + stuAry.exam[1] + stuAry.project[0] + stuAry.project[1]/4;
parenthesize the sum
divide by 4.0 to avoid integer division and get a float division with a float result
index the array by [ind] to work on the current student.
stuAry[ind].average = (stuAry[ind].exam[0] + stuAry[ind].exam[1] + stuAry[ind].project[0] + stuAry[ind].project[1])/4.0;
There are may be other errors but this should get you some good start