细节问题

 

 

  1.     今天看了下,大一时写的C程序,虽然命名真的不太规范,但整体感觉还好,程序逻辑很清
  2. 晰、也比较高效。这的确是我编程的风格,呵呵。我不太喜欢很臃肿的代码,喜欢将它们写得足够
  3. 简洁,而逻辑上也足够清晰。
  4.     举个小小的例子,一个大家熟知的 split 函数,它完成的功能就是:
  5. 给定一个字符串,然后通过指定的分隔符,将字符串分成N个子串,就这么简单。
  6.     现在给出程序1
  7. void Split( const string& s, char c, vector<string>& v )
  8. {
  9.     int i = 0;
  10.     int j = s.find(c,0);
  11.     while (j >= 0) 
  12.     {
  13.         v.push_back(s.substr(i, j-i));
  14.         i = ++j;
  15.         j = s.find(c, j);
  16.         if (j < 0)
  17.         {
  18.             v.push_back(s.substr(i, s.length( )));
  19.         }
  20.     }
  21. }
  22.     第一眼看它的时候,你或许会纳闷 为什么会有这个 if (j < 0),你试下 去掉这条语句,
  23. 就会发现一个bug,就是最后条子串不会被添加到 v 中,例如: s = "ht;t2;t3;t4", c = ';'时,
  24. 调用Split时,t4就不会加到v中。
  25. 原因很简单:在 i 指向 't'的时候,这条语句 j = s.find( c, j ); 会因为找不到 ';' 而返回 
  26. -1。
  27. 但是这个函数的写作者知道了这种情况,在后面添加了 if ( j < 0 ) ...解决了这个bug。。。
  28. 是这样的吗?可别被我诱导了,实际上真正的bug在于当字符串里面没有 ';'时,问题就来了,例如
  29. : s = "http", c = ';'int j = s.find(c,0); 执行后 j = -1; while根本不会运行,也就是说
  30. ,v里面根本就没有数据了。显然这和该函数完成的功能是不吻合的。
  31. 实际上,通过分析上面的程序,我们发现我们只是漏掉了最后一个子串的情况,因此,别的代码不
  32. 用做改变,只用在最后将 s 里的最后一个子串 插入到 v 中就OK了。
  33. 我们可以先去掉这个 while 里边的 if 。 然后在while()外面,将最后的那个子串插入到 v 中,
  34. 这显然可行。而且,比上面的效率要高。修改之后的程序2为:
  35. 程序2:
  36. void Split( const string& s, char c, vector<string>& v )
  37. {
  38.     int i = 0;
  39.     int j = s.find(c,0);
  40.     while (j >= 0) 
  41.     {
  42.         v.push_back(s.substr(i, j-i));
  43.         i = ++j;
  44.         j = s.find(c, j);
  45.     }
  46. v.push_back( s.substr(i, -1) );
  47. }
  48. 最后一句代表把 s.substr(i,-1)表示从下标i 开始到 s结尾处 的一个子串。显然在字符串分隔符
  49. 很多的情况下,它比程序一节省了将近一半的时间。
  50. 在这里,你可能会说我太拘泥于细节了。的确,有时候,编程的确需要有很好的细节把握能力,但
  51. 这并不是过分的表现。可以这么说,不会把握细节的程序员,不是一个好的程序员。
  52. 回到正题,我甚至觉得上面那段还是不大好看,能不能再简洁些呢。我们仔细分析下,可发现,只
  53. 要 s 不为空的情况下,
  54. v里面的子串就至少有一个,也就是说,循环至少应该被执行一次。那个循环与此相同,对!用 do 
  55. .. while循环。我将修改后的代码直接给出:
  56. 程序3:
  57. void Split( const string& s, char c, vector<string>& v )
  58. {
  59.     if ( s.empty() )
  60.     return;
  61.     int i;
  62.     int j = -1;
  63.     do
  64.     {
  65.         i = ++j;    
  66.         j = s.find( c, j );
  67.         v.push_back( s.substr(i, j-i) );
  68.     } while ( j > 0 );
  69. }
  70. 你可能会担心在 j < 0(也就是j==-1) 之后,v.push_back(s.substr(i, j-i)); 是否正确。
  71. 是的,当 j = -1 时,j - i 显然是一个负数,在这样的情况下,s.substr将包含从下标从 i 到 s
  72. 结尾处 的 子串
  73. 这样做,感觉上就比较清晰了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值