最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c - Usage details of fscanf and similar functions? - Stack Overflow

programmeradmin5浏览0评论

I'm using fscanf to parse a string, and I've been using it thusly:

fscanf(file_in, "%i: %s%c%s", &current_id) == 4

Ignore the weirdness of the formatting(I know I could probably get away with replacing the %s%c%s with a single %s), because the most important specific is that the number of formatting arguments doesn't match the number of format specifiers in the string itself

The compiler throws a warning about this, and while it runs correctly, I'd like to know if there is a better way of doing this, perhaps another function?

Edit: Some people have asked for it, so here's the basic gist:

I'm writing a Todo app as practice (and for fun)

It saves data in a file, formatted thusly:

{item.id}: {item.title}{Unit Separator}{item.desc}

My current goal with fscanf was to incrementally check to see if the ID I wanted to assign to an item was already taken, and if so, increment current_id.

Nothing about this program is sophisticated in any way, and I don't intend to publish it as anything more serious than what it is: A practice project.

I'm using fscanf to parse a string, and I've been using it thusly:

fscanf(file_in, "%i: %s%c%s", &current_id) == 4

Ignore the weirdness of the formatting(I know I could probably get away with replacing the %s%c%s with a single %s), because the most important specific is that the number of formatting arguments doesn't match the number of format specifiers in the string itself

The compiler throws a warning about this, and while it runs correctly, I'd like to know if there is a better way of doing this, perhaps another function?

Edit: Some people have asked for it, so here's the basic gist:

I'm writing a Todo app as practice (and for fun)

It saves data in a file, formatted thusly:

{item.id}: {item.title}{Unit Separator}{item.desc}

My current goal with fscanf was to incrementally check to see if the ID I wanted to assign to an item was already taken, and if so, increment current_id.

Nothing about this program is sophisticated in any way, and I don't intend to publish it as anything more serious than what it is: A practice project.

Share Improve this question edited Mar 25 at 1:07 GooseyLoosey asked Mar 21 at 21:13 GooseyLooseyGooseyLoosey 233 bronze badges 7
  • 8 "it runs correctly" – only by chance. The behaviour is undefined. Consider using fgets() and then analysing the string input. – Weather Vane Commented Mar 21 at 21:22
  • 4 Your format "%i: %s%c%s" has 4 conversion specifiers but you only provide a single parameter for conversion. That's undefined behaviour -- it doesn't run "correctly" at all. – G.M. Commented Mar 21 at 21:23
  • 1 You cannot get away with replacing the %s%c%s with a single %s, even if you suppress assignment as one of your answers describes. The two have meaningfully different behavior. However, you mostly could replace %s%*c%s with %s%s. – John Bollinger Commented Mar 22 at 0:45
  • Where are the parsed values for format speciers #2 to #4 stored to "run correctly"? Looks as if you corrupt random memory areas. – Gerhardh Commented Mar 22 at 13:20
  • 1 @GooseyLoosey, the scanf family of functions is well documented in numerous places. Google "man 3 scanf" for some of them. As for the particular format %s%c%s: it scans two separate whitespace-delimited strings plus one of the whitespace characters between. Additionally, leading whitespace is discarded by %s (but not by %c), so there might be any amount of whitespace between, possibly including newlines. On the other hand, %s scans only one (whitespace-delimited) string. The two formats will consume different amounts of the input (unless the input is exhausted first). – John Bollinger Commented Mar 25 at 3:29
 |  Show 2 more comments

3 Answers 3

Reset to default 4

You can use * right after the % which indicates assignment suppression, i.e. nothing will be assigned as a result of matching that particular format specifier.

fscanf(file_in, "%i: %*s%*c%*s", &current_id) == 1

Note that this will now return the number of items matched and assigned.

Consider using %d instead of %i. If there are any values with a leading 0, %i will assume the value is base 8 ( octal). Scanning 058 or 059, using %i, will only store 5 as the digits 8 and 9 are not valid octal digits. %d will store 58 or 59.

if ( fscanf ( file_in, "%d", &current_id) == 1) will be true if an integer is successfully scanned. If an integer isn't scanned, the return will be 0. The other possible return value is EOF. This will not detect some errors such as overflow. As mentioned it may be better to use fgets to read a line, then strtol to parse the integer to get better error detection.

fscanf ( file_in, "%*[^\n]") can be used to scan and discard everything up to a newline.

fscanf ( file_in, "%*1[\n]") will scan and discard one character that must be a newline (if you want to consume the newline). %d will consume any leading whitespace.

It would be helpful if you would post a few lines from the file.

Something similar to this might be used to read the file.

int result = 0;
do {
    if ( 1 == ( result = fscanf ( file_in, "%d", &current_id))) {
        // do something with current_id
    }
    if ( EOF == result) {
        fprintf ( stderr, "problem EOF\n");
        exit ( EXIT_FAILURE);
    }
    fscanf ( file_in, "*[^\n]"); // scan and discard rest of line up to newline
    fscanf ( file_in, "*1[\n]"); // scan and discard one character that must be a newline
} while ( 0 == result);

But without knowing what the file contains, it might not work correctly.

Rather than fscanf(file_in, "%i: %s%c%s", &current_id) == 4, use fgets() to read a line from the file into a string. Then parse the string. Use " %n" to determine if the entire line was properly parsed.

#define LINE_SIZE_MAX 256
char buf[LINE_SIZE_MAX];
if (fgets(buf, sizeof buf, file_in)) {
  int n = 0;
  sscanf(buf, "%i: %*s%*c%*s %n", &current_id, &n);
  //  v---v---------------------- Did scan reach the end of the format?
   // |   |    v------------v---- Was that end of scanning the end of the line?
  if (n > 0 && buf[n] == '\0') {
    // Success
    printf("current_id: %d\n", current_id);
  } else {
    // Failure
  } 
发布评论

评论列表(0)

  1. 暂无评论