我的strcat:

 char *strcat(char *dest,char *src)
{
char * reval = dest;
while(*dest)
dest++;
while(*src)
*dest++ = *src++ ;
*dest = *src;
return reval;
}

MSVC:

 char * __cdecl strcat (
char * dst,
const char * src
)
{
char * cp = dst; while( *cp )
cp++; /* find end of dst */ while( *cp++ = *src++ ) ; /* Copy src to end of dst */ return( dst ); /* return dst */ }

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

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

我的strncat:

 char *strncat(char *dest,char *src,int n)
{
char * reval = dest;
while(*dest)
dest++;
while(n-- && (*dest++ = *src++));
if(n < )
*dest = ;
return reval;
}

MSVC:

 char * __cdecl strncat (
char * front,
const char * back,
size_t count
)
{
char *start = front; while (*front++)
;
front--; while (count--)
if (!(*front++ = *back++))
return(start); *front = '\0';
return(start);
}

我的strchr:

 char *strchr(const char *s,char c){
while(*s)
{
if(*s == c)
return s;
s++;
}
return NULL;
}

MSVC:

 char * __cdecl strchr (
const char * string,
int ch
)
{
while (*string && *string != (char)ch)
string++; if (*string == (char)ch)
return((char *)string);
return(NULL);
}

我的strcmp:

 int strcmp(const char *s1,const char * s2){
while(*s1 == *s2 && *s1)
{
++s1;
++s2;
}
return *(unsigned char *)s1 - *(unsigned char *)s2;
}

MSVC:

 int __cdecl strcmp (
const char * src,
const char * dst
)
{
int ret = ; while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
++src, ++dst; if ( ret < )
ret = - ;
else if ( ret > )
ret = ; return( ret );
}

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

我的strcpy:

 char *strcpy(char *dest,const char *src){
char * reval = dest;
while(*dest++ = *src++);
return reval;
}

MSVC:

 char * __cdecl strcpy(char * dst, const char * src)
{
char * cp = dst; while( *cp++ = *src++ )
; /* Copy src over dst */ return( dst );
}

我的strncpy:

 char *strncpy(char *dest, const char *src, int n){
char * reval = dest;
while(n--){
if(*src)
*dest++ = *src++;
else
*dest++ = ;
}
return reval;
}

MSVC:

 char * __cdecl strncpy (
char * dest,
const char * source,
size_t count
)
{
char *start = dest; while (count && (*dest++ = *source++)) /* copy string */
count--; if (count) /* pad out with zeroes */
while (--count)
*dest++ = '\0'; return(start);
}

我的strcspn:

 int strcspn(const char *s1,const char *s2){
const char *cp;
int reval = ;
for(; *s1; s1++){
for(cp = s2; *cp; cp++){
if(*s1 == *cp)
return reval;
}
++reval;
}
return reval;
}

MSVC:

 size_t __cdecl strcspn (
const char * string,
const char * control
)
{
const unsigned char *str = string;
const unsigned char *ctrl = control; unsigned char map[];
int count; /* Clear out bit map */
for (count=; count<; count++)
map[count] = ; /* Set bits in control map */
while (*ctrl)
{
map[*ctrl >> ] |= ( << (*ctrl & ));
ctrl++;
} /* 1st char in control map stops search */
count=;
map[] |= ; /* null chars not considered */
while (!(map[*str >> ] & ( << (*str & ))))
{
count++;
str++;
}
return(count);
}

函数说明: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

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

例如:

 #include <stdio.h>
#include <errno.h> int main(void)
{
char *buffer;
buffer = strerror(errno);
printf("Error: %s\n", buffer);
return ;
}

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

我的strlen:

 int strlen(const char *s){
const char *cp = s;
while(*cp){
cp++;
}
return (cp - s);
}

MSVC:

 size_t __cdecl strlen (
const char * str
)
{
const char *eos = str; while( *eos++ ) ; return( (int)(eos - str - ) );
}

返回值应该不需要强制类型转换,因为指针相减返回值是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:

 char *strrchr(const char *str, const char c){
const char *cp = str;
if(*str == )
return NULL;
while(*str)
str++;
while(*cp++){
if(*--str == c)
return str;
}
return NULL;
}

MSVC:

 char * __cdecl strrchr (
const char * string,
int ch
)
{
char *start = (char *)string; while (*string++) /* find end of string */
;
/* search towards front */
while (--string != start && *string != (char)ch)
; if (*string == (char)ch) /* char found ? */
return( (char *)string ); return(NULL);
}

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

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

MSVC:

 char * __cdecl strtok (
char * string,
const char * control
)
{
unsigned char *str;
const unsigned char *ctrl = control; unsigned char map[];
int count; static char *nextoken; /* Clear control map */
for (count = ; count < ; count++)
map[count] = ; /* Set bits in delimiter table */
do {
map[*ctrl >> ] |= ( << (*ctrl & ));
} while (*ctrl++); /* Initialize str. If string is NULL, set str to the saved
* pointer (i.e., continue breaking tokens out of the string
* from the last strtok call) */
if (string)
str = string;
else
str = nextoken; /* Find beginning of token (skip over leading delimiters). Note that
* there is no token iff this loop sets str to point to the terminal
* null (*str == '\0') */
while ( (map[*str >> ] & ( << (*str & ))) && *str )
str++; string = str; /* Find the end of the token. If it is not the end of the string,
* put a null there. */
for ( ; *str ; str++ )
if ( map[*str >> ] & ( << (*str & )) ) {
*str++ = '\0';
break;
} /* Update nextoken (or the corresponding field in the per-thread data
* structure */
nextoken = str; /* Determine if a token has been found. */
if ( string == str )
return NULL;
else
return string;
}

用一个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. 观察者模式:猫叫鼠跑人醒(C#)

    本着菜鸟先飞的想法,决定把平时遇到的知识点记录下来,一来是加深理解,二来是方便以后自己查阅.当您看到我这篇文章的时候,觉得代码有哪里不足的地方,请多指教,谢谢.(命名不规范是为了加深自己的理解,多多见 ...

  2. ajax 实现异步请求

    ajax实现异步请求: function onclicks() { $.ajax( { url:'../hhh/columnSearch.do',// 跳转到 action // data: {tab ...

  3. 整理mysql的一些常用用法

    在php项目中,使用mysql的一些常用的语句,今天有空系统整体一下.有些整理自网络,如有错误,请指正,谢谢.... #显示数据库和显示数据表show databases;use databaseNa ...

  4. smarty 判断变量是否为空

    {if $val.title!=""} 这里填写想要输出的内容即可 {/if}

  5. virtualBox 安装CentOS 全屏

    在VirtualBox里安装CentOS系统,会遇到“增强工具”无法正常安装,主要的原因是出在Kernel 库找不到. 错误提示如下: 通过查看日志文件: cat /var/log/vboxadd-i ...

  6. codeforces 702E Analysis of Pathes in Functional Graph 倍增

    题目链接 给一个图, 然后给出每条边的权值和一个k值. 让你求出从每个点出发, 走k次能获得的边权的和以及边权的最小值. 用倍增的思想, 求出每个点走一次能到达的点, 权值和以及最小值, 走两次..四 ...

  7. 如何交换a和b两个整数的值,不用额外空间

    这个题貌似完全颠覆一般的Logic:交换两个整数需要一个额外的空间用于保存: t = b; b = a; a  = t; 粗看上去似乎没有办法,但是仔细想一下,既然不能用额外的空间,那么能用的方法就只 ...

  8. 求解printf函数?

    求大神解释一下下面的代码为什么答案不是1 2,而是1 0. #include <stdio.h> int ans = 0; int a() { ans = 1; return ans++; ...

  9. xshell使用命令总结

    这个工具主要是链接linux 并且可以从linux上面下载文件到本地 还有上传本地文件到linux上面 下载首先需要压缩打包命令为: tar -cf am_mailer.tar * sz am_mai ...

  10. getBoundingClientRect()来获取页面元素的位置”

    getBoundingClientRect()来获取页面元素的位置” 获取的是一个对象; 延伸阅读; https://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA== ...