我想从命令行读取一行CSV。用户以age, HH:MM:SS, number
。
我写了以下内容:
int age;
char timestamp[8];
int number;
scanf("%d,%8[^,],%d", &age, timestamp, &number;
printf("%d, %s, %d", age, timestamp, number);
当我输入23, abcd, 9
时,它会打印23, abcd, 9
当我输入23, abcdefghijklmno, 9
时,它会打印23, abcdefgh, 0
我该如何解决这个问题?
答案 0 :(得分:3)
scanf()
和UB
%8[^,]
(阅读不是char
的8 ','
)将" HH:MM:S"
读入太小@Weather Vane的空间。因此,如果将char
和空字符存储到timestamp[8]
中的未定义行为不会导致代码被删除,则尝试阅读第二个S
并与','
匹配将会停止扫描@Marc B。不检查返回值(一个很大的禁忌),进一步隐藏了number
未写入的事实。
char timestamp[8];
// 12345678
// age, HH:MM:SS, number
scanf("%d,%8[^,],%d", &age, timestamp, &number;`
相反
char buf[100];
fgets(buf, sizeof buf, stdin);
// 1 bigger for the null character
char timestamp[8+1];
// v-- add space check result --v
if (sscanf(buf, "%d, %8[^,],%d", &age, timestamp, &number) == 3) {
printf("%d, %s, %d", age, timestamp, number);
} else {
puts("Input data scan failed");
}
scanf()
是邪恶的。节省时间,避免头痛。使用fgets()
。
此广告由“实践安全输入”委员会提供给您。
答案 1 :(得分:1)
检查出来。
宣称小尺寸..
timestamp[8]
而是像timestamp[16]
这样的东西。在这种情况下,名称长度最多为16。
%8
最多消耗8个字符。这是另一个原因。
答案 2 :(得分:1)
如果您不确定逗号之间的字符串长度,可以扫描整数和逗号。使用%n
说明符捕获扫描的字符数。最多可扫描8个字符串。然后使用strpbrk
查找下一个逗号并扫描该逗号和最后一个整数。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *comma = NULL;
char csv1[] = "23, abcdefghijklmnop, 9";
char timestamp[9]= "";
int age = 0;
int number = 0;
int used = 0;
if ( ( sscanf ( csv1, "%d ,%n %8[^,]", &age, &used, timestamp)) == 2) {
if ( ( comma = strpbrk ( csv1 + used, ","))) {
if ( ( sscanf ( comma, ",%d", &number)) == 1) {
printf ( "%d, %s, %d\n", age, timestamp, number);
}
}
}
return 0;
}