关于str家族

不受限制的字符串函数,比如说strcpy、strcmp等等,我们最常用的字符串函数都是不受限制的,只是通过寻找字符串参数结尾的NULL字节来判断它的长度。那么什么是受限制的字符串函数呢?通过下面的例子我们来一起详细了解一下

strcpy:

原型:char *strcpy( char *strDestination, const char *strSource );

这个函数把参数src字符串复制到dest参数中,在使用这个函数时需要注意,首先,必须保证目标字符数组的空间足以容纳需要复制的字符串,为什么呢?如果字符串比数组长,多余的字符仍然会被复制,这就导致它们会覆盖原先存储在数组后面的内存空间的值。其次,目标参数应该是可被修改的,所以它必须是个字符数组或者是一个指向动态分配内存的数组的指针。

1.strcpy模拟实现:

char *my_strcpy(char *dest, const char *src)
{
	char *ret = dest;
	assert(src != NULL);
	assert(dest != NULL);
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

strncpy:  把src所指向的字符串中以src地址开始的前n个字节复制到dest所指的数组中,并返回dest。

上面是不受限制的字符串函数,那么为什么会有strncpy这样一类受限制的字符串函数呢?

就拿这两个函数来说,strcpy只是复制字符串,但不限制复制的数量,很容易造成缓冲溢出。strncpy要安全一些。strncpy能够选择一段字符输出,strcpy则不能。

下面是strncpy模拟实现:

char *my_strncpy(char *dest, const char *src, int n)
{
	char *ret = dest;
	assert(dest);
	assert(src);
	while (n--)
	{
		*dest++ = *src++;
	}
		*dest = ‘\0‘;
	return ret;
}

2.将两个字符串连接,我们可以使用strcat函数

函数原型:

char *strcat( char *strDestination, const char *strSource );

功能:

把src所指字符串添加到dest结尾处(覆盖dest结尾处的‘\0‘)。

说明:

src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。

返回指向dest的指针

char *my_strcat(char *dest, const char *src)
{
	char *ret = dest;
	assert(src != NULL);
	assert(dest != NULL);
	while (*dest)
	{
		dest++;
	}
	while (*dest++ = *src++)
		{
			;
		}
	return ret;
}

strncat:

功能

把src所指字符串的前n个字符添加到dest所指字符串的结尾处,并覆盖dest所指字符串结尾的‘\0‘,从而实现字符串的连接。

说明

src和dest所指内存区域不可以重叠,并且dest必须有足够的空间来容纳src的字符串。

返回值

返回指向dest的指针。

char *my_strncat(char *dest, const char *src, int len)
{
	char *ret = dest;
	assert(dest);
	assert(src);
	while (*dest)
	{
		dest++;
	}
	while (len--)
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = ‘\0‘;
	return ret;
}

3.strcmp函数:比较两个字符串。

有一个需要注意的地方是

当s1<s2时,返回为负数;

当s1=s2时,返回值= 0;

当s1>s2时,返回正数。

即:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇‘\0‘为止。

有的人以为返回值是1和-1,分别代表大于和小于,如果你也这样想,那就错了。ANSI标准规定,返回值为正数,负数,0 。而确切数值是依赖不同的C实现的。

int my_strcmp(const char *str1, const char *str2)
{
	assert(str1);
	assert(str2);
	while (*str1 == *str2)
	{
		if (*str1 == ‘\0‘)
			return 0;
		str1++;
		str2++;
	}
		if (*str1 - *str2 > 0)
			return -1;
		else
			return 1;
}

strncmp函数原型:

int strncmp ( const char * str1, const char * str2, size_t n );

参数str1, str2 为需要比较的两个字符串,n为要比较的字符的数目。

字符串大小的比较是以ASCII 码表上的顺序来决定,此顺序亦为字符的值。strncmp()首先将s1 第一个字符值减去s2 第一个字符值,若差值为0 则再继续比较下个字符,直到字符结束标志‘\0‘,若差值不为0,则将差值返回。例如字符串"Ac"和"ba"比较则会返回字符"A"(65)和‘b‘(98)的差值(-33)。注意:要比较的字符包括字符串结束标志‘\0‘,而且一旦遇到‘\0‘就结束比较,无论n是多少,不再继续比较后边的字符。

strncmp函数模拟实现:

int my_strncmp(const char *dest, const char*src, int count)
{
	assert(dest);
	assert(src);
	while (count>0 && (*dest == *src))
	{
		if (*dest == ‘\0‘)
			return 0;
		dest++;
		src++;
		count--;
	}
	return *dest - *src;
}

4.为了在字符串中查找一个子串,我们可以使用strstr函数

函数原型:

char *strstr( const char *string, const char *strCharSet );

这个函数在s1中查找整个s2第一次出现的起始位置,并返回一个指向该位置的指针。如果s2没有完整地出现在s1的任何地方,函数将返回一个NULL指针。如果第二个参数是一个空字符串,函数就返回s1。

char *my_strstr(const char *str, const char *substr)
{
	assert(str != NULL);
	assert(substr != NULL);
	char *s1 = (char *)str;
	char *s2 = (char *)substr;
	char *start = (char *)str;
	while (*start)
	{
		s1 = start;
		while ((*s1 != ‘\0‘) && (*s2 != ‘\0‘) && (*s1 == *s2))
		{
			s1++;
			s2++;
		}
		if (*s2 == ‘\0‘)
			return start;
		s2 = (char *)substr;
		start++;
	}
	return NULL;
}

strrstr:

标准库中并不存在这样的函数,当然,如果需要,也可以很容易实现

strrstr函数在字符串s1中查找s2最后出现的位置

char* my_strrstr(char const *s1, char const *s2)
{
	char *last = NULL;  //将指针初始化为已经找到的前一次匹配位置
	char *current = NULL;
	assert(s1);
	assert(s2);
	if (*s2 )  //只有在第二个字符串不为空时才进行查找
	{
		current = (char *)strstr(s1, s2);//s2在s1中第一次出现的位置
		while (current != NULL)
		{
	//每次找到字符串时,让指针指向它的起始位置,然后查找该字符串下一个匹配位置
			last = current;   
			current = (char*)strstr(last + 1, s2);
		}
	}
	return last;
}

5.在一个字符串中查找一个特定字符最容易的方法是使用strchr函数

这个函数比较简单,下面是模拟实现:

#include<stdio.h>
#include<stdlib.h>

char *my_strchr(const char*str, int ch)
{
	while (*str)
	{
		if (*str == ch)
			return (char*)str;
		str++;
	}
	return NULL;
}
int main()
{
	char *str = "happy";
	char *ret = my_strchr(str, ‘a‘);
	if (ret != NULL)
	{
		printf("%c\n", *ret);
	}
	system("pause");
	return 0;
}

strrchr:

strrchr() 函数查找字符在指定字符串中从后面开始的第一次出现的位置,如果成功,则返回从该位置到字符串结尾的所有字符,如果失败,则返回 false。与之相对应的是strstr()函数,它查找字符串中首次出现指定字符的位置。

函数原型:

char *strrchr( const char *string, int c );

char *my_strrchr(char *str, char ch)
{
	char *ptr = NULL;
	assert(str);
	while (*str)
	{
		if (*str == ch)
			ptr = str;
		str++;
	}
	if (ptr != 0)
		return ptr;
	return 0;
}
int main()
{
	char ch = 0;
	char *ret = NULL;
	char *arr = "feabadc";
	printf("请输入一个你要查找的字符:");
	scanf_s("%c", &ch);
	ret = my_strrchr(arr, ch);
	printf("%s\n", *ret);
	system("pause");
	return 0;
}

当然,关于str这样的函数还有很多,这里模拟实现了一些经常用的函数,希望互相借鉴帮助。

时间: 2024-10-13 10:53:16

关于str家族的相关文章

cocos2d-x 2.2 study ------------------------ CCCallFunC家族

CCCallFunC家族 当我们需要在一个动作序列中某一个动作执行结束之后,调用某个函数用于执行一个任务的时候,我们可以使用CCCallFunC家族函数.CCCallFunC是CCActionInstant类的子类.值得注意的是,虽然CCCallFunC家族函数是瞬时动作函数的子类,但是所谓的瞬时,也只是指函数调用的一瞬间,而关于函数内部怎么执行,耗用多久,则完全与瞬时没有任何关系.CCCallFunC家族函数可以将函数调用的过程封装成一个动作类,从而放入动作序列中以供我们调用. HelloWo

v-once指令、v-cloak指令、条件指令家族、原义指令、循环指令、todolist案例、实例成员-符号、实例成员-计算属性、实例成员-属性监听、监听的案例、局部组件、全局组件、组件交互(父传子、子传父)

v-once指令: v-once:单独使用,限制的标签内容一旦赋值,便不可被动更改(如果是输入框,可以主动修改) <div id="app"> <input type="text" v-model="msg"> <!-- 一旦赋值,只可主动更改 --> <input type="text" v-model="msg" v-once> <p>{{ m

python判断字符串,str函数isdigit、isdecimal、isnumeric的区别

s为字符串s.isalnum() 所有字符都是数字或者字母s.isalpha() 所有字符都是字母s.isdigit() 所有字符都是数字s.islower() 所有字符都是小写s.isupper() 所有字符都是大写s.istitle() 所有单词都是首字母大写,像标题s.isspace() 所有字符都是空白字符.\t.\n.\r 判断是整数还是浮点数a=123b=123.123 >>>isinstance(a,int)True>>>isinstance(b,floa

int、str、list、tuple、dict补充

一.int a = 123 b = a# a与b指向同一个地址值 c = 123 d = 123 e = 123 #d.c.e当在-5~257这个范围时,都指向一个地址值(Python优化的结果,当超出这个范围,id与之不同) 二.str a. name = "你猜" for i in name: print(i) bytes_name = bytes(i, encoding='utf-8')# 字符转换成字节 print(byte_name)# 16进制表示 for byte in

TypeError: string indices must be integers, not str

1. TypeError: string indices must be integers, not str 字符串类型取第index个字符的时候,应该传入int而不是str.如 view source print? 1 a='abcdef' 2 print a[0] 3 #而不是 print a['0'] 更常见的情况是把一个string当成了字典在使用 :should_be_dict_but_string['id'] .这样的错误

Rust的str与String

字面量 http://doc.rust-lang.org/reference.html#literals 字面量是放在编译后的二进制的静态数据段的. str字面量引用 let a_str = "abcdefg" let b_str = "你好世界"  使用字符串字面量创建的字符串引用,其 lifetime 是 'static 的.而使用另一种方式:来自 String 的形式创建的&str,其 lifetime 是非 'static 的. &str是不

Java集合四大家族的故事(四)——Map家族的LinkedHashMap

每个家族都有一个最基本且最常用的数据类型:比如List系列的ArrayList,Map系列的HashMap,并且,它们的本质都是数组存储结构.相似的是,每个家族都有一个Linked开头的类,如List家族的LinkedList和Map家族的LinkedHashMap,这两个类的存储的数据结构又都是双向链表(其实是连续数组添加了两个方向的指针,所以既能与数组兼容,又能够有双向链表的性质).而引入双向链表功能的目的就是为了能够有序遍历. 今天,我们就来介绍LinkedHashMap. 扩展HashM

istringstream字符串流,实现类似字符串截取的功能,字符串流中的put,str()将流转换成为字符串string

 1. istringstream字符串流 #include <iostream> #include <sstream> #include <string> using namespace std; struct MyStruct { string str1, str2, str3; double db; int num; char ch; }; void main() { string  mystring("china  google microsoft

PyQt QString 与 Python str&amp;unicode

昨日,将许久以前做的模拟网页登录脚本用PyQt封装了一下,结果出大问题了, 登录无数次都提示登录失败!!而不用PyQt实现的GUI登录直接脚本登录无数次都提示登录成功!!心中甚是伤痛,于是探究起来,解决这一问题. 问题描述及证据如下: 上图是脚本MD5加密过程及结果 上图是PyQt GUI中获取密码框内容后加密的结果,其实现代码如下: # -*- coding: gbk -*- ''' Version : Python27 Author : Spring God Date : 2013-6-28