我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C语言的字符串函数,内存函数笔记详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C语言的字符串函数,内存函数笔记详解

strlen

此函数接收一个char*类型参数,返回字符串\0前字符数,注意返回类型是size_t型的


//关于strlen返回值的一个易错点
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;
}

strlen模拟实现

法一

使用计数器


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

法二

指针相减


size_t my_strlen2(const char* str)
{
	assert(str);
	char* start = str;
	while (*str!='\0')//注意这种写法不能写*str++;这里要先判断再++;*str++的写法在'\0'的地方也+1了
	{
		str++;
	}
	return str - start;//\0与起始位置的差就是字符数
}

法三

递归,不适用临时变量


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

strcpy

此函数接收两个char*类型参数,把后一个字符串拷贝到前一个字符串中,包括\0,注意前一个指针指向的数组空间要足够大,被拷贝的内容必须包含\0

strcpy的模拟实现


char* my_strcpy(char* dest, const char* class="lazy" data-src)
{
	assert(dest && class="lazy" data-src);
	char* ret = dest;
	while (*dest++ = *class="lazy" data-src++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[20] = "hello underworld";//注意写成数组
	char arr2[20] = "hello world";

	printf("%s\n", arr2);
	printf("%s\n", my_strcpy(arr2, arr1));

	return 0;
}

strcat

此函数接收两个char*参数,在前一个字符串\0的位置开始拷贝后一个字符串,直到后一个字符串的\0,返回前一个字符串首地址。注意要保证前一个指针指向的空间足够大

strcat的模拟实现


char* my_strcat(char* dest, const char* class="lazy" data-src)
{
	char* ret = dest;
	assert(dest && class="lazy" data-src);
	while (*dest)//让dest到达str1的\0位置
	{
		dest++;
	}
	while (*dest++ = *class="lazy" data-src++)//这一部分和strcpy同
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[20] = "hello ";
	char arr2[20] = "underworld";

	printf("%s\n", my_strcat(arr1, arr2));

	return 0;
}

strcmp

接收两个char*参数,依次比较每个字符,在第一个不相等的字符处比较他们的编码值,前者大则返回一个大于0的数,前者小则返回一个小于0的数,字符串完全相等则返回0

strcmp模拟实现


int my_strcmp(const char* str1, const char* str2)
{
	while (*str1 == *str2)
	{
		if (*str1 == '\0')//说明两个字符串同时到达结束标记
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;//如果不是在循环内部返回,就一定不相等,而字符相减可以反映大小
}
int main()
{
	char *str1 = "hello world";
	char *str2 = "hello underworld";

	printf("%d\n", my_strcmp(str1, str2));//w比u大

	return 0;
}

strstr

接收两个char*参数,返回第二个字符串在第一个字符串第一次出现的首位置指针

strstr模拟实现


char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);

	char* s1;//s1维护str1
	char* s2;//s2维护str2
	char* cp = str1;//cp用来记录比较开始的位置

	if (*str2 == '\0')//特殊情况
		return str1;

	while (*cp)
	{
		s1 = cp;
		s2 = str2;

		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)//其实*s1='\0'且*s2!='\0'时已经没有比较下去的必要了
			//*s1==*s2就让两个维护指针分别+1;不等就让cp+1,s1和s2分别重置		
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')//*s2=='\0'说明找到了
		{
			return cp;
		}
		cp++;
	}

	return NULL;
}

应用KMP算法的strstr


void get_next(char* str, int* next)
{
	int i, k;
	i = 0;
	k = -1;
	next[0] = -1;//这个值没用;或者说是为了使i增加而j不增加
	int len = strlen(str);
	while (i < len - 1)//next数组最大下标是字符串长度减1,数组长度和字符串长度相同
	{
		if (k == -1 || *(str + i) == *(str + k))
		{
			++i;
			++k;
			next[i] = k;
		}
		else
			k = next[k];
	}

	//测试打印next
	int z;
	printf("next:");
	for (z = 0; z < len; z++)
	{
		printf("%d ", next[z]);
	}
	printf("\n");
}

int Index_KMP(char* str1, char* str2, int pos)
{
	int i = pos;
	int j = 0;
	int next[255];
	get_next(str2, next);
	int len1 = strlen(str1);
	int len2 = strlen(str2);
	int count = 0;
	while (i < len1 && j < len2)//i从0到10(len1=11),共11次,但是考虑到走else的回溯,单字符查找一共循环22次
	{
		count++;
		if (j == -1 || *(str1 + i) == *(str2 + j))//先判断,再把下标加1
		{
			++i;
			++j;
		}
		else
		{
			j = next[j];
		}
	}
	printf("i=%d\n", i);
	printf("j=%d\n", j);
	printf("count=%d\n", count);//是存在回溯的,那么这个函数的时间复杂度还是O(m)吗?
	//if ((len2!=1) && (j >=(len2-1)))//有缺陷,对于len2=1的情况无法处理
	if (j >= (len2 - 1))//单字符查找情形,while结束时j=0,而len2-1也=0,故不能作为找到了的标志
		//对于单字符查找以外的情形,len2-1一定大于0,len2-1代表的就是目标串最后一个字符的下标,既然j
		//到达了这个位置,就说明完全匹配了
		return i - len2;//由于字符串长度与数组下标的差异造成len2=1时
	else
		return 0;
}
int main()
{
	char* str1 = "hello underworld!";
	char* str2 = "under";

	printf("%s\n", my_strstr(str1, str2));
	printf("%s\n", *(str1+Index_KMP(str1, str2, 0)));

	return 0;
}

strncpy

比strcpy多一个参数,描述拷贝的字节数,如果多于str2的长度,则会补0


int main()
{
	char arr1[20] = "abcdefghi";
	char arr2[] = "xxxx";

	//strncpy(arr1, arr2, 6);//从arr2拷贝6个字符给arr1?如果arr2长度不够,则补0
	//strncpy(arr1, arr2, 3);//长度不够不拷贝\0
	//strncpy(arr1, arr2, 4);
	strncpy(arr1, arr2, 5);

	printf("%s\n", arr1);
	return 0;
}

strncat

比strcat多一个参数,最多只拷贝完整的str2(包括\0)


int main()
{
	char arr1[20] = "abc\0xxxxxxx";
	char arr2[] = "def";

	//strncat(arr1, arr2, 6);//在arr1后面接上arr2的六个字符?最多只接arr2这么长的字符串,包括\0
	//strncat(arr1, arr2, 3);//自己会加上\0
	strncat(arr1, arr2, 2);

	printf("%s\n", arr1);
	return 0;
}

strncmp

比strcmp多一个参数,描述比较的字节数


int main()
{
	char arr1[] = "abcdew";
	char arr2[] = "abcdeqj";

	printf("%d\n",strncmp(arr1, arr2, 5));
	printf("%d\n",strncmp(arr1, arr2, 6));

	return 0;
}

strtok

字符串分割函数,接收两个char*参数,第一个是要被分割的字符串,第二个是分割符,分割符顺序不重要;第一个参数不为NULL时,返回分割的第一段;第一个参数为NULL,将从上个位置开始查找下一段


int main()
{
	char arr1[] = "cjh@scu.edu";
	char arr2[100] = { 0 };//保存临时数据
	char sep[] = "@.";
	char* ret = NULL;//接收strtok的返回值
	strcpy(arr2, arr1);
	for (ret = strtok(arr2, sep); ret != NULL; ret = strtok(NULL, sep))
	{
		printf("%s\n", ret);
	}

	return 0;
}

int main()
{
	char str[] = "- This, a sample string.";
	char* pch;
	printf("Splitting string \"%s\" into tokens:\n", str);
	pch = strtok(str, ", .-");//分隔标记的位置不重要
	while (pch != NULL)
	{
		printf("%s\n", pch);
		pch = strtok(NULL, " ,.-");//注意这里有空格
	}
	return 0;
}

memcpy

接收三个参数,第一个是char的目标位置,第二个是被拷贝的char的数据源,最后一个是size_t的拷贝字节数。注意标准未定义把自己的内容拷贝被自己的结果。

memcpy模拟实现


void* my_memcpy(void* dest, void* class="lazy" data-src, size_t count)
{
	void* ret = dest;
	assert(dest && class="lazy" data-src);

	while (count--)
	{
		*(char*)dest = *(char*)class="lazy" data-src;
		dest = (char*)dest + 1;
		class="lazy" data-src = (char*)class="lazy" data-src + 1;
	}
	//printf("%d\n", count);//count=-1
	return ret;
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };

	my_memcpy(arr2, arr1, 10 * sizeof(int));

	int i;
	for (i = 0; i < 20; i++)
	{
		printf("%d ", arr2[i]);
	}

	return 0;

memmove

此函数原型和memcpy一样,包含额memcpy的功能,且可以处理把自己的内容拷贝给自己的情景


#include <stdio.h>
#include <string.h>
int main()
{
	char str[] = "memmove can be very useful......";
	printf("%c\n", *(str + 15));
	printf("%c\n", *(str + 20));

	memmove(str + 20, str + 15, 11);//注意memmove和memcpy不会遇到\0停下来,什么时候停取决于第三个参数
	puts(str);
	return 0;
}

memmove模拟实现


void* my_memmove(void* dest, void* class="lazy" data-src, size_t count)//关键在于拷贝之前先判断是否会出现overlap
{
	void* ret = dest;
	if (dest <= class="lazy" data-src || (char*)dest >= ((char*)class="lazy" data-src + count))
	{
		while (count--)
		{
			*(char*)dest = *(char*)class="lazy" data-src;
			dest = (char*)dest + 1;
			class="lazy" data-src = (char*)class="lazy" data-src + 1;
		}
	}
	else
	{
		dest = (char*)dest + count - 1;
		class="lazy" data-src = (char*)class="lazy" data-src + count - 1;
		while (count--)
		{
			*(char*)dest = *(char*)class="lazy" data-src;
			dest = (char*)dest - 1;
			class="lazy" data-src = (char*)class="lazy" data-src - 1;
		}
	}
	return ret;
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

	my_memmove(arr + 2, arr, 4 * sizeof(int));//1 2 1 2 3 4 7 8 9 10  
	//my_memcpy(arr + 2, arr, 4 * sizeof(int));//1 2 1 2 1 2 7 8 9 10

	int i;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

memcmp

接收三个参数,前两个是void*型,指向被比较的两块内容,最后一个size_t的参数表示要比较多少字节


#include <stdio.h>
#include <string.h>
int main()
{
	char buffer1[] = "DWgaOtP12df0";
	char buffer2[] = "DWGAOTP12DF0";
	int n;
	n = memcmp(buffer1, buffer2, sizeof(buffer1));
	if (n > 0) printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
	else if (n < 0) printf("'%s' is less than '%s'.\n", buffer1, buffer2);
	else printf("'%s' is the same as '%s'.\n", buffer1, buffer2);
	return 0;
}

字符分类函数

函数 如果他的参数符合下列条件就返回真

  • iscntrl 任何控制字符
  • isspace 空白字符:空格‘ ',换页‘\f',换行'\n',回车‘\r',制表符'\t'或者垂直制表符'\v'
  • isdigit 十进制数字 0~9
  • isxdigit 十六进制数字,包括所有十进制数字,小写字母af,大写字母AF
  • islower 小写字母a~z
  • isupper 大写字母A~Z
  • isalpha 字母az或AZ
  • isalnum 字母或者数字,az,AZ,0~9
  • ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
  • isgraph 任何图形字符
  • isprint 任何可打印字符,包括图形字符和空白字符

字符串换函数

  • tolower()
  • toupper()

#include <stdio.h>
int main ()
{
  int i=0;
  char str[]="Test String.\n";
  char c;
  while (str[i])
 {
    c=str[i];
    if (isupper(c)) 
        c=tolower(c);
    putchar (c);
    i++;
 }
  return 0; }

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C语言的字符串函数,内存函数笔记详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C语言字符串函数与内存函数怎么用

这篇“C语言字符串函数与内存函数怎么用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C语言字符串函数与内存函数怎么用”文章吧
2023-06-30

C语言字符串函数和内存函数怎么使用

本文小编为大家详细介绍“C语言字符串函数和内存函数怎么使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“C语言字符串函数和内存函数怎么使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。字符串函数长度不受限制的字
2023-06-30

深入了解C语言中的字符串和内存函数

本文主要带大家来学习一些常用的库函数。有了这些库函数,我们可以更加方便地操作字符串和内存,从而提升我们的编码效率。话不多说,我们开始吧
2022-11-13

C语言中字符函数和字符串函数介绍

本篇内容介绍了“C语言中字符函数和字符串函数介绍”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!目录前言求字符串长度strlen介绍strle
2023-06-20

C语言的字符函数和字符串函数怎么用

这篇文章主要讲解了“C语言的字符函数和字符串函数怎么用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C语言的字符函数和字符串函数怎么用”吧!一、字符&字符串函数1.strlen--求字符串长
2023-06-26

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录