我的strcat:

  1. char *strcat(char *dest,char *src)
  2. {
  3. char * reval = dest;
  4. while(*dest)
  5. dest++;
  6. while(*src)
  7. *dest++ = *src++ ;
  8. *dest = *src;
  9. return reval;
  10. }

MSVC:

  1. char * __cdecl strcat (
  2. char * dst,
  3. const char * src
  4. )
  5. {
  6. char * cp = dst;
  7.  
  8. while( *cp )
  9. cp++; /* find end of dst */
  10.  
  11. while( *cp++ = *src++ ) ; /* Copy src to end of dst */
  12.  
  13. return( dst ); /* return dst */
  14.  
  15. }

在while( *cp++ = *src++ )中,条件的值为赋值语句的返回值即*cp被赋的值,也就是此时*src的值。则,当*src为0时,将其赋给*cp后完成赋值。非常简洁。

该函数的前提条件:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。

我的strncat:

  1. char *strncat(char *dest,char *src,int n)
  2. {
  3. char * reval = dest;
  4. while(*dest)
  5. dest++;
  6. while(n-- && (*dest++ = *src++));
  7. if(n < )
  8. *dest = ;
  9. return reval;
  10. }

MSVC:

  1. char * __cdecl strncat (
  2. char * front,
  3. const char * back,
  4. size_t count
  5. )
  6. {
  7. char *start = front;
  8.  
  9. while (*front++)
  10. ;
  11. front--;
  12.  
  13. while (count--)
  14. if (!(*front++ = *back++))
  15. return(start);
  16.  
  17. *front = '\0';
  18. return(start);
  19. }

我的strchr:

  1. char *strchr(const char *s,char c){
  2. while(*s)
  3. {
  4. if(*s == c)
  5. return s;
  6. s++;
  7. }
  8. return NULL;
  9. }

MSVC:

  1. char * __cdecl strchr (
  2. const char * string,
  3. int ch
  4. )
  5. {
  6. while (*string && *string != (char)ch)
  7. string++;
  8.  
  9. if (*string == (char)ch)
  10. return((char *)string);
  11. return(NULL);
  12. }

我的strcmp:

  1. int strcmp(const char *s1,const char * s2){
  2. while(*s1 == *s2 && *s1)
  3. {
  4. ++s1;
  5. ++s2;
  6. }
  7. return *(unsigned char *)s1 - *(unsigned char *)s2;
  8. }

MSVC:

  1. int __cdecl strcmp (
  2. const char * src,
  3. const char * dst
  4. )
  5. {
  6. int ret = ;
  7.  
  8. while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
  9. ++src, ++dst;
  10.  
  11. if ( ret < )
  12. ret = - ;
  13. else if ( ret > )
  14. ret = ;
  15.  
  16. return( ret );
  17. }

strcmp返回值不必为1和-1的。使用unsigned char 因为有符号数可能会导致比较大小错误。

我的strcpy:

  1. char *strcpy(char *dest,const char *src){
  2. char * reval = dest;
  3. while(*dest++ = *src++);
  4. return reval;
  5. }

MSVC:

  1. char * __cdecl strcpy(char * dst, const char * src)
  2. {
  3. char * cp = dst;
  4.  
  5. while( *cp++ = *src++ )
  6. ; /* Copy src over dst */
  7.  
  8. return( dst );
  9. }

我的strncpy:

  1. char *strncpy(char *dest, const char *src, int n){
  2. char * reval = dest;
  3. while(n--){
  4. if(*src)
  5. *dest++ = *src++;
  6. else
  7. *dest++ = ;
  8. }
  9. return reval;
  10. }

MSVC:

  1. char * __cdecl strncpy (
  2. char * dest,
  3. const char * source,
  4. size_t count
  5. )
  6. {
  7. char *start = dest;
  8.  
  9. while (count && (*dest++ = *source++)) /* copy string */
  10. count--;
  11.  
  12. if (count) /* pad out with zeroes */
  13. while (--count)
  14. *dest++ = '\0';
  15.  
  16. return(start);
  17. }

我的strcspn:

  1. int strcspn(const char *s1,const char *s2){
  2. const char *cp;
  3. int reval = ;
  4. for(; *s1; s1++){
  5. for(cp = s2; *cp; cp++){
  6. if(*s1 == *cp)
  7. return reval;
  8. }
  9. ++reval;
  10. }
  11. return reval;
  12. }

MSVC:

  1. size_t __cdecl strcspn (
  2. const char * string,
  3. const char * control
  4. )
  5. {
  6. const unsigned char *str = string;
  7. const unsigned char *ctrl = control;
  8.  
  9. unsigned char map[];
  10. int count;
  11.  
  12. /* Clear out bit map */
  13. for (count=; count<; count++)
  14. map[count] = ;
  15.  
  16. /* Set bits in control map */
  17. while (*ctrl)
  18. {
  19. map[*ctrl >> ] |= ( << (*ctrl & ));
  20. ctrl++;
  21. }
  22.  
  23. /* 1st char in control map stops search */
  24. count=;
  25. map[] |= ; /* null chars not considered */
  26. while (!(map[*str >> ] & ( << (*str & ))))
  27. {
  28. count++;
  29. str++;
  30. }
  31. return(count);
  32. }

函数说明:strcspn()从参数s 字符串的开头计算连续的字符, 而这些字符都完全不在参数reject 所指的字符串中. 简单地说, 若strcspn()返回的数值为n, 则代表字符串s 开头连续有n 个字符都不含字符串reject 内的字符。

返回值:返回字符串s 开头连续不含字符串reject 内的字符数目。

我的实现和《C标准库》书中基本相同,不需要任何的额外存储空间,但是使用两层的循环,花费较多的时间。

该函数的实质其实是判断s1中的每一个字符,是否在s2字符串中,对于这种判断是否在其中的问题,经常会采用映射表的方式来缩减查找时间,典型实现就是布隆过滤器。

此处,MSVC的实现就是采用了映射表的方式。

因为ASCII码有256个,所以需要256bit来作为映射标记。一个字节是8bit,所以需要32个字节。所以在代码中有 unsigned char map[32]的定义。

那么,我们就需要将8bit,分别映射出一个map的下标和bit中的位位置。

map的下表需要使用5bit(32),而bit中的位位置使用剩余的3bit(8)来映射。

通过*ctrl >> 3取到高5位到0-31的映射,通过1 << (*ctrl & 7)取得到1字节中某一位的标记。

完成控制字符的映射表建立,就能用o(1)的时间完成某个字符的查找了。

strerror

功  能: 返回指向错误信息字符串的指针

例如:

  1. #include <stdio.h>
  2. #include <errno.h>
  3.  
  4. int main(void)
  5. {
  6. char *buffer;
  7. buffer = strerror(errno);
  8. printf("Error: %s\n", buffer);
  9. return ;
  10. }

此段代码strerror指向的内存中的字符串为No Error

我的strlen:

  1. int strlen(const char *s){
  2. const char *cp = s;
  3. while(*cp){
  4. cp++;
  5. }
  6. return (cp - s);
  7. }

MSVC:

  1. size_t __cdecl strlen (
  2. const char * str
  3. )
  4. {
  5. const char *eos = str;
  6.  
  7. while( *eos++ ) ;
  8.  
  9. return( (int)(eos - str - ) );
  10. }

返回值应该不需要强制类型转换,因为指针相减返回值是int。当然,加上显式转换则更加明确。

ptrdiff_t
This is the type returned by the subtraction operation between two pointers. This is a signed integral type, and as such can be casted to compatible fundamental data types.

strpbrk和strspn的实现和strcspn相同

我的strrchr:

  1. char *strrchr(const char *str, const char c){
  2. const char *cp = str;
  3. if(*str == )
  4. return NULL;
  5. while(*str)
  6. str++;
  7. while(*cp++){
  8. if(*--str == c)
  9. return str;
  10. }
  11. return NULL;
  12. }

MSVC:

  1. char * __cdecl strrchr (
  2. const char * string,
  3. int ch
  4. )
  5. {
  6. char *start = (char *)string;
  7.  
  8. while (*string++) /* find end of string */
  9. ;
  10. /* search towards front */
  11. while (--string != start && *string != (char)ch)
  12. ;
  13.  
  14. if (*string == (char)ch) /* char found ? */
  15. return( (char *)string );
  16.  
  17. return(NULL);
  18. }

确实只需要初始位置的拷贝,不需要用拷贝来计数。

strtok,没想好如何实现比较合适。

MSVC:

  1. char * __cdecl strtok (
  2. char * string,
  3. const char * control
  4. )
  5. {
  6. unsigned char *str;
  7. const unsigned char *ctrl = control;
  8.  
  9. unsigned char map[];
  10. int count;
  11.  
  12. static char *nextoken;
  13.  
  14. /* Clear control map */
  15. for (count = ; count < ; count++)
  16. map[count] = ;
  17.  
  18. /* Set bits in delimiter table */
  19. do {
  20. map[*ctrl >> ] |= ( << (*ctrl & ));
  21. } while (*ctrl++);
  22.  
  23. /* Initialize str. If string is NULL, set str to the saved
  24. * pointer (i.e., continue breaking tokens out of the string
  25. * from the last strtok call) */
  26. if (string)
  27. str = string;
  28. else
  29. str = nextoken;
  30.  
  31. /* Find beginning of token (skip over leading delimiters). Note that
  32. * there is no token iff this loop sets str to point to the terminal
  33. * null (*str == '\0') */
  34. while ( (map[*str >> ] & ( << (*str & ))) && *str )
  35. str++;
  36.  
  37. string = str;
  38.  
  39. /* Find the end of the token. If it is not the end of the string,
  40. * put a null there. */
  41. for ( ; *str ; str++ )
  42. if ( map[*str >> ] & ( << (*str & )) ) {
  43. *str++ = '\0';
  44. break;
  45. }
  46.  
  47. /* Update nextoken (or the corresponding field in the per-thread data
  48. * structure */
  49. nextoken = str;
  50.  
  51. /* Determine if a token has been found. */
  52. if ( string == str )
  53. return NULL;
  54. else
  55. return string;
  56. }

用一个static变量来记录当前分割到的位置,它是线程不安全的,多次调用也会使它失效。

strcoll使用当前的区域设置来比较字符串,strxfrm使用当前的区域设置来转换字符串。当前区域设置由LL_COLLATE宏指定。它们均调用带有区域设置参数的内部版本strcoll_l和strxfrm_l来完成实际的工作。

走进C标准库(8)——"string.h"中函数的实现相关字符串操作函数的更多相关文章

  1. 走进C标准库(6)——"string.h"中函数的实现memchr

    我写的memchr: void *memchr(const void *buf, char ch, unsigned count){ unsigned ; while(*(buf++) != ch & ...

  2. 走进C标准库(7)——"string.h"中函数的实现memcmp,memcpy,memmove,memset

    我的memcmp: int memcmp(void *buf1, void *buf2, unsigned int count){ int reval; while(count && ...

  3. 走进C标准库(3)——"stdio.h"中的getc和ungetc

    接前文. 再来看看getc和ungetc的实现.在看这两个函数的实现之前,我们先来想一想这两个函数分别需要做的工作. int getc(FILE *stream) 说明:函数getc从stream指向 ...

  4. 走进C标准库(2)——"stdio.h"中的fopen函数

    其他的库文件看起来没有什么实现层面的知识可以探究的,所以,直接来看stdio.h. 1.茶余饭后的杂谈,有趣的历史 在过去的几十年中,独立于设备的输入输出模型得到了飞速的发展,标准C从这个改善的模型中 ...

  5. 走进C标准库(5)——"stdio.h"中的其他部分函数

    函数介绍来自:http://ganquan.info/standard-c/ 函数名: freopen 功  能: 替换一个流 用  法: FILE *freopen(char *filename, ...

  6. 走进C标准库(4)——"stdio.h"中的putc

    花了点时间把园子弄得好看了点,现在继续. 函数名: putc 功  能: 输出一字符到指定流中 用  法: int putc(int ch, FILE *stream); #define _putc_ ...

  7. 走进C标准库(1)——assert.h,ctype.h

    默默觉得原来的阅读笔记的名字太土了,改了个名字,叫做走进C标准库. 自己就是菜鸟一只,第一次具体看C标准库,文章参杂了对<the standard C library>的阅读和对源码的一些 ...

  8. C++ 标准库类型-String,Vector and Bitset

    <C++ Primer 4th>读书摘要 最重要的标准库类型是 string 和 vector,它们分别定义了大小可变的字符串和集合.这些标准库类型是语言组成部分中更基本的那些数据类型(如 ...

  9. 谈谈两种标准库类型---string和vector

    两种最重要的标准库---string和vector string和vector是两种最重要的标准库类型,string表示可变长的字符序列,vector存放的是某种给定类型对象的可变长序列. 一.标准库 ...

随机推荐

  1. 关于ECharts Java类库的一个jquery插件

    在项目中开发图表功能时用到了Echars和一个关于Echars的java类库(http://git.oschina.net/free/ECharts).这个类库主要目的是方便在Java中构造EChar ...

  2. css样式规则的简要总结

    css与文档关联起来发挥作用. css文件中是各种样式规则,由选择器和声名块构成.声明块由多条声明组成.选择器是声明要作用的对象,声明是对具体规则的描述. 声明由属性和值组成,值或是属性的错误都会使该 ...

  3. Java环境配置原理

    Java环境配置原理详解 1.Jdk安装目录文件说明: 一般jdk安装目录及路径 \Java\jdk1.7.0_79\lib,里面主要包含以下文件夹. bin:主要存放的是java工具中常用命令如:j ...

  4. pythonj基础之 多线程

    多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序中的任务放到后台去处理. 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进 ...

  5. Android 开源控件系列_1

    第一部分 个性化控件(View) 主要介绍那些不错个性化的View,包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.Pro ...

  6. android AsyncTask 的使用(转载)

    1 ) AsyncTask实现的原理,和适用的优缺点 AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可 ...

  7. Looper、Hander、HandlerThread

    一.Message .Looper.Handler之间的关系 1.系统发送的Message消息传送给Handler,Handler将Message放入自己的looper队列的底部   然后再从Loop ...

  8. Linux06--Shell程序设计02 数据流重定向与管道

    包含3种数据流: •标准输入(stdin):代码为0,符号为<或<<; •标准输出(stdout):代码为1,符号为>或>>; •标准错误输出(stderr):代码 ...

  9. 转:JavaScript函数式编程(一)

    转:JavaScript函数式编程(一) 一.引言 说到函数式编程,大家可能第一印象都是学院派的那些晦涩难懂的代码,充满了一大堆抽象的不知所云的符号,似乎只有大学里的计算机教授才会使用这些东西.在曾经 ...

  10. GDB单步调试程序

    linux下gdb单步调试 用 GDB 调试程序 GDB 概述———— GDB 是 GNU开源组织发布的一个强大的 UNIX下的程序调试工具.或许,各位比较喜欢那种图形界面方式的,像 VC. BCB等 ...