现在的位置: 首页 > 综合 > 正文

C语言字符串处理函数

2013年06月21日 ⁄ 综合 ⁄ 共 2721字 ⁄ 字号 评论关闭

 这边文章对c语言的字符串处理的常用库函数总结一下,并进行实现。

1.字符串比较

int strcmp(const char *s1, const char *s2);

比较两个字符串的大小(不忽略大小写),返回值很有学问:如果s1小于s2返回一个小于0的数,如果s1大于s2返回一个大于0的数,如果相等则返回0。返回值是两个字符串中第一个不相等的字符ascii码的差值。实现如下:

int my_strcmp(const char *s1, const char *s2){
	//important! validate arguments first!
	assert(NULL !=s1 && NULL != s2);
	while(*s1 != '\0' && *s2 != '\0' && *s1==*s2){
		s1++;
		s2++;
	}
	return *s1 - *s2;
}

注意再函数开始进行参数检查,防止输入参数有NULL时发生运行时错误。

strcmp是最常用的字符串比较函数,一般用法是if(!strcmp(s1, s2)){ ...}。如果不是对整个字符串进行比较而只是比较指定数目的字符串,可以使用函数:

int strncmp(const char *s1, const char *s2, size_t n);

用法和返回值都和strcmp类似,之比较给定字符串的前n个字符,或者到遇到任一字符串结尾。实现如下:

int my_strncmp(const char *s1, const char *s2, size_t n){
	//important! validate arguments first!
	assert(NULL!=s1 && NULL!=s2);
	if(n == 0)
		return 0;
	size_t cnt = 1;
	while(*s1 != '\0' && *s2 != '\0' && *s1==*s2 && cnt < n){
		s1++;
		s2++;
		cnt++;
	}
	return *s1 - *s2;
}

需要注意的除了参数检查外,还要注意n=0的特殊情况,这里我们n=0永远返回0。

还有其他一些带特殊要求字符串比较函数,如:

stricmp,memcmp,memicmp等等,加i表示比较时忽视大小写,带mem的是比较一块内存区间。

2.字符串查找

最简单的是查找字符串查找字符:

char *strchr(const char *s, int c);

至于参数为什么是int,历史遗留问题,这里不多讨论。函数返回在s中找到的第一个c的位置的指针,注意的是,字符串末尾的‘\0’也是可以被查找的。实现如下:

char *my_strchr(const char *s, int n){
	assert(s != NULL);
	char c = (char)n;
	do{
		if(*s == c)
			return (char *)s;
	}while(*s++);
	return NULL;
}

还有查找字符串的函数strstr:

char *strstr(const char *s1, const char *s2);

函数返回s2在s1中出现的首字符的位置,实现如下:

char *my_strstr(const char *s1, const char *s2){
	assert(NULL!=s1 && NULL!=s2);
	size_t len = strlen(s2);
	while(*s1){
		if(!strncmp(s1,s2,len))
			return (char *)s1;
		s1++;
	}
	return NULL;
}

c标准库中并没有定义类似strnchr和strnstr的限定查找范围的函数,当然需要的话我们可以自己定义,如:

char *strnstr(const char* s1, const char* s2, size_t n)
{
  const char* p;
  size_t len = strlen(s2);
  if (len == 0) {
    return (char *)s1;
  }
  for (p = s1; *p && (p + len<= buffer + n); p++) {
    if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) {
      return (char *)p;
    }
  }
  return NULL;
}

3.字符串复制

最常见的字符串复制函数是strcpy:

char *strcpy(char *dst, const char *src);

把src所指的由NULL结尾的字符串复制到由dst所指的字符串中,src和dst不可以相同(可以由c99的restrict关键字声明),dst必有足够的空间存放复制的字符串。

还有一点要注意的是函数返回值,返回值是指向dst的指针,这样做的目的是方便程序中语句内联,比如strlen(strcpy(s,t))。

函数的实现如下:

char *my_strcpy(char *dst, const char *src){
	assert(NULL!=dst && NULL!=src);
	char *p = dst;
	while((*dst++ = *src++) != '\0');
	return p;
}

使用strcpy是危险的,因为函数本身是不检查dst指向的空间是否足够存储需要复制的字符串,导致的一个潜在隐患就是字符串溢出。这也是上个世纪常被黑客利用的一个经典漏洞。所以,在大多数情况下都是用strncpy无疑更加保险:

char *my_strncpy(char *dst, const char *src, size_t n){
	assert(NULL!=dst && NULL!=src);
	char *p = dst;
	while(n){
		if((*dst++ = *src++) == '\0')
			break;
		n--;
	}
	return p;
}

需要注意另外一个函数strdup:

char *strdup(const char *);

该函数和strcpy的不同是,函数会自己申请内存空间存放拷贝的字符串,然后返回指向该字符串的指针。所以在使用strdup函数时需要注意的是,在使用完复制的字符串后使用free函数释放其占用的空间。

另memcpy函数和strncpy类似,只是不会再遇到NULL时终止拷贝,该函数一定会拷贝n个字符。

4.字符串连接

字符串连接是把一个字符串的头连接到另一个字符串的结尾。

char *strcat(char *s1, const char *s2);

函数的实现如下:

char *my_strcat(char *s1, const char *s2){
	assert(NULL!=s1 && NULL!=s2);
	char *p =s1;
	while(*s1)s1++;
	strcpy(s1,s2);
	return p;
}

同样,strcat也是不安全的,因为也对缓冲区足够存放连接的字串进行了假设。所以,多数情况下我们应该使用更安全的:

char *strncat(char *s1, const char *s2, size_t n);

抱歉!评论已关闭.