Home > Back-end >  Why does sscanf changing the value of original char array?
Why does sscanf changing the value of original char array?

Time:09-25

I'm not understand how sscanf works.

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

int main(void)
{

    char s[100] = "testtes te asdf newlinetest";

    char parm1[10];
    char parm2[4];
    char parm3[256];
    char parm4[10];

    printf("BEFORE: %s\n", s);
    sscanf(s, "%s %s %s %s", parm1, parm2, parm3, parm4);
    printf("AFTER: %s\n", s);

    return (0);
}

Output :

BEFORE: testtes te asdf newlinetest
AFTER: t

It seems like it is printing the last character, however when the size of parm1 to 90, it prints the correct output.

Output:

BEFORE: testtes te asdf newlinetest
AFTER: testtes te asdf newlinetest

CodePudding user response:

There isn't enough space in parm4 to hold "newlinetest". parm4 can hold 10 characters, but "newlinetest" is 11 characters long, plus you need an additional character for the null character, so you need 12 characters to hold it. After writing the first 10 characters to parm4, it keeps going, writing t and \0 to the memory that follows parm4, which in this case is apparently s. So s ends up holding "t".

Note that this is undefined behavior, and you can't count on it behaving this way.

CodePudding user response:

param4 is not large enough to hold the string "newlinetest". As a result, when sscanf writes to it it writes past the end of the array. This triggers undefined behavior.

In this particular case, it just so happened that s appeared immediately after param4 in memory so the first few bytes of s were overwritten. However, this is only one way the program could have behaved. It could have appeared to work properly.

By making param4 larger, you prevent writing past the end of the array.

CodePudding user response:

There is a memory overwriting because the following array is declared with only 10 characters like

char parm4[10];

and you are trying to write to it the string "newlinetest" that contains 12 characters including the terminating zero character '\0'.

Declare the array at least with 12 characters

char parm4[12];

and you will get the expected result.

CodePudding user response:

In addition to what has been said in the answers, when you use sscanf() to parse a string, better use a width modifier:

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

int main(void)
{
    char s[100] = "testtes te asdf newlinetest";

    char parm1[10];
    char parm2[4];
    char parm3[256];
    char parm4[12]; // 12 since your last word contains 11 characters ( 1 for \0)

    printf("BEFORE: %s\n", s);
    sscanf(s, "%9s %3s %5s s", parm1, parm2, parm3, parm4);
    printf("AFTER: %s\n", s);
}

Your output should look like this:

BEFORE: testtes te asdf newlinetest
AFTER: testtes te asdf newlinetest
  • Related