小技巧,大智慧:%n of sscanf

scanf 系列中有个函数 sscanf,可能有人用过,它的普通用法,我就不讲了,可以参考这里:man 3 sscanf

gnu c 实现了 C 标准的 format specify 的 %n,它的含义是返回从该次 XXscanf 调用开始到此读了多少个字节,我们可以利用这一点,来实现不需要内存分配的%s

假定我们读取一批商品记录,每条记录包含商品ID,商品名称,商品价格,各字段的类型在代码中是自包含的

size_t len1 = 0;
ssize_t len2 = 0;
char* line = NULL;
while ((len2 = getline(&line, &len1, fp) > 0) {
    int beg = -1; // name offset begin in line
    int end = -1; // name offset end   in line
    int id;
    const char* name;
    double price;
    int fields = sscanf(line, "%d %n%*s%n %lf", &id, &beg, &end, &price);
    if (2 == fields) { // 'beg' and 'end' are not counted in return value
         int slen = end - beg;
         name = line + beg;
         name[slen] = 0;
         // ....
    } else {
         fprintf(stderr, "bad record\n");
    }
}
if (NULL != line) free(line);

%*s 用来扫描但跳过(不存储)一个字符串,两个 %n,前一个得到name的起始偏移,后一个得到name的结束偏移……其它的,也就不用我多说了。

%n 应该是 C99 新加入的,不过这一点我不太确信,但 gnu 里面的确有这个实现,msvc 里面没有,其他的环境就不太清楚了。如果是写服务器应用,一般就不用担心它是否实现(95%以上的服务器都该有gnu环境吧,况且 glibc 和gcc是相对独立的)。

%n 特性真可谓小技巧,大智慧,我很长一段时间不知道这个东西,还一直为 XXprintf 系列可以得到已写出的字节数,而 XXscanf 无法得到已读取的字节数犯愁。

我觉得在新代码中应该使用该技巧取代 %s,当然,gnu 的 XXscanf 里面还有个 %as,它返回一个由系统 malloc 出来的字符串,需要用户自己调用 free 来释放它。如果是写纯 C 代码,并且字符串需要保存起来长期使用,应该使用 %as,否则应该使用我提到的这个技巧。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值