简体   繁体   中英

C: Matching a single space in a scanf

I just want to force a scanf to read a single space and then store the rest of the string until a comma is found in a variable. I cannot do it like this:

char content[100];
fscanf(f, " %[^,\n],", content);

because I don't want content to be set if there is a pending '\\n' . Is there a way to scape the whitespace?

The workaround I've found so far:

char space;
fscanf(f, "%1[^\n]%[^,\n],", &space, content);

Sorry for the silly question and thank you in advance.

I'm supposing that the code you presented expresses your intent better than your words, which don't correspond on the details. Inasmuchas you say ...

The workaround I've found so far:

 char space; fscanf(f, "%1[^\\n]%[^,\\n],", &space, content); 

... I conclude that that code seems to you to do what you want, and I infer that you designate it a "workaround" instead of a wholly satisfactory solution on account of the need for the space variable to be involved.

Indeed, it's worse than that: whenever scanf() successfully matches the first field, it invokes undefined behavior by overrunning the bounds of space . That happens because the [ field descriptor matches nonempty strings , which have a terminator after their content. But the good news is that getting rid of the need for the extra variable, which you seem to want to do anyway, will solve that problem, too.

The easiest way to do that would be to apply the assignment-suppression modifier ( * ) to the corresponding field descriptor:

fscanf(f, "%*1[^\n]%[^,\n],", content);

Do be sure to check the return value to determine whether anything was assigned to content . It will be 1 if a non-empty string was matched and assigned to content (after matching but not assigning the leading newline), -1 if the file f was initially positioned at its end or if an I/O error occurs, or 0 if a matching failure occurs before assigning content .

Update :

As @chux observed, the scanf format above does nothing to protect against overrunning the bounds of content in the event that the corresponding data is wider than it can accommodate. Since you're declaring it as an array of 100 char , it can accommodate up to 99 characters plus a terminator, which you can ensure is not overrun like so:

fscanf(f, "%*1[^\n]%99[^,\n],", content);

That leaves you with the possibility that scanning stops before either a newline or a comma is seen, however, and the return value will not help you distinguish that case from a wholly successful scan. In that event, the next scan will yield a matching failure (supposing that the same format is used). There is more than one way to address that, but you might consider omitting the trailing comma from your format, and instead checking for a comma and consuming it separately via a call to fgetc() .

And you have to use fscanf() because...?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

size_t myScan (
    const char * string,
    char * outBuffer,
    size_t outBufferMax
) {
    // No string
    if (!string) return 0;
    // First char not a space
    if (string[0] != ' ') return 0;
    // Find semicolon
    size_t size = 0;
    while (string[size + 1] != 0 && string[size + 1] != ';') size++;
    // Doesn't fit into buffer!
    if (size > outBufferMax) return 0;

    memcpy(outBuffer, &string[1], size);
    return size;
}


int main ( ) {
    size_t size = 0;
    char content[100] = { 0 };
    char * test = " Hello World; Test Test; Foobar!";

    size = myScan(test, content, sizeof(content));
    printf("###%.*s###\n", (int)size, content);

    size = myScan(&test[6], content, sizeof(content));
    printf("###%.*s###\n", (int)size, content);

    size = myScan(&test[13], content, sizeof(content));
    printf("###%.*s###\n", (int)size, content);

    size = myScan(&test[24], content, sizeof(content));
    printf("###%.*s###\n", (int)size, content);

    // No position with a space in front!
    size = myScan(&test[22], content, sizeof(content));
    printf("###%.*s###\n", (int)size, content);


    return 0;
}

Output:

###Hello World###
###World###
###Test Test###
###Foobar!###
######

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM