-6

I am working on a project where I will have either read or write commands and then an address on a single line in a file. The format will be as follows:

R 0x...
W 0x...

And the file is thousands of lines long. I am attempting to read the command and put it in buf1 and read the address into buf2. I have attempted to do this with fgets / fgetc, as well as fscanf with "%*c %s" and the other way around. Each time I do this, buf2 will grab the address correctly but the command is very hit or miss. Here is my code:

char buf1, buf2[64];
int readcount = 0, writecount = 0, other = 0;
while(!feof(trace)){
printf("\nFile is open");
fgetc(trace);
fgets(buf2,16,trace);
printf("\nBuf1 is: %c",buf1);
printf("\nBuf2 is: %s",buf2);

and the output that I keep getting is:

The address is: E  
File is open  
Buf1 is: ?  
Buf2 is:  0x123456  

The address is: V  
File is open  
Buf1 is: ?  
Buf2 is:  0x234567  

The address is: g  
File is open  
Buf1 is: ?  
Buf2 is:  0x345678  

The address is: x  
File is open  
Buf1 is: ?  
Buf2 is:  0x345678  

I have a feeling that the problem is my understanding of the file-reading functions. Why isn't buf1 reading correctly?

Jenks
  • 53
  • 8
  • 3
    Welcome to SO. Please do not post links to your code. Add it here directly in your question. And also don't post pictures of code. Use copy&paste instead to insert the text in your question. – Gerhardh Mar 11 '19 at 18:05
  • It wouldn't let me post the pictures directly which is why i embedded it as such. Thanks for your help – Jenks Mar 11 '19 at 18:09
  • 2
    You should noti add pictures of code. Show the code as text. – Gerhardh Mar 11 '19 at 18:14
  • Buf2 is designed to be 64 bits as there could be 64-bit addresses in the files. I'm not sure if this helps or not. – Jenks Mar 11 '19 at 19:04
  • @Jenks what about my answer ? (and do not use _feof_) – bruno Mar 11 '19 at 19:09
  • 1
    You do not assign anything to `buf1` – Gerhardh Mar 12 '19 at 05:21
  • Read [How to debug small programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) and read much more about [parsing](https://en.wikipedia.org/wiki/Parsing) concepts and techniques (e.g. read the [Dragon book](https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools)) – Basile Starynkevitch Mar 12 '19 at 12:33
  • BTW, it is much better to *end* (not start) your `printf` format control strings with `\n`. Or read about line-buffering and `fflush` – Basile Starynkevitch Mar 12 '19 at 12:35
  • @bruno could you elaborate on why I shouldn't use feof? – Jenks Mar 12 '19 at 15:03
  • @Gerhardh I realized that I didn't set buf1 = fgetc and now it works correctly – Jenks Mar 12 '19 at 15:04
  • 1
    @Jenks look at https://stackoverflow.com/questions/5431941/why-is-while-feoffile-always-wrong?r=SearchResults&s=1|168.8280 for instance – bruno Mar 12 '19 at 15:04
  • Thanks @bruno you've been very helpful! – Jenks Mar 12 '19 at 15:36
  • @Jenks this is why it is very important to show us a complete example. Otherwise we don't know whether it is missing in your code or only in the snippet in your question. – Gerhardh Mar 12 '19 at 18:19
  • @Gerhardh in this case my code is several hundred lines long and this is the only portion that is giving me issues. For future reference would it still be better to post the complete code? – Jenks Mar 12 '19 at 20:05
  • "Complete" does not mean that it is your complete program. It must be a minimal complete program. All the hundreds of lines not related to your problem need to be removed to get a "Minimal complete verifyable example" [MCVE](https://stackoverflow.com/help/mcve). – Gerhardh Mar 12 '19 at 20:24

1 Answers1

2

(I did that answer while R 0x... and W 0x... was given on the same line rather than two)

If you are sure each line of the file contains R<space>0x...<space>W<space>0x... then you can do

int main()
{
  FILE * fp = fopen("in", "r");

  if (fp == NULL) {
    puts("cannot open 'in'");
    return -1;
  }

  char line[100];

  while (fgets(line, sizeof(line), fp)) {
    char c1, c2;
    unsigned n1, n2;

    errno = 0;
    if ((sscanf(line, "%c %x %c %x", &c1, &n1, &c2, &n2) == 4) && !errno) {
      // just to indicate it read well
      printf("%c:%x:%c:%x\n", c1, n1, c2, n2);
    }
    else {
      printf("invalid line %s\n", line);
    }
  }

  puts("done");
  fclose(fp);
}

Compilation and execution

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra f.c
pi@raspberrypi:/tmp $ cat in
R 0x1 W 0x2
A 0x123 Z 0x345
C 0x0 Z 0x678
pi@raspberrypi:/tmp $ ./a.out
R:1:W:2
A:123:Z:345
C:0:Z:678
done

Note I first read the line to not be disturbed by the newline etc


If you can have several spaces and/or may be tabs between the field and/or even at the beginning of the line you can use strtok :

#include <stdio.h>
#include <string.h>
#include <errno.h>

int getChar(char * c, char * s, int n)
{
  if (s == NULL) {
    printf("field %d is missing\n", n);
    return 0;
  }
  if (s[1] != 0) {
    printf("invalid field %d : '%s'\n", n, s);
    return 0;
  }

  *c = s[0];
  return 1;
}

int getUnsigned(unsigned * u, char * s, int n)
{
  if (s == NULL) {
    printf("field %d is missing\n", n);
    return 0;
  }

  char c;

  errno = 0;
  if ((sscanf(s, "%x%c", u, &c) != 1) || (errno != 0)) {
    printf("invalid field %d : '%s'\n", n, s);
    return 0;
  }

  return 1;
}

int main()
{
  FILE * fp = fopen("in", "r");

  if (fp == NULL) {
    puts("cannot open 'in'");
    return -1;
  }

  char line[100];

  while (fgets(line, sizeof(line), fp)) {
    char c1, c2;
    unsigned n1, n2;

    if (getChar(&c1, strtok(line, " \t"), 0) &&
        getUnsigned(&n1, strtok(NULL, " \t"), 1) &&
        getChar(&c2, strtok(NULL, " \t"), 2) &&
        getUnsigned(&n2, strtok(NULL, " \t\n"), 3)) /* warning \n is added */
      // just to indicate it read well
      printf("%c:%x:%c:%x\n", c1, n1, c2, n2);
  }

  puts("done");
  fclose(fp);
}

Compilation and execution :

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra ff.c
pi@raspberrypi:/tmp $ cat in
 R 0x1   W  0x2
A    0x123 Z 0x345
    C 0x0  Z     0x678
pi@raspberrypi:/tmp $ ./a.out
R:1:W:2
A:123:Z:345
C:0:Z:678
done
bruno
  • 32,421
  • 7
  • 25
  • 37
  • I believe that the first edition of the question didn't format the question properly. The format is "W 0x... \nR 0x...." and so the same technique would still work, yes? also I didn't know that you could use %x as a format control string. Is that standard? – Jenks Mar 12 '19 at 15:11
  • @Jenks adapt the sscanf to read only a character and the number rather than two couples of them and of course replace `== 4` by `== 2`. in the _strtok_ version of course read 1 couple rather than 2. I use `%x` because the number is in hexadecimal, yes this is standard – bruno Mar 12 '19 at 15:24