当前位置: 首页 > article >正文

笔记一:字符函数和字符串函数

笔记系列文章为补充前面的知识点的篇章

目录

前言

一、函数介绍

 1.1strlen

 1.2 strcpy

 1.3 strcat

1.4 strcmp

 1.5 strncpy

1.6 strncat

1.7 strncmp

1.8 strstr

1.9  strtok

1.10 strerror

 1.11 memcpy

1.12 memmove 

 1.13 memcmp

 二、库函数的模拟实现

2.1 strlen模拟实现

2.2 strcpy模拟实现

 2.3 模拟实现strcat

 2.4 模拟实现strstr

 2.5 模拟实现strcmp

2.6 模拟实现memcpy

2.7 模拟实现memmove 

 tips:字符分类函数

 字符转换(大小写):


前言

         C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在 常量字符串 (如 “abcde” 就是一个常量字符串)或者 字符数组  (如 char s[3] )中。而常量字符串是存放在静态区的,不能被修改,所以 字符串常量 适用于那些对它不做修改的字符串函数。

一、函数介绍

 1.1strlen

        查阅手册观察strlen函数,strlen的返回值返回值为size_t类型(注意size_t,是无符号的整型),参数是一个char 类型的指针,其中加上了const修饰意味char*指向的内容不能够被修改。可以推断这个函数是用来计算字符串长度的,字符串都以‘\0'作为结束标志,那么strlen计算长度时是否会计入呢?

char s[] = "abcde";
printf("该字符串的长度为: %d\n", strlen(s));

结果:该字符串的长度为: 5

         则可以得出以下的几点:

  • 字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包 '\0' )。sizeof (计算数据类型所占空间的大小,单位为字节)与 strlen 计算字符串的长度时的区别,计入'\0'。
  • 参数指向的字符串必须要以 '\0' 结束。
  • 注意函数的返回值为size_t,是无符号的

 1.2 strcpy

   观察手册中strcpy函数的声明,发现strcpy的参数有两个char类型的指针,一个destination(目的符串),另外一个叫source(源字符串);返回类型也是个char类型的指针,在依照strcpy的命名,推断strcpy函数是把source(源字符串)的内容复制到destination(目的符串)中。

#include <string.h>

int main()
{
	char str1[] = "Do one's level best and leave the rest to world's will.";
	char str2[60];
	char str3[60];
	strcpy(str2, str1);  //str1的内容拷贝到str2
	strcpy(str3, "尽人事 听天命.");  //将常量字符串拷贝给str3
	printf("str1: %s\nstr2: %s\nstr3: %s\n", str1, str2, str3);
	return 0;
}


运行结果:
str1: Do one's level best and leave the rest to world's will.
str2: Do one's level best and leave the rest to world's will.
str3: 尽人事 听天命.

需要注意的几个点:

  • 源字符串必须以 '\0' 结束。
  • 会将源字符串中的 '\0' 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可变

 1.3 strcat

         手册中是这样描述strcat的功能:

        Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.

        大概意思为:source(源字符串)的从destination(目的符串)的'\0'位置开始追加source(源字符串,通过下面的示例,感受一下strcat的追加。

/* strcat example */
#include <stdio.h>
#include <string.h>

int main()
{
	char str[80];
	strcpy(str, "喜欢 ");
	strcat(str, "吃 ");
	strcat(str, "梨儿 ");
	printf("str: %s\n", str);
	return 0;
}


运行结果:
str: 喜欢 吃 梨儿

 注意:

  • 源字符串必须以 '\0' 结束。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。

1.4 strcmp

         手册中这样描述strcmp:Compares the C string str1 to the C string str2. 是将两个字符串进行比较,类似整型的比大小,可是这里是字符串,该怎么比呢?字符串的比较可以拆分成字母间的比较,比较字母的ascll码,如果相等就比较写一个字母,否则按照如下的标准,返回结果。

  • 标准规定:
  • 第一个字符串大于第二个字符串,则返回大于0的数字
  • 第一个字符串等于第二个字符串,则返回0
  • 第一个字符串小于第二个字符串,则返回小于0的数字
#include <stdio.h>
#include <string.h>

int main()
{
	char str1[] = "apple";
	char str2[]="banane";

	printf("比较结果为: %d\n", strcmp(str1, str2));
	return 0;
}


运行结果:
比较结果为: -1  //第一个字符串小于第二个字符串

 1.5 strncpy

         Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.

  • 拷贝num个字符从源字符串到目标空间。
  • 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

        strncpy和strcpy的功能类似,而strncpy可以控制拷贝的长度以及不够时补充

/* strncpy example */
#include <stdio.h>
#include <string.h>

int main()
{
	char str1[] = "Do one's level best";
	char str2[40] = { 0 };
	char str3[40] = "aaaaaaaa";

	strncpy(str2, str1, sizeof(str2)); //将str2的所有字符拷贝到str2

	strncpy(str3, str2, 3);  //将str2的三个字符拷贝到str3

	printf("str1: %s\nstr2: %s\nstr3: %s\n", str1, str2, str3);

	return 0;
}

运行结果:
str1: Do one's level best
str2: Do one's level best
str3: Do aaaaa    //拷贝的内容会覆盖原来的内容

1.6 strncat

        Appends the first num characters of source to destination, plus a terminating null-character.
If the length of the C string in source is less than num, only the content up to the terminating null-character is copied.

  • 将 source(源字符串) 的前 num 个字符追加到 destination(目标字符串),外加一个'\0'
  • 如果 source(源字符串)的长度小于 num,则仅复制'\0'字符之前的内容。
/* strncat example */
#include <stdio.h>
#include <string.h>

int main()
{
	char str1[20];
	char str2[20];
	strcpy(str1, "To be or not");
	strcpy(str2, "to be");
	strncat(str1, str2, 6);
	printf("str1: %s\nstr2: %s\n", str1, str2);
	return 0;
}

运行结果:
str1: To be or not to be
str2:  to be

1.7 strncmp

        功能与strcmp类似,但strncmp限定了比较字符的长度为num个

/* strncmp example */
#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)   //如果比较字符串的前两个字符,如果为R2则打印
		{
			printf("found %s\n", str[n]);
		}
	return 0;
}

运行结果:
Looking for R2 astromech droids...
found R2D2
found R2A6

1.8 strstr

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

/* strstr example */
#include <stdio.h>
#include <string.h>

int main()
{
	char str[] = "This is a simple string";
	char* pch;
	printf("%s\n", strstr(str, "simple"));
	return 0;
}

运行结果:
 simple string

1.9  strtok

  • delimiters参数是个字符串,定义了用作分隔符的字符集合
  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标 记。
  • strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修改)
  • strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  • 如果字符串中不存在更多的标记,则返回 NULL 指针。
/* strtok example */
#include <stdio.h>
#include <string.h>
int main()
{
	char str[] = "- This, a sample string.";
	char* pch;
	printf("Splitting string \"%s\" \ninto tokens:\n", str);
	pch = strtok(str, " ,.-");
	while (pch != NULL)
	{
		printf("%s\n", pch);
		pch = strtok(NULL, " ,.-");
	}
	return 0;
}

运行结果:
Splitting string "- This, a sample string."
into tokens:
This
a
sample
string

1.10 strerror

         返回错误码,所对应的错误信息

/* strerror example : error list */
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main ()
{
  FILE * pFile;
  pFile = fopen ("unexist.ent","r");
  if (pFile == NULL)
 printf ("Error opening file unexist.ent: %s\n",strerror(errno));  //打印错误码对应的错误信息
  return 0;
}

运行结果:
Error opening file unexist.ent: No such file or directory

 1.11 memcpy

  • 函数memcpysource的位置开始向后复制num个字节的数据到destination的内存位置。
  • 这个函数在遇到 '\0' 的时候并不会停下来。
  • 如果sourcedestination有任何的重叠,复制的结果都是未定义的。

1.12 memmove 

  • memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理。

 1.13 memcmp

  • 比较从ptr1ptr2指针开始的num个字节
  • 返回值如下:

 二、库函数的模拟实现

2.1 strlen模拟实现

//模拟实现strlen
size_t my_strlen(const char* str) {
	//计数器方式
	int count = 0;
	while (*str != '\0') {
		++count;
		++str;
	}

	return count;
}

size_t my_strlen(const char* str) {
	//递归方式
	if (*str != '\0')  return 0;

	else {
		return 1+my_strlen(str+1);
	}	
}

size_t my_strlen(const char* str) {
	//指针相减
	char* tail = str;
	while(*tail != '\0') {
		++tail;
	}

	return tail - str;
}

2.2 strcpy模拟实现

//strcpy复制串模拟实现
char* my_strcpy(char* dest, const char* src) {
	char* ret = dest;
	assert(dest != NULL);
	assert(src != NULL);
	while ((*dest++ = *src++)) {// 先复制后加加   /0值与0同,即赋值串终止停止
	}
	return ret;
}

 2.3 模拟实现strcat

char* my_strcat(char* dest, const char* src) {
	char* ret = dest;
	assert(dest && src);//断言
	while (*dest) {    //先到dest的'\0'位置
		dest++;
	}
	while ((*dest++ = *src++)) {  //当源字符串内容拷贝完成,结束
	}
	return ret;
}

 2.4 模拟实现strstr

//strstr模拟实现
char* strstr(const char* str1, const char* str2)
{
	char* cp = (char*)str1;
	char* s1, * s2;

	if (!*str2)  //str2为空字符串则返回str1
		return  (char*)str1;
	while (*cp)   //一个位置一个位置往下找与str2匹配字符串的位置
	{
		s1 = cp;
		s2 = (char*)str2;

		while (*s1 && *s2 && !(*s1 - *s2))
			s1++, s2++;

		if (!*s2) {  //str2走到'\0'位置说明找到了
			return  cp;
		}
			

		cp++;
	}
	return(NULL); //如果 str2 不是 str1 的一部分,则返回空指针
}

 2.5 模拟实现strcmp

//strcmp模拟实现
int my_strcmp(const char* src, const char* dst)
{
	int ret = 0;
	assert(src != NULL);
	assert(dst != NULL); //比较的字符串不能为空指针

	while (!(ret = *(unsigned char*)src - *(unsigned char*)dst) && *dst)  //一个字母一个字母的比较,不等则退出循环
		++src, ++dst;

	if (ret < 0)
		ret = -1;
	else if (ret > 0)
		ret = 1;

	return ret;
}

2.6 模拟实现memcpy

void* my_memcpy(void* dest, const void* src, size_t num) {//dest位拷贝内存,src拷贝字符串,num拷贝字符串长度
	
	assert(dest != NULL);
	assert(src != NULL);

	void* ret = dest;

	while (num--) {
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}

	return ret;
}

2.7 模拟实现memmove 

void* my_memmove(void* dest, const void*src, size_t num)//str区域与dest对比,进行重叠覆盖,相当于‘移位取代’
{
	void* ret = dest;
	assert(dest && src);
	if (dest < src)   //比较dest和src的相对位置,谁前谁后
	{
		//前->后
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		//后->前
		while (num--)
		{
			*((char*)dest+num) = *((char*)src + num);
		}
	}
	return ret;
}

 tips:字符分类函数

函数
如果他的参数符合下列条件就返回真
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
任何可打印字符,包括图形字符和空白字符

 字符转换(大小写):

int tolower ( int c );  //字符大写转小写
int toupper ( int c );  //字符小写转大写


http://www.kler.cn/a/564259.html

相关文章:

  • 小白向-用python实现选择排序
  • 想知道两轮差速方形底盘 URDF 咋做,ROS2 配 Rviz 咋显示吗?看这里!
  • Eureka的缓存原理分析
  • AI顿悟之旅 - 1 - DeepSeek的训练方法为什么相比GPT-o1大幅度减少算力资源?
  • Paperless-ngx文档管理系统本地部署
  • YOLOv5白皮书-第Y1周:调用官方权重进行检测
  • 轮式机器人在复杂地形中如何选择合适的全局路径规划算法?
  • 一、IDE集成DeepSeek保姆级教学(安装篇)
  • GPT1 与 GPT2 的异同
  • 鸿蒙新版开发工具DevEco Studio不能新建模拟的解决方法
  • 介绍下pdf打印工具类 JasperPrint
  • 【LeetCode】148. 排序链表
  • Spark Streaming是如何实现实时大数据处理的
  • path.join和path.resolve说明
  • Redis主从架构+使用sentinel实现主从架构高可用
  • 如何判断数据是否使用AES加密以及如何使用AES解密
  • 企业微信里可以使用的企业内刊制作工具,FLBOOK
  • ArcGIS Pro技巧实战:高效矢量化天地图地表覆盖图
  • JSX 的基础概述、优势与工作原理(babel解析为JS)
  • Linux操作系统:基于ELK栈的日志分析系统与数据爬虫的设计与实现