C - strtok()的分段错误

时间:2014-10-24 01:47:23

标签: c strtok

我正在尝试从控制台获取日期,然后分别与月份,日期和年份一起使用。

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, " "));
}

我只是执行一次就不会出错。当我尝试一次获得2个日期时,我得到了分段错误错误。

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

并且在第二次执行期间给出错误的行是d->day = atoi(strtok(NULL, "/"));

2 个答案:

答案 0 :(得分:3)

问题在于您使用fgets()。它没有返回你认为它第二次做的事情。

第一次,fgets()line[]填入"10/23/2014\0",一切顺利。

然而,第二次, ENTER 键仍在stdin的输入缓冲区中,因为第一个fgets()line[]中没有任何空间{1}}要阅读它,因此第二个fgets()会将line[]填入"\n\0",而无需等待新的用户输入。因此,对strtok(line, "/")的第一次调用返回"\n"atoi()转换为0),然后对strtok(NULL, "/")的下一次调用失败并返回NULL,这会导致atoi() to segfault。

增加数组的大小,以便每次调用fgets()时都会读取 ENTER 。我还建议您使用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;
}

或者,添加一些额外的验证以确保正确读取日期:

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);
    }
}

答案 1 :(得分:1)

您在输入缓冲区中留下一个新行。发生这种情况是因为您的数组只接受max个字符并将换行符留在缓冲区中。

您可以在读取数据后增加数组的大小或清除缓冲区。

您还应该检查每个strtok()调用的返回值,以检测调用是否成功。