c语言分片函数strtok和strtok_r
strtok
是不可重入函数,strtok_r
是可重入函数,r
指reentrant
,意指可重入的意思。
可重入指能递归,即在函数内部再次调用函数。看例题:
定义一个字符串:
char s[]="hello world;I'm pele";
我想要的输出:
part:hello world
word:hello word:world
part:I'm pele
word:I'm word:pele
先用;号分隔2部分,在用空格分隔每一小部分。想法是好的,要是用strtok
去做,就会变成这样:
part:hello world
word:hello word:world
为什么少一部分?因为strtok内部维护一个静态字符串变量,2次调用导致该变量被共享了,当内部的word退出时,导致外部也对退出了。
错误代码:
#include <cstdio>
#include <cstring>
using namespace std;
int main(){
char s[]="hello world;I'm pele";
char *p=NULL,*w=NULL;
char *ss1,*ss2;
p=strtok(s,";");
while(p!=NULL){
printf("part:%s\n",p);
w=strtok(p," ");
while(w!=NULL){ //当这里变成NULL时,strtok内部的静态指针也变为NULL,导致外面循环也结束了
printf("word:%s ",w);
w=strtok(NULL," ");
}
printf("\n");
p=strtok(NULL,";");
}
return 0;
}
这里就需要可重入版本strtok_r
,该版把静态变量改为一个参数传入,这样就可以分别为2个切片函数各自一个不同的指针变量了。
#include <cstdio>
#include <cstring>
using namespace std;
int main(){
char s[]="hello world;I'm pele";
char *p=NULL,*w=NULL;
char *ss1,*ss2;
p=strtok_r(s,";",&ss1);//这里调用的是指针ss1的地址,这样才可以反复使用,功能相当于一个静态指针了。
while(p!=NULL){
printf("part:%s\n",p);
w=strtok_r(p," ",&ss2);
while(w!=NULL){
printf("word:%s ",w);
w=strtok_r(NULL," ",&ss2);//同上
}
printf("\n");
p=strtok_r(NULL,";",&ss1);
}
return 0;
}
c风格的字符串替换函数
解说:orig是原始字符串,用with串替换rep串。因为出现len_with-len_rep
所以要用表指针距离的ptrdiff_t
类型,该类型原型是long signed
类型。
还有就是各种判断不能少,否则会出各种错误,无限循环等等错误。const char *
来定义rep,with
是因为它们无需改动且需要接受字符串字面量的赋值,所以需要常量指针,因为c++规定字符串字面量只能由常量指针接受。
tmp=strncpy(tmp,orig,len_front)+len_front;
tmp=strcpy(tmp,with)+len_with;
上面这种写法,可以避免重复查找合适的复制起点位置,直接计算出正确的起点。
#include <cstdio>
#include <cstring>
using namespace std;
// You must free the result if result is non-NULL.
// useage:
// char *done = replace("abcdefghijkl", "bc", "yz");
// if(done){
// do_stuff();
// delete[] done;
// }
char *str_replace(char *orig, const char *rep, const char *with) {
char *result; // the return string
char *ins; // the next insert point
char *tmp; // varies
ptrdiff_t len_rep; // length of rep (the string to remove)
ptrdiff_t len_with; // length of with (the string to replace rep with)
ptrdiff_t len_front; // distance between rep and end of last rep
size_t count; // number of replacements
// sanity checks and initialization
if (!orig || !rep)
return NULL;
len_rep = strlen(rep);
if (len_rep == 0)
return NULL; // empty rep causes infinite loop during count(32 line for)
if (!with)
with = "";
len_with = strlen(with);
// count the number of replacements needed
ins = orig;
for (count = 0; (tmp = strstr(ins, rep))!=NULL; ++count) {
ins = tmp + len_rep;
}
// tmp = result = (char *)malloc(strlen(orig) + (len_with - len_rep) * count + 1);
tmp = result = new char [strlen(orig)+(len_with - len_rep)*count +1];
if (!result)
return NULL;
// first time through the loop, all the variable are set correctly
// from here on,
// tmp points to the end of the result string
// ins points to the next occurrence of rep in orig
// orig points to the remainder of orig after "end of rep"
while (count--) {
ins = strstr(orig, rep);
len_front = ins - orig;
tmp = strncpy(tmp, orig, len_front) + len_front;
tmp = strcpy(tmp, with) + len_with;
orig += len_front + len_rep; // move to next "end of rep"
}
strcpy(tmp, orig);
return result;
}
int main(){
char a[]="helll,wahelll,wallll";
char *ans=str_replace(a,"ll","x");
if(ans){
puts(a);
puts(ans);
delete[] ans;
}
return 0;
}
字符串插入函数
#include <cstdio>
#include <cstring>
using namespace std;
char * str_insert(char *s,char *pos,const char *ins){
size_t len_s=strlen(s);
size_t len_ins=strlen(ins);
ptrdiff_t len_front=pos-s;
char *tmp,*result;
tmp=result=new char[len_s+len_ins+1];
tmp=strcpy(tmp,s)+len_front;
tmp=strcpy(tmp,ins)+len_ins;
tmp=strcpy(tmp,pos);
return result;
}
int main(){
char a[]="hello,worldllo";
char *ans=str_insert(a,a+4,"123");
puts(ans);
delete[] ans;
return 0;
}