strok&strok_r 实例

不会先问男人,男人告诉我们:

  1. 函数原型
    #include <string.h>
    char *strtok(char *str, const char *delim);
    char *strtok_r(char *str, const char *delim, char **saveptr);

  2. 功能
    函数按照delim中的标记将目标字符串str拆分成0个或者多个标记,由返回值指向拆分得到的目的字符。
    函数都会破坏str字符串的结构,使用之前切记保护源数据。
    第一次调用str必须指向有效负载,往后循环调回置为NULL即可。

  3. 区别
    strtok 将第一次拆分后的数据存放在一个静态变量区域,不可重入。
    strtok 将剩余数据由saveptr明确指向,可重入

根据两个函数书写一个实际例程,拆分一条消息流。

  1. strtok版本
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_BIZ_LEN 16
#define MAX_CMD_DATA_LEN 128
#define MAX_RES_INFO_DATA 128
#define MAX_tmp_buf_LEN 1024
#define MAX_COLUMN_NUM 12
#define MAX_CATALOG_LEN 64
#define MAX_COLUMN_LEN 256

#define DELIM_SPACE " "
#define DELIM_COLON ":"
#define DELIM_LINE "-"

#define MIN(a,b) (((a)<(b))?(a):(b))

typedef struct _Save_data_struct {
	int column_count;
	int event_type;
	int event_sub_type;
	int opt_catalog_len;
	int opt_cmd_len;
	int res_info_len;
	unsigned int host_ip;
	unsigned int login_ip;

	char date[3][6];
	char time[3][6];
	char bizaccount[MAX_BIZ_LEN];
	char opt_catalog[MAX_CATALOG_LEN];
	char opt_cmd_data[MAX_CMD_DATA_LEN];
	char res_info_data[MAX_RES_INFO_DATA];
}Save_data_struct;

int split_str(char *src, int src_len, Save_data_struct *handle)
{
	char buffer[MAX_tmp_buf_LEN];
	char tmp_buf[MAX_COLUMN_NUM][MAX_COLUMN_LEN];
	unsigned int addr = 0;
	int i = 0;
	int j = 0;
	int data_len = 0;
	char *ptr = NULL;
	
	if (NULL == src || NULL == handle)
		return;
	
	memset(buffer, 0, sizeof(buffer));
	memset(tmp_buf, 0, sizeof(tmp_buf));
	memset(handle, 0,sizeof(Save_data_struct));
	
	strncpy(buffer, src, MIN(MAX_tmp_buf_LEN,src_len));
	
	/*因strtok存放数据于静态区域不可重入,一旦对strtok第一个参数
	*重新赋值便不可找回先前的序列,为对字符串进行二次拆分,
	*需要第一次拆分后缓存供二次使用*/
	ptr = strtok(buffer, DELIM_SPACE);
	
	/*对最后一个参数不做拆分,在for循环中利用反向遍历率先处理最后一个参数
	*可解决最后一个参数因空格隔开多个字符*/
	while (ptr && j < MAX_COLUMN_NUM) {
		strncpy(tmp_buf[j],ptr, MIN(MAX_tmp_buf_LEN,strlen(ptr)));
		ptr = strtok(NULL, DELIM_SPACE);
		j++;
	}
	
	for (i = j; i >= 0; --i){
		switch (i)
		{
		case 0:
			handle->event_type = atoi(tmp_buf[i]);
			break;
		case 1:
			handle->event_sub_type = atoi(tmp_buf[i]);
			break;
		case 2:
			ptr = strtok(tmp_buf[i], DELIM_LINE);
			j  = 0;
			while (ptr && j < 3)
			{
				strncpy(handle->date[j], ptr, MIN(sizeof(handle->date[j]), strlen(ptr)));
				ptr = strtok(NULL, DELIM_LINE);
				j++;
			}
			break;
		case 3:
			ptr = strtok(tmp_buf[i], DELIM_COLON);
			j  = 0;
			while (ptr && j < 3)
			{
				strncpy(handle->time[j], ptr, MIN(sizeof(handle->time[j]), strlen(ptr)));
				ptr = strtok(NULL, DELIM_COLON);
				j++;
			}
			break;
		case 4:
			if (inet_aton(tmp_buf[i], (struct in_addr*)&addr))
				handle->host_ip = ntohl(addr);
			break;
		case 5:
			if (inet_aton(tmp_buf[i], (struct in_addr*)&addr))
				handle->login_ip = ntohl(addr);
			break;
		case 6:
			strncpy(handle->bizaccount, tmp_buf[i], strlen(tmp_buf[i]));
			break;
		case 7:
			handle->opt_catalog_len = atoi(tmp_buf[i]);
			break;
		case 8:
			strncpy(handle->opt_catalog, tmp_buf[i], strlen(tmp_buf[i]));
			break;
		case 9:
			handle->opt_cmd_len = atoi(tmp_buf[i]);
			break;
		case 10:
			strncpy(handle->opt_cmd_data, tmp_buf[i], strlen(tmp_buf[i]));
			break;
		case 11:
			handle->res_info_len = atoi(tmp_buf[i]);
			break;
		case 12:
			while (NULL != ptr) {
				data_len = MIN((MAX_RES_INFO_DATA - strlen(handle->res_info_data)), strlen(ptr));
				sprintf(handle->res_info_data + strlen(handle->res_info_data),"%.*s ",data_len,ptr);
				ptr = strtok(NULL, DELIM_SPACE);
			}
			break;
		default:
			break;
		}
		
	}

	return 0;
}
void show_sysinfo(Save_data_struct *handle)
{
	if (NULL == handle)
		return;
	printf("syslog_info:\n");
	printf("result:%d\n",handle->event_type);
	printf("result:%d\n",handle->event_sub_type);
	printf("result:%s:%s:%s\n",handle->date[0],handle->date[1],handle->date[2]);
	printf("result:%s:%s:%s\n",handle->time[0],handle->time[1],handle->time[2]); 
	printf("result:%u\n",handle->host_ip);
	printf("result:%u\n",handle->login_ip);
	printf("result:%s\n",handle->bizaccount);
	printf("result:%d\n",handle->opt_catalog_len);
	printf("result:%s\n",handle->opt_catalog);
	printf("result:%d\n",handle->opt_cmd_len);
	printf("result:%s\n",handle->opt_cmd_data);
	printf("result:%d\n",handle->res_info_len);
	printf("result:%s\n",handle->res_info_data);

	return;
}
int main()
{
	Save_data_struct syslog_info;
	char str[]  = "1 1 2016-12-34 12:34:56 192.168.0.112 192.168.0.113 admin";
	char str1[] = "1 1 2016-12-34 12:34:56 192.168.0.112 192.168.0.113 admin 5 /home 2 ls";
	char str2[] = "1 1 2016-12-34 12:34:56 192.168.0.112 192.168.0.113 admin 5 /home 2 ls 5 a.txt a.out split_strtok.c";
	split_str(str, strlen(str),&syslog_info);
	show_sysinfo(&syslog_info);
	split_str(str1, strlen(str1),&syslog_info);
	show_sysinfo(&syslog_info);
	split_str(str2, strlen(str2),&syslog_info);
	show_sysinfo(&syslog_info);
	return 0;
}

strtok_r 版本

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

#define MAX_BIZ_LEN 16
#define MAX_CMD_DATA_LEN 128
#define MAX_RES_INFO_DATA 128
#define MAX_TMP_BUF_LEN 1024
#define MAX_COLUMN_NUM 13
#define MAX_CATALOG_LEN 64

#define DELIM_SPACE " "
#define DELIM_COLON ":"
#define DELIM_LINE "-"

#define MIN(a,b) (((a)<(b))?(a):(b))
typedef struct _Save_data_struct {
	int event_type;
	int event_sub_type;
	int opt_catalog_len;
	int opt_cmd_len;
	int res_info_len;
	unsigned int host_ip;
	unsigned int login_ip;

	char date[3][6];
	char time[3][6];
	char bizaccount[MAX_BIZ_LEN];
	char opt_catalog[MAX_CATALOG_LEN];
	char opt_cmd_data[MAX_CMD_DATA_LEN];
	char res_info_data[MAX_RES_INFO_DATA];
}Save_data_struct;

int split_str(char *src, int src_len, Save_data_struct *handle)
{
	char buffer[MAX_TMP_BUF_LEN];
	unsigned int addr = 0;
	int i = 0;
	int j = 0;
	int data_len = 0;
	char *ptr = NULL;
	char *p = NULL;
	char *p_tmp = NULL;
	
	if (NULL == src || NULL == handle)
		return -1;
	
	memset(buffer, 0, sizeof(buffer));
	memset(handle, 0,sizeof(Save_data_struct));
	
	strncpy(buffer, src, MIN(MAX_TMP_BUF_LEN,src_len));
	
	ptr = strtok_r(buffer, DELIM_SPACE, &p);
	handle->event_type = atoi(ptr);
	
	for (i = 1; i < MAX_COLUMN_NUM; ++i){
		if (NULL == ( ptr = strtok_r(NULL, DELIM_SPACE, &p))) 
			continue;
		
		switch (i)
		{
		case 1:
			handle->event_sub_type = atoi(ptr);
			break;
		case 2:
			ptr = strtok_r(ptr, DELIM_LINE,&p_tmp);
			j  = 0;
			while (ptr && j < 3)
			{
				strncpy(handle->date[j], ptr, MIN(sizeof(handle->date[j]), strlen(ptr)));
				ptr = strtok_r(NULL, DELIM_LINE,&p_tmp);
				j++;
			}
			break;
		case 3:
			ptr = strtok_r(ptr, DELIM_COLON,&p_tmp);
			j  = 0;
			while (ptr && j < 3)
			{
				strncpy(handle->time[j], ptr, MIN(sizeof(handle->time[j]), strlen(ptr)));
				ptr = strtok_r(NULL, DELIM_COLON,&p_tmp);
				j++;
			}
			break;
		case 4:
			if (inet_aton(ptr, (struct in_addr*)&addr))
				handle->host_ip = ntohl(addr);
			break;
		case 5:
			if (inet_aton(ptr, (struct in_addr*)&addr))
				handle->login_ip = ntohl(addr);
			break;
		case 6:
			strncpy(handle->bizaccount, ptr, strlen(ptr));
			break;
		case 7:
			handle->opt_catalog_len = atoi(ptr);
			break;
		case 8:
			strncpy(handle->opt_catalog, ptr, strlen(ptr));
			break;
		case 9:
			handle->opt_cmd_len = atoi(ptr);
			break;
		case 10:
			strncpy(handle->opt_cmd_data, ptr, strlen(ptr));
			break;
		case 11:
			handle->res_info_len = atoi(ptr);
			break;
		case 12:
			while (NULL != ptr) {
				data_len = MIN((MAX_RES_INFO_DATA - strlen(handle->res_info_data)), strlen(ptr));
				sprintf(handle->res_info_data + strlen(handle->res_info_data),"%.*s ",data_len,ptr);
				ptr = strtok_r(NULL, DELIM_SPACE, &p);
			}
			break;
		default:
			break;
		}
		
	}

	return 0;
}
void show_sysinfo(Save_data_struct *handle)
{
	if (NULL == handle)
		return;
	printf("syslog_info:\n");
	printf("result:%d\n",handle->event_type);
	printf("result:%d\n",handle->event_sub_type);
	printf("result:%s:%s:%s\n",handle->date[0],handle->date[1],handle->date[2]);
	printf("result:%s:%s:%s\n",handle->time[0],handle->time[1],handle->time[2]); 
	printf("result:%u\n",handle->host_ip);
	printf("result:%u\n",handle->login_ip);
	printf("result:%s\n",handle->bizaccount);
	printf("result:%d\n",handle->opt_catalog_len);
	printf("result:%s\n",handle->opt_catalog);
	printf("result:%d\n",handle->opt_cmd_len);
	printf("result:%s\n",handle->opt_cmd_data);
	printf("result:%d\n",handle->res_info_len);
	printf("result:%s\n",handle->res_info_data);

	return;
}
int main()
{
	Save_data_struct syslog_info;
	char str[]  = "1 1 2016-12-34 12:34:56 192.168.0.112 192.168.0.113 admin";
	char str1[] = "1 1 2016-12-34 12:34:56 192.168.0.112 192.168.0.113 admin 5 /home 2 ls";
	char str2[] = "1 1 2016-12-34 12:34:56 192.168.0.112 192.168.0.113 admin 5 /home 2 ls 5 a.txt a.out split.c";
	split_str(str, strlen(str),&syslog_info);
	show_sysinfo(&syslog_info);
	split_str(str1, strlen(str1),&syslog_info);
	show_sysinfo(&syslog_info);
	split_str(str2, strlen(str2),&syslog_info);
	show_sysinfo(&syslog_info);
	return 0;
}

总结:

  1. 尽量采用可重入函数,以便控制达到安全效果。
    linux系统 strtok_r
    windows系统 strtok_s

  2. 保护原始数据

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值