How can fscanf(), in C, be used to read a .gro file? - c

I am trying to read the following gro file via a C code.
FJP in Pol Water in water t= 0.00000 step= 0
16
1FJP P 1 5.346 7.418 0.319
2FJP P 2 5.151 7.405 0.499
3FJP P 3 5.260 7.178 0.428
4FJP P 4 5.159 6.961 0.342
5FJP P 5 5.355 6.909 0.220
6FJP P 6 5.169 6.824 0.043
7FJP P 7 5.068 6.669 11.454
8FJP P 8 4.919 6.861 11.482
9FJP P 9 4.835 7.075 11.364
10FJP P 10 4.738 6.987 11.197
11FJP P 11 4.847 7.115 10.993
12FJP P 12 4.642 7.126 10.870
13FJP P 13 4.680 6.940 10.674
14FJP P 14 4.521 7.052 10.545
15FJP P 15 4.321 6.973 10.513
16FJP P 16 4.315 6.728 10.516
11.56681 11.56681 11.56681
My code is:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[])
{
char input_file[]="file.gro";
FILE *input;
char *myfile=malloc(sizeof(char)*80);
sprintf(myfile,"%s",input_file); //the .gro file being read in
input=fopen(myfile,"r");
double dummy1,dummy6,dummy7,dummy8,dummy9,dummy10,dummy11;
int dummy2,dummy3,dummy4,dummy5;
int lines=0;
while (fscanf(input,"FJP in Pol Water in water t= %lf step= %d",&dummy1,&dummy2)==2
||fscanf(input," %d\n",&dummy3)==1
||fscanf(input," %dFJP P %d %lf %lf %lf\n",
&dummy4,&dummy5,&dummy6,&dummy7,&dummy8)==5
||fscanf(input," %lf %lf %lf\n",&dummy9,&dummy10,&dummy11)==3)
{
printf("%lf %d\n",dummy1,dummy2);
printf("%d\n",dummy3);
printf("%d %d\n",dummy4,dummy5);
printf("%lf %lf %lf\n",dummy6,dummy7,dummy8);
printf("%lf %lf %lf\n",dummy9,dummy10,dummy11);
lines=lines+1;
}
printf("lines=%d\n",lines);
fclose(input);
}
The problem is the values printed by the various dummy variables do not match what is in the file. Also, the number of lines being read is 3 as opposed to 19, which matches the file. I am not certain what is incorrect about my fscanf() statements to read this file. Any help for this problem would be much appreciated.

Your main problem is that you are assuming scanf is better than it is.
Scanf will read and parse as many arguments as it can, and then give up. It does not rewind to the start of the scanf. Also it treats spaces and newlines (and tabs) as simply "skip all whitespace"
So the line printf("%d\n",dummy3) will try to parse the main lines, eg 1FJP
It will read the digit 1 OK into dummy3, but then get stuck because P != a whitespace.
All the other rules will then get stuck, because none of them expect a P or any string first.
If you want to do it this way, you will just have to apply the scanf statements more intelligently as and when they are expected.

The problem is that you try to read and match the header repeatedly, before each line read (in the while loop.) you should read the head once, then read the lines. You also only need to skip any given piece of whitespace once. So you end up with code like:
if (fscanf(input,"FJP in Pol Water in water t=%lf step=%d%d", &dummy1, &dummy2, &dummy3) != 3) {
fprintf(stderr, "Invalid header\n");
exit(1); }
while (fscanf(input,"%dFJP P%d%lf%lf%lf", &dummy4, &dummy5, &dummy6, &dummy7, &dummy8) == 5) {
... read a line of the table

Related

Leading Zeroes not showing up in c [duplicate]

This question already has answers here:
Extra leading zeros when printing float using printf?
(2 answers)
Closed 5 years ago.
I am trying recreate a sample LC-3 simulator as an assignment, and part of that is to have a 4 digit integer. My code is as follows:
while (read_success != NULL && !done) {
// If the line of input begins with an integer, treat
// it as the memory value to read in. Ignore junk
// after the number and ignore blank lines and lines
// that don't begin with a number.
//
words_read = sscanf(buffer, "%04d", &value_read);
// if an integer was actually read in, then
// set memory value at current location to
// value_read and increment location. Exceptions: If
// loc is out of range, complain and quit the loop. If
// value_read is outside -9999...9999, then it's a
// sentinel -- we should say so and quit the loop.
if (value_read < -9999 || value_read > 9999)
{
printf("Sentinel read in place of Memory location %d: quitting loop\n", loc);
break;
}
else if (value_read >= -9999 && value_read <= 9999)
{
cpu -> mem[loc] = value_read;
printf("Memory location: %02d set to %04d \n", loc, value_read);
cpu -> count++;
loc++;
value_read = NULL;
}
if (loc > 99)
{
printf("Reached Memory limit, quitting loop.\n", loc);
break;
}
read_success = fgets(buffer, DATA_BUFFER_LEN, datafile);
// Gets next line and continues the loop
}
fclose(datafile);
I am reading values from an sdc file with the following values:
1234
3456
-4567;
2353
3434
654
0345
7655
555
9999
10000
The problem is that 0345 shows up as 345, i want 645 to be 0645, and so on.
I tried formatting %d based on a post I saw related to this, but it is not working. Any professional insight?
Edit: I did use %04d to start, but that did not work.
If you want leading zeros to be displayed, use %04d in your printf format.
The 0 is a flag used with d (among others) that says to pad on the left with zeros.

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);

Q: About reading data files using fscanf()

Am using Turbo C in a DOS emulator (Dosbox). In the following lines, I am trying to read integer and float data but only get the first (int) field. Have found much Q & A on the subject of reading files using fscanf() and, specifically, with space-delimited data but relevant info was scant or missing (mostly from the questions). Here is code demonstrating the problem:
#include <stdio.h>
int index;
float rtime, volts;
char infilename[10];
int *pti;
float *ptx;
float *pty;
FILE *infp;
void main(void)
{
infp = fopen("data1", "r");
pti = &index;
ptx = &rtime;
pty = &volts;
fscanf(infp, "%d %6.3f %6.3f", &index, &rtime, &volts);
printf("%3d %6.3f %6.3f\n", index, rtime, volts);
}
Here is the first line from the data file:
37 261.100 0.996
printf gives the following output:
37 0.000 0.000
Any obvious goofs? thx
The format %6.3f is incorrect for scanf(). You probably want %f, or possibly %7f. You cannot specify the number of decimals in a scanf() format.

c - fscanf segmentation fault

Really strange problem with fscanf. It seems as if it can't find the file. Heres the code:
char obs_file[255];
FILE *obs_fp;
strcpy(obs_file, "/aber/dap/cetaceans/data/observers_1.txt");
obs_fp = fopen(obs_file, "r");
date_time t;
fscanf(obs_fp, "%d %d %d %d %d %d\n", &t.day, &t.mth, &t.yr, &t.hrs, &t.mns, &t.scs); //This line runs fine
obs_head.obs->time = t;
printf("%d %d %d %d %d %d\n", t.day, t.mth, t.yr, t.hrs, t.mns, t.scs);
while(feof(obs_fp) == 0) {
char id[5];
char a[7];
char b[7];
location loc;
double lng = 0.0, lat = 0.0;
fscanf(obs_fp, "%s %lf %lf", id, &lat, &lng); //Seg fault here on first run of loop
loc.lat = lat;
loc.lng = lng;
add_obs_node(make_obs_node(id, loc, t));
}
File to be read:
05 11 2014 14 53 00
AB01 52.408 -4.217
It seems like the file pointer has changed somewhere around the while statement, I would understand if I was reading over the end of file, but it fails while there are definitely lines left. Also, I know Im opening the file right, as the first fscanf runs fine.
Any ideas?
Wrong use of feof() and unlimited fscanf("%s"...
feof() reports if EOF occurred due to previous IO, not if it is about to occur.
Use instead
char id[5];
double lng = 0.0, lat = 0.0;
while(fscanf(obs_fp, "%4s%lf%lf", id, &lat, &lng) == 3) {
loc.lat = lat;
loc.lng = lng;
add_obs_node(make_obs_node(id, loc, t));
}
I suspect original code failed on the 2nd iteration. Assume the last data in the file was "AB01 52.408 -4.217\n". fscanf(obs_fp, "%s %lf %lf" would scan up to the "\n" and put "\n" back into stdin as it is not part of a double. EOF flag is not set. The use of feof() signals no EOF. So fscanf(obs_fp, "%s %lf %lf" happens again, but no data is save in id, as "%s" consume leading white-space but has not non-white-space to save. Code does not check the fscanf() return value (bad), but assumes good data in id, which may be junk. Then add_obs_node() is called with an invalid string id.
Other failure mechanisms could have occurred too - need to see more code.
Bottom line: Check fscanf() results. Limit string input.
Minor: Note that the spaces between "%d %d" are not needed, but OK to have. The final "\n" is also OK but not needed. It is not simply consuming the following '\n', but any and all following white-space.
if (6 != fscanf(obs_fp, "%d%d%d%d%d%d",
&t.day, &t.mth, &t.yr, &t.hrs, &t.mns, &t.scs)) {
Handle_BadData();
}

strtok() appends some character to my string

I'm using strtok() to parse a string I get from fgets() that is separated by the ~ character
e.g. data_1~data_2
Here's a sample of my code:
fgets(buff, LINELEN, stdin);
pch = strtok(buff, " ~\n");
//do stuff
pch = strtok(NULL, " ~\n");
//do stuff
The first instance of strtok breaks it apart fine, I get data_1 as is, and strlen(data_1) provides the correct length of it. However, the second instance of strtok returns the string, with something appended to it.
With an input of andrewjohn ~ jamessmith, I printed out each character and the index, and I get this output:
a0
n1
d2
r3
e4
w5
j6
o7
h8
n9
j0
a1
m2
e3
s4
s5
m6
i7
t8
h9
10
What is that "11th" value corresponding to?
EDIT:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char buff[100];
char * pch;
fgets(buff, 100, stdin);
pch = strtok(buff, " ~\n");
printf("FIRST NAME\n");
for(i = 0; i < strlen(pch); i++)
{
printf("%c %d %d\n", *(pch+i), *(pch+i), i);
}
printf("SECOND NAME\n");
pch = strtok(NULL, " ~\n");
for(i = 0; i < strlen(pch); i++)
{
printf("%c %d %d\n", *(pch+i), *(pch+i), i);
}
}
I ran it by:
cat sample.in | ./myfile
Where sample.in had
andrewjohn ~ johnsmith
Output was:
FIRST NAME
a 97 0
n 110 1
d 100 2
r 114 3
e 101 4
w 119 5
j 106 6
o 111 7
h 104 8
n 110 9
SECOND NAME
j 106 0
o 111 1
h 104 2
n 110 3
s 115 4
m 109 5
i 105 6
t 116 7
h 104 8
13 9
So the last character is ASCII value 13, which says it's a carriage return ('\r'). Why is this coming up?
Based on your edit, the input line ends in \r\n. As a workaround you could just add \r to your list of tokens in strtok.
However, this should be investigated further. \r\n is the line ending in a Windows file, but stdin is a text stream, so \r\n in a file would be converted to just \n in the fgets result.
Are you perhaps piping in a file that contains something weird like \r\r\n ? Try hex-dumping the file you're piping in to check this.
Another possible explanation might be that your Cygwin (or whatever) environment has somehow been configured not to translate line endings in a file piped in.
edit: Joachim's suggestion is much more likely - using a \r\n file on a non-Windows system. If this is the case , you can fix it by running dos2unix on the file. But in accordance with the principle "accept everything, generate correctly" it would be useful for your program to handle this file.

Resources