使用C分隔函数strtok的两个细节

Tokenizer函数strtok是常用的函数,可以用来对某个字符串分隔成几段,若只是分隔单个串没什么问题,但不当使用会产生意料外的结果。strtok的函数实现风格很C-style,如果不了解一些细节就很难调试


一,

strtok是会修改原字符串的

考虑以下程式,不过就是把str划分两次

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {

	char	*token;

	char str[] = "This + is + a + line.";
	char sp[] = " .\n\t\r";

	token = strtok(str, "+");
	while (token) {
		printf("%s\n", token);
		token = strtok(NULL, "+");
	}

	token = strtok(str, "+");
	while (token) {
		printf("%s\n", token);
		token = strtok(NULL, "+");
	}

	return 0;
}

预测输出:

This 
 is 
 a 
 line.
This 
 is 
 a 
 line.

实际输出:

This 
 is 
 a 
 line.
This 

很明显,strtok在划分原串时,把包含在分隔集内的字符转化成了'\0'(可能是其他字符)

如果想对同一个串多次划分,请保存原串,用复制串去划分


二,

不应在分隔循环内显式或隐式调用strtok

strtok在实现时,可能用到了两个以上的静态指针。很多人在第一次看到strtok的使用例时可能会很费解,为什么开始是strtok(str, sp),而进入while循环则是strtok(NULL, sp)。因为strtok在每次分隔串时,保存上一次分隔的地址到一个静态指针

以str="This is a line"为例,如果分隔符是空格,那么第一次调用strtok(str, sp),This后面的" "被修改为"\0",原串变为"This\0is a line",更新静态指针则指向"is a line",返回旧指针"This"的头地址;

进入while循环后,调用strtok(NULL, sp),则原串变为"This\0is\0a line",更新静态指针指向"a line",返回旧的静态指针:"is"的头地址;

直到静态指针指向原串末尾,strtok(NULL, sp)只能返回NULL,循环结束


这种设计带来的一点不方便,程序在分隔串时,无法进行进一步的分隔,即无法在while循环内调用strtok,除非保存下一次分隔的头地址,在调用结束后恢复strtok的静态指针


考虑如下程序,

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int tokenizer(char *line, char *sp, char* tokens[]) {
	
	int		i;
	char	*token;

	i = 0;
	token = strtok(line, sp);
	while (token) {
		printf("%s\n", token);
		if (tokens) {
			tokens[i] = token;
		} i++;
		token = strtok(NULL, sp);
	} if (tokens) tokens[i] = NULL;

	return i;
}

int main(void) {

	char	*token;

	char str[] = "This + is + a + line.";
	char sp[] = " .\n\t\r";

	token = strtok(str, "+");
	while (token) {
		printf("%s\n", token);
		tokenizer(token, sp, NULL);
		token = strtok(NULL, "+");
	}

	return 0;
}
在分隔内又隐含调用了strtok:
token = strtok(str, "+");
	while (token) {
		printf("%s\n", token);
		tokenizer(token, sp, NULL); // call strtok
		token = strtok(NULL, "+");
	}

 期待的输出:

This
This
 is 
is
 a 
a
 line.
line

实际输出:

This
This


不愿熬夜调试程式的话就请读一下加粗字体吧!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值