字符函数与字符串函数

1 strlen—求字符串长度

size_t strlen(const char * str);

1、 字符串以'\0'作为结束标志,strlen函数返回的是在字符串中'\0'前面出现的字符个数(不包含'\0')

2、 参数指向的字符串必须要以'\0'结束

3、 注意函数的返回值size_t,是无符号的

#include <stdio.h>
int main()
{
 const char*str1 = "abcdef";
 const char*str2 = "bbb";
 if(strlen(str2)-strlen(str1)>0)
 {
 printf("str2>str1\n");
 } 
 else
 {
 printf("srt1>str2\n");
 }
 return 0;
}

 

why?明明str2的长度是3,str1的长度是6,strlen(str1)>strlen(str2)

strlen的模拟实现(3种方法)

方法1:

size_t my_strlen(const char* str)
{
	assert(str);
	int len = 0;
	while (*str++)
	{
		len++;
	}
	return len;
}

方法2:指针-指针

size_t my_strlen(char* str)
{
    assert(str);
    char* p = str;
    while (*p)
    {
        p++;
    }
    return p-str;
}

方法3:递归

size_t my_strlen(const char* str)
{
	assert(str);
	if (*str == '\0')
		return 0;
	else
	{
		return my_strlen(str + 1) + 1;
	}
}

2 长度不受限制的字符串函数—strcpy

char * strcpy(char * destination, const char * source) ;

●strcpy 函数用于将 source 指针指向的 C 字符串(包括终止的空字符‘\0’)复制到 destination 指针指向的数组中,分配给 destination 的内存应足够大,以复制源字符串(包括‘\0’)。函数返回指针 destination

●源字符串必须以‘\0’结束

●会将源字符串中的‘\0’拷贝到目标空间

●目标空间必须足够大,能容纳源字符串的内容

●目标空间必须可变

●函数的返回指针destination是为了实现链式访问

	printf("%s\n", strcpy(str2, str1));

strcpy模拟实现

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

3 长度不受限制的字符串函数—strcat

char * strcat(char * destination, const char * source);

●strcat 函数用于将 source 指针指向的字符串追加到 destination 指针指向的字符串后面。在 destination 中,终止的空字符'\0'被 source 的第一个字符覆盖,新字符串的结尾包括一个空字符。函数返回指针 destination 。

●源字符串必须以‘\0’结束

●目标空间也要有结束标志

●目标空间必须足够大,能容纳源字符串的内容

●目标空间必须可变

?字符串自己给自己追加,可以吗?

不可以!str1作为目标空间,追加字符串会将末尾的结束标志'\0'覆盖,源字符串永远找不到'\0',会一直追加,直到目标空间溢出,导致运行错误。

 strcat函数模拟实现

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

3 长度不受限制的字符串函数—strcmp

int strcmp(const char * str1, const char * str2);

●strcmp函数从每个字符串的第一个字符开始比较。如果它们相等,它就继续比较后面的字符,直到出现不同的字符或者遇到终止的空字符为止。

●标准规定:

第一个字符串大于第二个字符串,则返回大于0的数字

第一个字符串等于第二个字符串,则返回0

第一个字符串小于第二个字符串,则返回小于0的数字

strcmp函数模拟实现

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2 && *str1 != '\0' )
	{
		str1++;
		str2++;
	}
	return *str1 - *str2;

}

 4 长度受限制的字符串函数—strncpy

char * strncpy ( char * destination, const char * source, size_t num );

 ●将source指向的源字符串的前num个字符复制到destination指向的目标字符串中。如果在复制num个字符之前,源字符串的结尾(以空字符为标志)被找到,那么目标字符串就用零填充,直到写入总共num个字符为止。

●拷贝num个字符从源字符串到目标空间

●如果源字符串的长度小于num,则拷贝完源字符串后,在目标空间后面追加‘\0’,知道拷贝数达到num个

应用实例1 源字符串长度大于num

int main()
{
	char str1[20] = "abcdef";
	char str2[20] = "cbb";
	printf("%s\n", strncpy(str1, str2, 3));
	return 0;
}

应用实例2  源字符串长度小于num

int main()
{
	char str1[10] = "abcdef";
	char str2[10] = "cbb";
	printf("%s\n", strncpy(str1, str2, 5));
	return 0;
}

 strncpy函数模拟实现

char* my_strncpy(char* dest, const char* src, size_t num)
{
	char* ret = dest;
	assert(dest && src);
	while (num && (*dest = *src))
	{
		dest++;
		src++;
		num--;
	}
	if (num == 0)
		return ret;
	else
	{
		while (num)
		{
			*dest = '\0';
			dest++;
			num--;
		}
		return ret;
	}

}

 5 长度受限制的字符串函数—strncat

●将source指向的字符串的前num个字符追加到destination指向的字符串后面,并在末尾添加一个空字符'\0'。

●如果source指向的字符串的长度小于num,那么也仅追加到source指向的字符串的最后一个空字符'\0'就停止。

应用实例1 源字符串长度大于num

int main()
{
	char str1[10] = "abcd\0efff";
	char str2[10] = "cbb";
	printf("%s\n", strncat(str1, str2, 2));
	return 0;
}

 应用实例2 源字符串长度小于num

int main()
{
	char str1[10] = "abcd\0efff";
	char str2[10] = "cbb";
	printf("%s\n", strncat(str1, str2, 5));
	return 0;
}

 strncat函数模拟实现 

char* my_strncat(char* dest, const char* src, size_t num)
{
	char* ret = dest;
	assert(dest && src);
	while (*dest)
	{
		dest++;
	}
	while (num && (*dest = *src))
	{
		dest++;
		src++;
		num--;
	}
	if (num == 0)
	{
		*dest = '\0';
	}
	return ret;
}

 6 长度受限制的字符串函数—strncmp

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

●比较到出现不一样的字符串或者其中一个字符串结束或者num个字符全部比较完

#include <stdio.h>
#include <string.h>
int main ()
{
  char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
  int n;
  puts ("Looking for R2 astromech droids...");
  for (n=0 ; n<3 ; n++)
  if (strncmp (str[n],"R2xx",2) == 0)//前两个字符相等就可以
 {
    printf ("found %s\n",str[n]);
 }
  return 0;
}

strncmp函数模拟实现

int my_strncmp(const char* str1, const char* str2, size_t num)
{
	while (num&&(*str1==*str2)&&(*str1))
	{
		str1++;
		str2++;
		num--;
	}
	if (num == 0)
	{
		return 0;
	}
	return *str1 - *str2;
}

7 字符串查找函数—strstr

char * strstr ( const char * str1 const char * str2); 

●返回一个指针,指向 str1 中 str2 第一次出现的位置,如果 str2 不是 str1 的一部分,则返回一个空指针

应用实例

#include <stdio.h>
#include <string.h>
int main ()
{
  char str[] ="This is a simple string";
  char * pch;
  pch = strstr (str,"simple");//返回的是simple中s的地址
  strncpy (pch,"sample",6);//从simple中s的地址开始,向后复制6个字符,将simple改为sample
  puts (str);//This is a sample string
  return 0;
}

strstr函数模拟实现

#include <stdio.h>
#include <string.h>
char* my_strstr(const char* str1, const char* str2)
{
	if (*str2 == '\0')
		return str1;
	while (*str1)
	{
		int len1 = strlen(str1);
		int len2 = strlen(str2);
		if (len1 < len2)//如果str1剩余的字符个数小于str2,str2一定不存在于str1中,跳出循环
			break;
		if (*str1 == *str2)
		{
			char* cp = str1;
			char* s1 = cp;
			char* s2 = str2;
			while ((*s1 == *s2) && *s2)
			{
				s1++;
				s2++;
			}
			if (*s2 == '\0')
			{
				return cp;
			}
		}
		str1++;
	}
	return NULL;
}

8 字符串查找函数—strtok

char * strtok ( char * str, const char * sep );

●sep参数是个字符串,定义了用作分隔符的字符集合

●第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。

●在第一次调用时,该函数需要一个字符串作为 str 的参数,其第一个字符用作扫描标记的起始位置。在后续的调用中,该函数需要一个空指针,并使用上一个标记结束后的位置作为新的扫描起始位置。

●为了确定一个标记的开始和结束,strtok函数首先从起始位置扫描,找到不包含在sep字符串中的第一个字符(这就是标记的开始)。然后从这个标记的开始处扫描,找到包含在sep字符串中的第一个字符,并将其用 \0 替换,这就是标记的结束。如果遇到终止空字符,扫描也会停止。最终返回一个指向标记开始的指针

●(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)

●strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数返回扫描起始位置的地址,并且保存这个标记后面的位置

● strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。 如果字符串中不存在更多的标记,则返回 NULL 指针。

应用实例 1

#include <stdio.h>
#include <string.h>
int main()
{
    char str[] = "- This, a sample string.";
    char* pch;
    printf("Splitting string \"%s\" into tokens:\n", str);
    pch = strtok(str, " ,.-");//被查找字符串中包含' (空格)'和','和'.'和'-',四个字符
                            //首先strtok从str第一个字符开始扫描,找到第一个不是上述字符的字符 
                              作为标记的开始,那就跳过了str第1个和第2个字符'-'和' (空格)', 
                              将T作为标记的开始
                             //找到','后将其变为'\0',返回T的地址,赋值给pch,并且保存
                               ' (空格)'(这个空格是','后面那个空格)的地址

    while (pch != NULL)
    {
        printf("%s\n", pch);//打印从T的地址开始打印,直到'\0',这个'\0'其实是我们找到的','变成 
                              的'\0'
        pch = strtok(NULL, " ,.-");//strtok函数又' (空格)'开始扫描,找到第一个不是上述4种字符 
                                     的字符作为标记的开始,那就跳过了' (空格)',将a作为标记的 
                                     开始
                                   //找到' (空格)'后将其变为'\0',返回a的地址,赋值给pch,并且 
                                     保存sample的s的地址
    }
    return 0;
}

 应用实例 2

int main()
{
	char arr[] = "xxdwf@tji.ecu%cn&ee";
	char sep[] = "@.%&";
	char* str = NULL;
	char p[30];
	strcpy(p,arr);//strtok函数会改变字符串,因此将arr字符串拷贝,使用p进行查找
	for (str = strtok(p, sep); str != NULL;str = strtok(NULL,sep))
	{
		printf("%s\n", str);
	}
	return 0;
}

 9 信息错误报告函数—strerror

char * strerror (int errnum);

●库函数在执行的时候发生错误会将一个错误码存放在errno这个变量中,errno是C语言提供的一个全局变量。

●strerror函数能够将错误码对应错误信息字符串的首字符的地址返回。

int main()
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d:%s\n", i, strerror(i));
	}
	return 0;
}

 应用实例

#include <stdio.h> 
#include <string.h> 
#include <errno.h>//使用errno必须包含的头文件

int main()
{
	//C语言中可以操作文件
	//操作文件的步骤
	//1、打开文件
	//2、读\写
	//3、关闭文件
	FILE* pf = fopen("unexist.ent", "r");//fopen是打开文件函数,"unexist.ent"不写路径表示当前路径下,"r"-read
	if (pf == NULL)//如果文件打开失败,则返回空指针
	{
		printf("%s\n", strerror(errno));//打印打开文件失败的错误信息
		return 1;
	}
	//读\写
	//...
	//关闭文件
	fclose(pf);
	return 0;
}

10 字符函数—字符分类函数

●使用时要包含头文件<ctype.h>

函数如果他的参数符合下列条件就返回真
iscntrl任何控制字符
isspace空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v'
isdigit十进制数字 0~9
isxdigit十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F
islower小写字母a~z
isupper大写字母A~Z
isalpha字母a~z或A~Z
isalnum字母或者数字,a~z,A~Z,0~9
ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph 任何图形字符
isprint任何可打印字符,包括图形字符和空白字符

 11 字符函数—字符转换函数

●使用时要包含头文件<ctype.h>

int tolower ( int c );//转换成小写

int toupper ( int c );//转换成小写

#include<stdio.h>
#include<ctype.h>
int main()
{
	char str[] = "She is my Good Friend";
	int i = 0;
	while (str[i])
	{
		if (isupper(str[i]))//判断是否为大写字母
			str[i] = tolower(str[i]);//转换为小写字母
		i++;
	}
	printf("%s\n", str);
	return 0;
}

 12 内存函数—memcpy

void * memcpy ( void * destination, const void * source, size_t num)

●函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置

●这个函数在遇到'\0'时不会停下来

●如果source和destination有任何的重叠,复制的结果都是未知的。

应用实例 1:函数在遇到'\0'时不会停下来,直到复制num个字节

int main()
{
	char str1[10] = "abcdefg";
	char str2[10] = "qwe\0r";
	memcpy(str1, str2, 5);
	printf("%s\n",str1);
	return 0;
}

应用实例2:source 和destination有重叠

int main()
{
	int a[10] = {1,2,3,4,5,6,7,8,9,10};
	memcpy(a + 2, a, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", a[i]);//1 2 1 2 3 4 5 8 9 10
	}
	return 0;
}

memcpy是用来处理不重叠内存的拷贝,VS编译器优化了他的功能,使得结果是正确的,但最好还是用处理重叠拷贝的函数memmove函数来进行重叠空间的拷贝最好!

应用实例 3:

int main()
{
	int a[6] = { 1,2,3,4,5,6};
	int a2[6] = { 0 };
	memcpy(a2, a, 21);
	int i = 0;
	for (i = 0; i < 6; i++)
	{
		printf("%d ", a2[i]);
	}
	return 0;
}

 

memcpy函数模拟实现

void* my_memcpy(void* dest, void* src, size_t num)
{
	void* ret = (char*)dest;
	assert(dest && src);
	while (num--)
	{
		*((char*)dest)++ = *((char*)src)++;
	}
	return ret;
}

 13 内存函数—memmove

void * memmove ( void * destination, const void * source, size_t num)

●和memcpy的差别就是,函数memmove处理的源内存块和目标内存块可以重叠

●如果源空间和目标空间出现重叠,就得使用memmove函数处理

应用实例:

#include <stdio.h> 
#include <string.h> 
int main()
{
	char str[] = "memmove can be very useful......";
	memmove(str + 20, str + 15, 11);
	puts(str);
	return 0;
}

memmove函数模拟实现

#include <stdio.h> 
#include <string.h> 
void* my_memmove(void* dest, void* src, size_t num)
{
	void* ret = (char*)dest;
	assert(dest && src);
	if (src > dest)
	{
		while (num--)
		{
			*((char*)dest)++ = *((char*)src)++;
		}
		return ret;
	}
	else
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}

 完结,撒花!🌸🌸🌸

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值