Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I resolve sscanf issue with email?

Tags:

c

scanf

Here's my code:

#include <stdio.h>

int main(int argc, char **argv)
{
    const char example[]="13902796D ; Josefa Moral Fidalgo ; [email protected] ; 01/03/2001 ; 0 ; 1 ;";
    char DNI[10];
    char name[100];
    char email[100];
    char date[10];
    int gender;
    int uni;

    sscanf(example, "%[^;] ; %[^;] ; %[^;] ; %[^;] ; %d ; %d ; ",
        DNI, name, email, date, &gender, &uni);

    printf("DNI: %s\n", DNI);
    printf("Name: %s\n", name);
    printf("Email: %s\n", email);
    printf("Date: %s\n", date);
    printf("Gender: %d\n", gender);
    printf("Uni: %d\n", uni);
    return 0;
}

And here's the result:

DNI: 13902796D
Name: Josefa Moral Fidalgo
Email:
Date: 01/03/2001
Gender: 0
Uni: 1

But I expect the result:

DNI: 13902796D
Name: Josefa Moral Fidalgo
Email: [email protected]
Date: 01/03/2001
Gender: 0
Uni: 1

I'm a newbie with C, but I can't find any answer on Internet, nor here on Stackoverflow, and check some books but can't find the reason why the code

 sscanf(example, "%[^;] ; %[^;] ; %[^;] ; %[^;] ; %d ; %d ; ",
            DNI, name, email, date, &gender, &uni);

doesn't work. Can anyone help me? I can't use other functions than sscanf, that's what my professor wants to use in the code.

like image 306
mindOf_L Avatar asked Nov 22 '25 09:11

mindOf_L


1 Answers

Buffer overflow.

How does code know to not overfill DNI[]? Only the address of DNI was passed to sscanf(). Since OP's code did not provide enough space for the input, DNI[] was overwritten leading to undefined behavior (UB).

sscanf(example, "%[^;] ... ", DNI, ....

Instead, pass the maximum number of characters to read, the width. A 9 will limit scan up to 9 characters. As the array is size 10, there will be enough memory for the 9 characters and the appended null character. Code also needs to make the buffers larger to accommodate user input.

char DNI[10*2];
sscanf(example, "%19[^;] ... ", DNI, ....

But was the entire scan right?
A simple method is to record the offset of the scan with " %n". If the scan reached the "%n", n will have a new value.

int n = -1;
sscanf(example, "%9[^;] ;...  %n", DNI, ..., &n);

Put this together

int main(int argc, char **argv) {
    const char example[]="13902796D ; 1 ;";
    char DNI[10*2];
    int uni;

    int n = -1;
    sscanf(example, "%19[^;] ; %d ; %n", DNI, &uni, &n);
    if (n < 0) {
      puts("Fail");
    } else {
      printf("DNI: %s\n", DNI);
      printf("Uni: %d\n", uni);
    }
    return 0;
}

Code still has issues as DNI[] is likely "13902796D " (note trailing space), but that is another issue for OP to handle.

like image 76
chux - Reinstate Monica Avatar answered Nov 23 '25 23:11

chux - Reinstate Monica