c语言strtok函数完美实现

看到网上好多错误的strtok实现,也不能说错,准确的说是没有完全的实现strtok,现自己写了下,目前还没有找到bug,如果有不对的欢迎指出。

大多数网上的strtok实现的代码跑不过a[]={“abc....123,,,,”},c[]={“.,”},就算跑过了,都是将a[]里的“.,”全部给置‘’了,更支持不了此等循环的调用例如:

char *ret = mystrtok(a, c);

    printf("%s %s ", a, ret);

    printf("%p %p ", a, ret);

    while(ret != NULL)

    {

        ret = mystrtok(NULL, c);

        printf("%s %s ", a, ret);

        printf("%p %p ", a, ret);

    }

 

 

 

以下是代码实现

#include <stdio.h>

#include <string.h>

#include <assert.h>

char *mystrtok(char *str, const char *delim)

{

 assert(delim != NULL);

 static char *str_next = NULL;

//用于记录置“”的后一个地址,准确的说是后一个字节地址,也就是下个字符的地址。一定要用static以免下次调用时被释放掉

 

//此循环的作用,是将str_next记录了置'\0'后一个字符的地址,进行了移位,,,为什么要移位呢,,因为其实strtok其实只将str字符串中有delim字符串中的字符进行了一次置'\0',而不是全部置'\0',例:字符串a[]={“ha,,,,,hihi....ser”},调用三次后,其实此时字符串a应该是“ha'\0',,,,hihi'\0'...ser”的,将数组a全部打印出来a2等于空,a11也等于空,其它字符是不变的,而不是将字符串置为“ha'\0''\0''\0''\0''\0'hihi'\0''\0''\0''\0'ser”,大家可以去打印来看看,所以我们需要将指针str_next指向“下一个字符串”,,例如上面举的a[]的例子,第二次调用strtok时str_next应该指向hihi的h地址

 while(str_next != NULL && *str_next != '\0')

 { 

  int str_num = 0;

  char *delim_k = (char *)delim;

  while(*delim_k != '\0')

  {

   if(*str_next == *delim_k)

   {

    str_num = 1;

    str_next++;

   }

   delim_k++;

  }

  if(str_num == 0)

  {

   break;

  }

 }

//str和str_next是不能同时为null的,其实“str是不能为空的”,但这里是因为strtok第二次开始调用时,传的参数为null,所以说第一次时str不能为null,第二次开始就可以为null,,因为str_next是记录调用后,置'\0'的后一个字符的地址,所以从第二次开始它不可能为null,所以说str和str_next是不能同时为null的,同时为空的情况只有第一次传str的地址进来时就为null,所以要避免此情况发生,当str_next不为空null也就代表它记录了“下一个字符串”的地址将它赋给str。

 if(str == NULL)

 {

  if(str_next == NULL)

  {

   return NULL;

  }

  str = str_next;

 }

//这是大多数人写的主代码,双层循环判断判断两个字符串是否有相同的字符,有就置'\0',如果只写这个,只适合被调用一次或者说只适合隔断符只有有一个,例如str=“192.168.2.1”中间只有一个字符“.”,,但如果多给它加几个字符,大多数人写的代码也就挂了,例如str=“192....168....2....1”时。

 char *str_i = str;

 while(*str_i != '\0')

 {

  char *delim_i = (char *)delim;

  while(*delim_i != '\0')

  {

   if(*str_i == *delim_i)

   {

    *str_i = '\0';

    str_next = str_i + 1; //记录置'\0'的后一个地址,准确的说是后一个字节地址,也就是下个字符的地址。

    return str;

   }

   delim_i++;

  }

  str_i++;

 }

//第一次没有在字符串str中找到和delim字符串中相同的字符,则还返回str,例1.str=“haha”、delim=“i”   此时虽然没有找到但仍要返回str、但如果在次或多次调用则返回null,例2.str=“zhang..san”、delim=“.”   此时虽然第一次能找到“.” ,但在次调用指针就指向字符“s”了,此时就和例1一样了。用static修饰n,防止n被释放。

 static int n = 0;

 n++;

 if(n == 1)

 {

  return str;

 }

 else

 {

  return NULL;

 }

 

}

//主函数试调

int main()

{

 char a[] = "zhan1;.,.san2,..196";

 char b[] = "123,456";

 char c[] = ".,;";

 

 char *ret = strtok(a, c);

 printf("%s %s\n", a, ret);

 printf("%p %p\n", a, ret);

 printf("\n");

 while(ret != NULL)

 {

  ret = strtok(NULL, c);

  printf("%s %s\n", a, ret);

  printf("%p %p\n", a, ret);

 }

 

 for(int i = 0; i < 19; i++)

 { 

  printf("a + %d = %c\n", i, a[i]);

 }

 return 0;

}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值