我正在尝试从控制台获取日期,然后分别与月份,日期和年份一起使用。
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, "/"));
。
答案 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()调用的返回值,以检测调用是否成功。