C语言字符串处理函数

1.字符串比较

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

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



  1. int my_strcmp(const char *s1, const char *s2){
  2. //important! validate arguments first!
  3. assert(NULL !=s1 && NULL != s2);
  4. while(*s1 != '\0' && *s2 != '\0' && *s1==*s2){
  5. s1++;
  6. s2++;
  7. }
  8. return *s1 - *s2;
  9. }


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个字符,或者到遇到任一字符串结尾。实现如下:



  1. int my_strncmp(const char *s1, const char *s2, size_t n){
  2. //important! validate arguments first!
  3. assert(NULL!=s1 && NULL!=s2);
  4. if(n == 0)
  5. return 0;
  6. size_t cnt = 1;
  7. while(*s1 != '\0' && *s2 != '\0' && *s1==*s2 && cnt < n){
  8. s1++;
  9. s2++;
  10. cnt++;
  11. }
  12. return *s1 - *s2;
  13. }


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’也是可以被查找的。实现如下:


  1. char *my_strchr(const char *s, int n){
  2. assert(s != NULL);
  3. char c = (char)n;
  4. do{
  5. if(*s == c)
  6. return (char *)s;
  7. }while(*s++);
  8. return NULL;
  9. }


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中出现的首字符的位置,实现如下:


  1. char *my_strstr(const char *s1, const char *s2){
  2. assert(NULL!=s1 && NULL!=s2);
  3. size_t len = strlen(s2);
  4. while(*s1){
  5. if(!strncmp(s1,s2,len))
  6. return (char *)s1;
  7. s1++;
  8. }
  9. return NULL;
  10. }


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的限定查找范围的函数,当然需要的话我们可以自己定义,如:


  1. char *strnstr(const char* s1, const char* s2, size_t n)
  2. {
  3. const char* p;
  4. size_t len = strlen(s2);
  5. if (len == 0) {
  6. return (char *)s1;
  7. }
  8. for (p = s1; *p && (p + len<= buffer + n); p++) {
  9. if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) {
  10. return (char *)p;
  11. }
  12. }
  13. return NULL;
  14. }


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))。

函数的实现如下:


  1. char *my_strcpy(char *dst, const char *src){
  2. assert(NULL!=dst && NULL!=src);
  3. char *p = dst;
  4. while((*dst++ = *src++) != '\0');
  5. return p;
  6. }


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无疑更加保险:

  1. char *my_strncpy(char *dst, const char *src, size_t n){
  2. assert(NULL!=dst && NULL!=src);
  3. char *p = dst;
  4. while(n){
  5. if((*dst++ = *src++) == '\0')
  6. break;
  7. n--;
  8. }
  9. return p;
  10. }


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; }


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



-------------------------------------


归类自己需要的资料,慢慢爬行

C语言中的字符串截取函数及应用



/*========================================================


对于一个五位数a1a2a3a4a5,可将其拆分为三个子数:

sub1=a1a2a3

sub2=a2a3a4

sub3=a3a4a5

例如,五位数20207可以拆分成

sub1=202

sub2=020(=20)

sub3=207

现在给定一个正整数K,要求你编程求出10000到30000之间所有满足下述条件的五位数,

条件是这些五位数的三个子数sub1,sub2,sub3都可被K整除。

输入

输入由键盘输入,输入仅一行,为正整数K(0<K<1000)。

输出

输出到文件,输出文件的每一行为一个满足条件的五位数,要求从小到大输出。

不得重复输出或遗漏。如果无解,则输出“No”。


样例

num.in

15

num.out

22555

25555

28555

30000


==========================================================*/


#include <stdio.h>

#include <string.h>


/*从字符串的左边截取n个字符*/

char * left(char *dst,char *src, int n)

{

    char *p = src;

    char *q = dst;

    int len = strlen(src);

    if(n>len) n = len;

    /*p += (len-n);*/   /*从右边第n个字符开始*/

    while(n--) *(q++) = *(p++);

    *(q++)='\0'; /*有必要吗?很有必要*/

    return dst;

}


/*从字符串的中间截取n个字符*/

char * mid(char *dst,char *src, int n,int m) /*n为长度,m为位置*/

{

    char *p = src;

    char *q = dst;

    int len = strlen(src);

    if(n>len) n = len-m;    /*从第m个到最后*/

    if(m<0) m=0;    /*从第一个开始*/

    if(m>len) return NULL;

    p += m;

    while(n--) *(q++) = *(p++);

    *(q++)='\0'; /*有必要吗?很有必要*/

    return dst;

}


/*从字符串的右边截取n个字符*/

char * right(char *dst,char *src, int n)

{

    char *p = src;

    char *q = dst;

    int len = strlen(src);

    if(n>len) n = len;

    p += (len-n);   /*从右边第n个字符开始*/

    while(*(q++) = *(p++));

    return dst;

}


void main()

{

    FILE * p;

    int i,k,outi,count=0;

    int sub1,sub2,sub3;

    char *strsub1,*strsub2,*strsub3,*strtempnum,*a,*b,*c;


    if((p = fopen("num.out", "ab+")) == NULL)

    {

        printf("open file fail!");

        getch();

        exit();

    }

    printf("Please input int number(0<K<1000):");

    scanf("%d",&k);


    for(outi=10000;outi<=30000;outi++)

    {

        itoa(outi,strtempnum,10);


        left(strsub1,strtempnum,3);

        mid(strsub2,strtempnum,3,1);

        right(strsub3,strtempnum,3);


        /*

        a=strsub1;

        b=strsub2;

        c=strsub3;

        printf("strsub1=%s,strsub2=%s,strsub3=%s\n",a,b,c);

        */


        sub1=atoi(strsub1);

        sub2=atoi(strsub2);

        sub3=atoi(strsub3);


        /*

        printf("sub1=%d , sub2=%d , sub3=%d \n\n",sub1,sub2,sub3);

        printf("sub1k=%d , sub2k=%d , sub3k=%d \n\n" , sub1 % k,sub2 % k,sub3 % k);

        getch();

        */

        if((sub1%k)==0 && (sub2%k)==0 && (sub3%k)==0)

        {

            fprintf(p,"%d\n",outi);

            count++;

            printf("outi=%d\n",outi);

        }

        else

        {

            fprintf(p,"%s\n","NO");

        }

    }

    printf("Count=%d    OK",count);

    fclose(p);

    getch();

}



What Doesn't Kill Me Makes Me Stronger