string.h c源码实现

int isspace( char c )
{
	char comp[] = { ‘ ‘, ‘\t‘, ‘\r‘, ‘\n‘, ‘\v‘, ‘\f‘ };
	const int len = 6;
	for ( int i=0; i<len; ++i )
	{
		if ( c == comp[i] )
			return 1;
	}
	return 0;
}

char tolower( char c )
{
	if ( c >= ‘A‘ && c <= ‘Z‘ )
		return ( c + 32 );
	return c;
}

// 在字符串s中查找 c 第一次出现的 位置。
// 找到: 返回指针位置; 未找到: 返回NULL
char * strchr( const char * s, int c )
{
	for ( ; *s != (char)c; ++s )
	{
		if ( *s == ‘\0‘ )
			return NULL; // 如果s已抵达尾部,为找到,返回NULL
	}

	return (char *)s; // 返回 c在s的指针位置
}

// 在字符串S中从末尾开始查找字符c, 找到则返回 字符串指针位置,未找到返回NULL
char * strrchr( const char * s, int c )
{
	const char * p = s + strlen( s ); // p 指向 s 的末端
	do {
		if ( *p == (char)c )
			return (char *)p; //
	} while ( --p >= s ); 

	return NULL;
}

// 在字符串S中指定长度内查找字符C。
char * strnchr( const char * s, size_t count, int c )
{
	for ( ; count-- && *s != ‘\0‘; ++s )
	{
		if ( *s == (char)c )
			return (char *)s;
	}

	return NULL;
}

// 搜索一个字符串 s2 在另一个字符串 s1 中的第一次出现
char * strstr( const char * s1, const char * s2 )
{
	size_t l1, l2;
	l2 = strlen( s2 );

	if ( !l2 )
		return (char *)s1;
	l1 = strlen( s1 );
	while ( l1 >= l2 )
	{
		l1--;
		if ( !memcmp( s1, s2, l2) )
			return (char *)s1;
		s1++;
	}
	return NULL;
}

// 从字符串s开头查找符合 accept 字符, 返回字符串s开头连续包含字符串 accept 内的字符数目。
// 如返回n,则代表 字符串s 开头连续有n个字符都属于字符串accept内的字符。
//char *str="Linux was first developed for 386/486-based pcs.";
//printf("%d\n",strspn(str,"Linux")); // 输出为 5
//printf("%d\n",strspn(str,"/-")); // 输出为 0
//printf("%d\n",strspn(str,"1234567890")); // 输出为 0
size_t strspn( const char * s, const char * accept )
{
	const char * p;
	const char * a;
	size_t count = 0;

	for ( p = s; *p != ‘\0‘; ++p )
	{
		for ( a = accept; *a != ‘\0‘; ++a ) // *p 逐个与 accept允许的字符串比对。
		{
			if ( *p == *a ) // 只要符合 accept,跳出accept循环,count+1
				break;
		}
		if ( *a == ‘\0‘ ) // 如果 accept 到了末尾,则表示出现第一个不符合accept的字符位置了。
			return count;
		++count;
	}
	return count;
}

// 从字符串s开头查找符合 reject 字符, 返回字符串s 开头连续不含字符串 reject 内的字符数目
// 如返回n, 则代表字符串s 开头连续有n 个字符都不含字符串 reject 内的字符.
//char *str = "Linux was first developed for 386/486-based pcs. ";
//printf("%d\n", strcspn(str, " ")); // 输出 5 ;只计算到" "的出现, 所以返回"Linux"的长度
//printf("%d\n", strcspn(str, "/-")); // 输出 33 ; 计算到出现"/"或"-", 所以返回到"6"的长度
//printf("%d\n", strcspn(str, "1234567890")); // 输出 30 ; 计算到出现数字字符为止, 所以返回"3"出现前的长度
size_t strcspn( const char * s, const char * reject )
{
	const char * p;
	const char * r;
	size_t count = 0;

	for ( p = s; *p != ‘\0‘; ++p )
	{
		for ( r = reject; *r != ‘\0‘; ++r )
		{
			if ( *p == *r ) // 如果 *p 等于 *r, 则返回 长度
				return count;
		}
		++count; // 2者不相等时,count+1
	}

	return count;
}

// 在字符串S1中 检验 S2串,当s2字符出线在s1中时,则停止检验,并返回该字符位置
// char *s = "12,3a,45"
// char *ptr = strpbrk(s, ","); // ptr = ,3a,45
char * strpbrk( const char * s1, const char * s2 )
{
	const char * sc1, * sc2;
	for ( sc1 = s1; *sc1 != ‘\0‘; ++sc1 )
	{
		for ( sc2 = s2; *sc2 != ‘\0‘; ++sc2 )
		{
			if ( *sc1 == *sc2 ) 	// 如果 在 s1 中找到符合 s2 的字符
				return (char *)sc1; // 则直接返回该字符位置
		}
	}
	return NULL; // 未找到则返回 NULL
}

char * strsep( char **s, const char *ct )
{
	char * sbegin = *s;
	char * end;

	if ( *sbegin == NULL )
		return NULL;

	end = strpbrk( sbegin, ct ); // 在 sbegin 中 查找 ct 第一次出线的位置。
	if ( end ) // 找到了
		*end++ = ‘\0‘; // 添加 结束符‘\0‘

	*s = end; // s指向了新的 开始位置
	return sbegin;
}

// 跳过空白符
char * skip_spaces( const char * str )
{
	while ( isspace( *str) )
		++str;
	return (char *)str;
}

// 跳过首尾的空白符
char * strim( char * s )
{
	size_t size;
	char * end;

	s = skip_spaces( s ); // 跳过空白符
	size = strlen( s ); // 计算 s 字符长度
	if ( !size ) // 长度为0,则直接返回s
		return s; // s = ‘\0‘

	end = s + size - 1; // end 指向 s 字符串末尾
	while ( end >= s && isspace( *end ) ) // 跳过末尾的空白符
		end--;
	*( end + 1 ) = ‘\0‘; // 设置下一位为 ‘\0‘

	return s;
} 

// 计算字符串s的长度. 以 ‘\0‘ 结尾
size_t strlen( const char * s )
{
	const char * sc;
	for ( sc = s; *sc != ‘\0‘; ++sc )
		; // nothing
	return sc - s;
}

// 比较指定长度的2个字符串, 不区分大小写
int strnicmp( const char * s1, const char * s2, size_t len )
{
	unsigned char c1, c2;
	if ( !len )
		return 0;

	do {
		c1 = *s1++;
		c2 = *s2++;

		if ( !c1 || !c2 ) // 如果其中一个为空
			break;
		if ( c1 == c2 ) // 相等,则继续比较下一个
			continue;
		c1 = tolower( c1 );
		c2 = tolower( c2 ); // 都转换为小写
		if ( c1 != c2 ) // 不相等
			break;
	} while ( --len ); // 在指定长度内比较

	return (int)c1 - (int)c2; // 跳出循环后,比较字符是否相等。
}

// 比较2个字符串, 不区分大小写。
int strcasecmp( const char * s1, const char * s2 )
{
	int c1, c2;
	do {
		c1 = tolower( *s1++ );
		c2 = tolower( *s2++ );
	} while ( c1 == c2 && c1 != ‘0‘ ); //

	return c1 - c2;
}

// 比较指定长度的2个字符串, 不区分大小写
int strncasecmp( const char * s1, const char * s2, size_t n )
{
	int c1, c2;
	do {
		c1 = tolower( *s1++ );
		c2 = tolower( *s2++ );
	} while ( ( --n > 0) && c1 == c2 && c1 != ‘0‘ ); //

	return c1 - c2;
}

// 字符串拷贝。 将 src 内容 拷贝到 dest 中。
// 这里不带长度,src 长度 大于 dest 长度,则会超出 存储范围。
char * strcpy( char * dest, const char * src )
{
	char * begin = dest; // 指向 目的存储空间 的 开始。

	while ( ( *dest++ = *src++) != ‘\0‘ ) // 逐字符保存内容。s
		; // nothing

	return begin;
}

// 字符串拷贝。 将 src 指定长度的内容 拷贝到 dest 中。
char * strncpy( char  * dest, const char * src, size_t count )
{
	char * move = dest;

	while ( count )
	{
		if ( ( *move = *src ) != ‘\0‘ )
			src++;
		move++;
		count--;
	}

	return dest;
}

// 字符串拼接, 将 src 内容 拷贝到 dest 的后面
char * strcat( char * dest, const char * src )
{
	char * begin = dest;

	while ( *dest )
		dest++; // 

	while ( ( *dest++ = *src++ ) != ‘\0‘ )
		; // do nothing

	return begin;
}

// 字符串拼接, 将 src 指定长度的内容 拷贝到 dest 的后面
char * strncat( char * dest, const char * src, size_t count )
{
	char * begin = dest;

	while ( *dest )
		dest++; // 

	while ( ( *dest++ = *src++ ) != ‘\0‘ )
	{
		if ( --count == 0 )
		{
			*dest= ‘\0‘;
			break;
		}
	}
		; // do nothing

	return begin;
}

// 比较2个字符串。 返回值: 0, -1, 1
int strcmp( const char * s1, const char * s2 )
{
	unsigned char c1, c2;

	while ( 1 )
	{
		c1 = *s1++;
		c2 = *s2++;
		if ( c1 != c2)
			return ( c1 < c2 ) ? -1 : 1; // 不相等 返回 -1 1
		if ( !c1 ) // 如果c1 已抵达末尾
			break;
	}

	return 0; // 相等返回 0
}

// 指定长度的2个字符串比较。 返回 0 -1 1
int strncmp( const char * s1, const char * s2, size_t count )
{
	unsigned char c1, c2;

	while ( count )
	{
		c1 = *s1++;
		c2 = *s2++;
		if ( c1 != c2 )
			return ( c1 < c2 ) ? -1 : 1; // 不相等 返回 -1 1
		if ( !c1 )
			break;

		count--; // 长度减1
	}

	return 0; // 相等返回 0
}

// 将 s 内长度为count 的内容 用c 来初始化s
void * memset( void *s, int c, size_t count )
{
	char * xs = (char *)s;
	while ( count-- )
		*xs++ = c;
	return s;
}

// 将 src 内count长度内容 拷贝到 dest 中
void * memcpy( void * dest, const void * src, size_t count )
{
	char * tmp = (char *)dest;
	const char * s = (const char *)src;
	while ( count-- )
		*tmp++ = *s++;

	return dest;
}

// 比较 s1 s2大小, 返回一个整数
int memcmp( const void * s1, const void *s2, size_t count )
{
	const unsigned char * su1 = (const unsigned char *)s1;
	const unsigned char * su2 = (const unsigned char *)s2;

	int res = 0;
	for ( ; count > 0; ++su1, ++su2, --count )
	{
		if ( ( res = *su1 - *su2 ) != 0 ) // 不相等,则跳出循环。
			break;
	}
	return res;
}

  

时间: 2024-10-15 16:38:02

string.h c源码实现的相关文章

JDK中String类的源码分析(二)

1.startsWith(String prefix, int toffset)方法 包括startsWith(*),endsWith(*)方法,都是调用上述一个方法 1 public boolean startsWith(String prefix, int toffset) { 2 char ta[] = value; 3 int to = toffset; 4 char pa[] = prefix.value; 5 int po = 0; 6 int pc = prefix.value.l

String类常用方法源码分析

环境:JDK8 主要分析String类的一些常用的方法源码. String 先看String类的定义: public final class String    implements java.io.Serializable, Comparable<String>, CharSequence 可以看到String类被final修饰,因此不能被继承.String类还实现了序列化接口Serializable.可比较的接口Comparable并指定范型为String,该接口必须要实现int comp

Unix NetWork Programming(unix环境编程)——环境搭建(解决unp.h等源码编译问题)

此配置实例亲测成功,共勉,有问题大家留言. 环境:VMware 10 + unbuntu 14.04 为了unix进行网络编程,编程第一个unix程序时遇到的问题,不能包含unp.h文件,这个感觉和apue.h差不多,不过这里需要编译源代码,为了以后方便,现在整理如下: 主要有两点一是生成libunp.a这个库,二是得到unp.h.config.h这两个个头文件. 1,安装编译器,为了齐全还是安装一下build-essential sudo apt-get install build-essen

String.getBytes(),源码之下,了无秘密

@Deprecated public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) { if (srcBegin < 0) { throw new StringIndexOutOfBoundsException(srcBegin); } if (srcEnd > value.length) { throw new StringIndexOutOfBoundsException(srcEnd); } if (s

Java源码分析——String的设计

Tip:笔者马上毕业了,准备开始Java的进阶学习计划.于是打算先从String类的源码分析入手,作为后面学习的案例.这篇文章寄托着今后进阶系列产出的愿望,希望能坚持下去,不忘初心,让自己保持那份对技术的热爱. 因为学习分析源码,所以借鉴了HollisChuang成神之路的大部分内容,并在此基础上对源码进行了学习,在此感谢. 问题的引入 关于String字符串,对于Java开发者而言,这无疑是一个非常熟悉的类.也正是因为经常使用,其内部代码的设计才值得被深究.所谓知其然,更得知其所以然. 举个例

Java String源码解析

String类概要 所有的字符串字面量都属于String类,String对象创建后不可改变,因此可以缓存共享,StringBuilder,StringBuffer是可变的实现 String类提供了操作字符序列中单个字符的方法,比如有比较字符串,搜索字符串等 Java语言提供了对字符串连接运算符的特别支持(+),该符号也可用于将其他类型转换成字符串. 字符串的连接实际上是通过StringBuffer或者StringBuilder的append()方法来实现的 一般情况下,传递一个空参数在这类构造函

死磕 Java 系列(一)&mdash;&mdash; 常用类(1) String 源码解析

写在前面 这是博主新开的一个 java 学习系列,听名字就可以看出来,在这一些系列中,我们学习的知识点不再是蜻蜓点水,而是深入底层,深入源码.由此,学习过程中我们要带着一股钻劲儿,对我们不懂的知识充满质疑,力求把我们学过的知识点都搞清楚,想明白. 一.引言 在 java 的世界里,存在一种特殊的类,它们的创建方式极为特别,不需要用到 new XXX(当然也可以用这种方式创建), 但是却大量出现在我们的代码中,那就是 String 类.作为日常中使用频率最高的类,它是那么普通,普通到我们从来都不会

Android研发中对String的思考(源码分析)

1.常用创建方式思考: String text = "this is a test text "; 上面这一句话实际上是执行了三件事 1.声明变量 String text; 2.在内存中开辟空间 (内存空间一) 3.将变量的text的引用指向开辟的内存空间 当有 text = "this is a change text"; 这一句话执行了两件事 1.在内存中开辟空间 2.将变量text 的引用指向 新开辟的内存空间 3.内存空间一此时依然存在,这就是说明了Stri

String、StringBuilder、 StringBuffer 深入分析 源码解析

java学习有一段时间了,但学习的东西都是框架等东西,java基础知识有点遗忘,所以重温一下java基础知识,写写文章里面有错的希望大家指正共同进步~~ 一.String 大家经常会说使用"+"号连接String 字符串比StringBuffer慢,String类对象为不可变对象,一旦你修改了String对象的值,隐性重新创建了一个新的对象,那接下来我们详细分析一下为什么使用"+"号速度会慢,为什么String 对象是不可变对象: 1.final修饰类.引用变量.基