您的位置:首页 > 编程语言 > C语言/C++

在C语言中分割字符串

2010-10-11 15:26 267 查看
C语言的库函数中,没有类似java中String类的split方法,可以把一个长字符串分割为字符串数组。不过,还是可以利用几个库函数,自己造出split的效果。虽然不像java那样支持分隔符为正则表达式,但一般情况下也够用了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* count the number of a character in a string
*/
int count_char(const char *str, char c) {
int count = 0;
char *p = str;
while ( *p ) {
if ( *p == c )
count++;
p++;
}
return count;
}
/*
* split a string into words, must free after use
*/
int split(char ***words, const char *line, char delim) {
int word_counter = count_char(line, delim) + 1;
*words = (char **) malloc(sizeof(char *) * word_counter);
int i = 0;
char *p = line;
while ( 1 ) {
char *s = p;
p = strchr(p, delim);
int len = ( p ) ? p - s : strlen(s);
(*words)[i] = (char *) malloc(sizeof(char) * (len + 1));
strncpy((*words)[i], s, len);
(*words)[i][len] = 0;
if ( !p ) break;
p++;
i++;
}
return word_counter;
}
/*
* unit test
*/
int main(void) {
char *line = "300;D;Event: /"460008103448843/",/"19/",/"2010/09/07-10-46-00.00/",/"/",/"/",/"/",/"0/",/"/",/"/",/"/",/"/",/"ROAMER MTC/",/"52/",/"Voice MTC/",/"460008103448843/",/"/",/"MO/",/"0011/",/"45500000103BD/",/"2010/09/07-10-46-52.00/",/"1/",/"/",/"8647145557^353070016806810/",/"11^^1^957^/",/"^^/",/"^^^/",/"45500000103BD/",/"MOSMTMSC/",/"/",/"/",/"/",/"/",/"rui_momsc1_mom1_1572_02933.dat/",/"1/",/"/"";
printf("%s/n", line);
char **words = NULL;
int n = split(&words, line, ',');
printf("split it into %d fields:/n", n);
int i;
for ( i = 0; i < n; i++) {
printf("field %d: [%s]/n", i, words[i]);
free(words[i]);
}
free(words);
return 0;
}


这个split函数原型是:int split(char ***words, const char *line, char delim);

为什么第一个参数是指向字符串数组的指针(char ***),而不是字符串数组(char **)呢?因为在C语言中,函数中的参数其实是它实际传入参数的副本。如果调用split时仅仅把字符串数组传入,在split函数中,实际上是对其副本执行malloc操作,而其正本并未有任何改变,没有分配到新的内存,导致程序执行时崩溃。

而使用指向字符串数组的指针就不一样了。split函数会在其副本所指向的内存上进行malloc操作,也就是在其正本所指向的内存上进行malloc操作,子函数中所作的改变在调用它的函数中得以体现。

林锐的《高质量C++/C编程指南》一书中,7.4节,《指针参数是如何传递内存的?》,对此问题有详细的解释:编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是_p,编译器使_p = p。如果函数体内的程序修改了_p的内容,就导致参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。……,(但如果)_p申请了新的内存,只是把_p所指的内存地址改变了,但是p丝毫未变。

此外,本案例的另一个值得注意的地方,是执行strncpy()之后,应当及时在新的字符串的末尾置结束符,否则会出现奇怪的字符串溢出错误,不要以为strncpy()之前的memset()能够解决这一问题。

本案例的测试结果如下图:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: