简体   繁体   中英

C - Segmentation fault with strtok()

I am trying to get a date from console and then getting the month, day and year to work with them separately.

const size_t max = 11;

void getDate(Date * d){
    char line[max];
    printf("\t Insert the date in the american format (mm/dd/yyyy): "); 
    fgets(line, max, stdin);
    d->month = atoi(strtok(line, "/"));
    d->day = atoi(strtok(NULL, "/"));
    d->year = atoi(strtok(NULL, " "));
}

I don't get an error executing it just once. I get segmentation fault error when I try to get 2 dates at once.

Date d1, d2;
getDate(&d1);
getDate(&d2);

and the line that gives me the error is d->day = atoi(strtok(NULL, "/")); during the second execution.

The problem is your use of fgets() . It is not returning what you think it does the second time around.

The first time through, fgets() fills line[] with "10/23/2014\\0" and all is well.

However, the second time through, the ENTER key is still in stdin 's input buffer because the first fgets() did not have any room in line[] to read it, so the second fgets() fills line[] with "\\n\\0" without waiting for new user input. The first call to strtok(line, "/") thus returns "\\n" (which atoi() converts to 0), then the next call to strtok(NULL, "/") fails and returns NULL, which causes atoi() to segfault.

Increase the size of your array so ENTER will be read by each call to fgets() . I also suggest you use sscanf() instead of atoi(strtok()) :

const size_t max = 16;

void getDate(Date * d)
{
    char line[max];
    printf("\t Insert the date in the american format (mm/dd/yyyy): ");
    fgets(line, max, stdin);
    if (sscanf(line, "%d/%d/%d", &(d->month), &(d->day), &(d->year)) != 3)
        d->month = d->day = d->year = 0;
}

Alternatively, add some extra validation to make sure a date is read properly:

const size_t max = 16;

void getDate(Date * d)
{
    char line[max];
    int consumed;
    printf("\t Insert the date in the american format (mm/dd/yyyy): ");
    fgets(line, max, stdin);
    while (1)
    {
        if (sscanf(line, "%d/%d/%d%n", &(d->month), &(d->day), &(d->year), &consumed) == 3)
        {
            if (consumed == strlen(line))
                break;
        }

        printf("\t Invalid input. Insert the date in the american format (mm/dd/yyyy): ");
        fgets(line, max, stdin);
    }
}

You are leaving a new line in the input buffer. That happens because your array only takes max characters and leaves the newline character in the buffer.

You can increase the size of the array or clear the buffer after you read from it.

You should also check the return value from every strtok() call, to detect if the call was successful.

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