简体   繁体   English

C-使用strtok()的分段错误

[英]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. 当我尝试一次获取2个日期时出现细分错误错误。

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

and the line that gives me the error is d->day = atoi(strtok(NULL, "/")); 而给我错误的那一行是d->day = atoi(strtok(NULL, "/")); during the second execution. 在第二次执行期间。

The problem is your use of fgets() . 问题是您对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. 第一次, fgets()"10/23/2014\\0"填充line[] ,一切都很好。

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. 然而,在第二时间通过,ENTER键仍处于stdin的输入缓冲器,因为第一fgets()没有在任何房间line[]读它,因此第二个fgets()填充line[]"\\n\\0"而无需等待新的用户输入。 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. 因此,对strtok(line, "/")的第一次调用返回"\\n"atoi()转换为0),然后对strtok(NULL, "/")的下一次调用失败并返回NULL,这导致atoi()

Increase the size of your array so ENTER will be read by each call to fgets() . 增加数组的大小,以便每次调用fgets()都会读取ENTER I also suggest you use sscanf() instead of atoi(strtok()) : 我还建议您使用sscanf()代替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. 发生这种情况是因为您的数组仅接受max字符,并将换行符留在缓冲区中。

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. 您还应该检查每个strtok()调用的返回值,以检测调用是否成功。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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