2

My aim is to extract the value and a key separated by an =. My initial idea was to use something like %s=%s, but unfortunately it doesn't work.

So I have a file:

A=1
B=2

So I open the file:

char *key;
char *value;

FILE* file = fopen("./file", "r");
do {
  fscanf(file, "%[^'=']=%[^'\n']\n", key, value);
  printf("key:%s value:%s\n", key, value);
} while(!feof(file));

However both key and value return:

key:1 value:1
key:2 value:2

Any idea why my expression is not matching?.

alk
  • 69,737
  • 10
  • 105
  • 255
piggyback
  • 9,034
  • 13
  • 51
  • 80

5 Answers5

2

key and value variables must be allocated, e.g.

char key[100];
char value[1000];

Then use them.

alk
  • 69,737
  • 10
  • 105
  • 255
Dr. Debasish Jana
  • 6,980
  • 4
  • 30
  • 69
1
char key[16];//char *key;//not point to memory for store.
char value[16];

FILE *file = fopen("./file", "r");
while(2==fscanf(file, " %[^=]=%[^\n]", key, value)){
  printf ("key:%s value:%s\n", key, value);
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
1

Your pointers are uninitialized. Reading them is undefined in C. You can use arrays (if you know the maximal lengths at compile-time) or allocate memory with malloc.

Read the *scanf documentation carefully, these functions are a little tricky.

"%s=%s" cannot match, %s consumes all = signs so the following = is always a matching failure (the next character after %s is always a whitespace or EOF).

When reading strings, always use a maximum field width (in some cases, it can be omitted safely, but only for sscanf). Unfortunately, you have to hard-code that value (or build up the format string at run-time, but I wouldn’t advise you to do so).

I'm not sure what the ' in the scan sets are supposed to do, %[^'='] is equivalent to %[^'=] and matches everything but ' and =. You’ve probably meant %[^=].

Every white-space character in the format string (outside a scan set) is treated equally as "skip any white-space", that is, a space () is the same as a newline. The whole format string is equivalent to

"%[^'=]=%[^'\n] " // Note the space at the end

To match a literal newline, you need to use a scanset (with a length).

Always check the return value of *scanf (also for fopen and any other function which can fail).

char key[64];   // Or whatever is appropriate for you,
char value[64]; // remember the 0-terminator needs one byte

FILE *file = fopen("./file", "r");
if(!file) {
    perror("./file");
    exit(1);
}
for(;;) {
    int e = fscanf(file, "%63[^=]=%63[^\n]%1[\n]", key, value, (char[2]){ 0 });
    if(e == -1) {
        if(ferror(file)) {
            perror("reading from ./file");
            // handle read error
        } else { // EOF reached on first character of line
            break;
        }
    } else if(e < 3) {
        // handle invalid input
    } else {
        printf("key:%s value:%s\n", key, value);
    }
}

Alternatively, you could use assignment-suppression for the last newline as in "%63[^=]=%63[^\n]%*1[\n]" and omit the last argument to fscanf. By doing so, you can no longer detect if the last line ended in a newline.

mafso
  • 5,433
  • 2
  • 19
  • 40
0

My initial idea was to use something like %s=%s, but unfortunately it doesn't work.

Thats simply because *scanf does not respect non-whitespace delimiters as you suspected. Furthermore, it does not support real regular expressions. Only a certain simple type of character classes [..] are supported.

To your problem:

keyand valuehave to be allocated static or dynamic, the rest can be simplified and written without fscanf (your input is obviously line-oriented), which might get you into trouble at some point:

  ...
  FILE* fh = fopen("file", "r");
  char buffer[1024]; /* line buffer for reading file if file is line-oriented */

  while( fgets(buffer, sizeof(buffer), fh) ) {
     char key[256], val[256];
     sscanf(buffer, "%[^=]=%[^\n]", key, val);
     printf("key:%s val:%s\n", key, val);
  } 
  fclose(fh);
  ...

Edit the length of the scan buffers (key[256], val[256]) depending on your input.

Community
  • 1
  • 1
rubber boots
  • 14,924
  • 5
  • 33
  • 44
  • 1
    For the sake of security do: `sscanf(buffer, "%255[^'=']=%255[^'\n']", key, val);` with `255` being one less then the buffers' sizes. – alk Oct 16 '14 at 10:20
  • @alk Thanks for the hint! This way, you could in a simple way avoid buffer overrun on unknown input. – rubber boots Oct 16 '14 at 10:27
0
// sample working code
#include<stdio.h>
#include<stdlib.h>

int main(void) {

    FILE* file = fopen("./file", "r");

    if(NULL == file) {
        printf("Failed to open file\n");
        return EXIT_FAILURE;
    }

    do {
        char key[256];
        char value[256];
        fscanf(file, "%[^'=']=%[^'\n']\n", key, value);
        printf("key:%s value:%s\n", key, value);
    }while(!feof(file));

    fclose(file);

    return EXIT_SUCCESS;
} // End of main()

Sample Output:

key:A value:1
key:B value:2
key:C value:3