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

目录
  • strlen
    • strlen模拟实现
  • strcpy
    • strcpy的模拟实现
  • strcat
    • strcat的模拟实现
  • strcmp
    • strcmp模拟实现
  • strstr
    • strstr模拟实现
  • strncpy
  • strncat
  • strncmp
  • strtok
  • memcpy
    • memcpy模拟实现
  • memmove
    • memmove模拟实现
  • memcmp
  • 字符分类函数
  • 字符串换函数
  • 总结

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* src)
{
	assert(dest && src);
	char* ret = dest;
	while (*dest++ = *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* src)
{
	char* ret = dest;
	assert(dest && src);
	while (*dest)//让dest到达str1的\0位置
	{
		dest++;
	}
	while (*dest++ = *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* src, size_t count)
{
	void* ret = dest;
	assert(dest && src);

	while (count--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)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* src, size_t count)//关键在于拷贝之前先判断是否会出现overlap
{
	void* ret = dest;
	if (dest <= src || (char*)dest >= ((char*)src + count))
	{
		while (count--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		dest = (char*)dest + count - 1;
		src = (char*)src + count - 1;
		while (count--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest - 1;
			src = (char*)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; }

总结

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

(0)

相关推荐

  • C语言字符函数与字符串函数详解

    目录 本章重点 前言 1.strlen函数 注意点1 注意点2 2.strcpy 注意点1: 注意点2: 注意点3: 注意点4: 总结 本章重点 重点介绍处理字符和字符串的库函数的使用和注意事项 1.求字符串长度 strlen 2.长度不受限制的字符串函数 strcpy ,strcat, strcmp 3.长度受限制的字符串函数 strncpy,strncat ,strncmp 4.字符串查找 strstr,strtok 5.错误信息报告 strerror 6.字符操作 7.内存操作函数 mem

  • C语言实现返回字符串函数的四种方法

    前言 C语言返回字符串函数共有四种方式,分别如下: 使用堆空间,返回申请的堆地址,注意释放 函数参数传递指针,返回该指针 返回函数内定义的静态变量(共享) 返回全局变量 下面来看看详细的介绍 其实就是要返回一个有效的指针,尾部变量退出后就无效了. 使用分配的内存,地址是有效 char *fun() { char* s = (char*)calloc(100, sizeof(char*) ); if (s) strcpy ( s , "abc " ); return s; } 但这种方式

  • 详解c语言中的 strcpy和strncpy字符串函数使用

    strcpy 和strcnpy函数--字符串复制函数. 1.strcpy函数 函数原型:char *strcpy(char *dst,char const *src)            必须保证dst字符的空间足以保存src字符,否则多余的字符仍然被复制,覆盖原先存储在数组后面的内存空间的数值,strcpy无法判断这个问题因为他无法判断字符数组的长度. #include <stdio.h> #include<string.h> int main() { char message

  • C语言实现字符串操作函数的实例

    C语言实现字符串操作函数的实例 在编写程序的过程中,我们经常使用到一些字符串函数,例如求字符串长度,拷贝字符串--,这些函数都在C标准库中存在,我们可以直接使用.但我们还需要掌握这些函数的实现方法,今天来看看一些常用的字符串操作函数的实现方法. 1.strlen strlen是用来求字符串长度的函数,字符串长度就是它所包含的字符个数. 今天给大家介绍三种实现strlen函数的方法 (1)定义一个计数器count //方式一:定义一个计数器 size_t my_strlen(const char

  • C语言中“不受限制”的字符串函数总结

    "不受限制的"字符串函数 按<C和指针>中所说,那些常用的字符串函数都是"不是限制的",就是说它们只能通过寻找字符串末尾的NULL来判断字符串的长度. strlen strlen函数用于求解字符串长度,其返回类型为unsigned int(即size_t).strlen函数从起点开始,往后计数,遇到'\0'停止. 值得注意的是:strlen函数的返回类型.看如下代码: #include<string.h> #include<iostre

  • C语言字符串函数介绍与模拟实现详解

    目录 2. strcpy(复制字符串) 2.1 strncpy函数 2.2 模拟实现strcpy 3. strcat (追加字符) 3.1 strncat 函数 3.2 模拟实现strcat 4. strcmp(比较两个字符串内容) 4.1 strncmp函数 4.2 模拟实现strcmp 5. strstr (返回str1出现在str2位置处第一次的指针) 5.1 模拟实现strstr 6. strtok(分割字符串) 总结 1. strlen(求字符串长度) 这个函数就是求一个字符串的长度.

  • C语言中关于动态内存分配的详解

    目录 一.malloc 与free函数 二.calloc 三.realloc 四.常见的动态内存的错误 [C语言]动态内存分配 本期,我们将讲解malloc.calloc.realloc以及free函数. 这是个动态内存分配函数的头文件都是 <stdlib.h>. c语言中动态分配内存的函数,可能有些初学c语言的人不免要问了:我们为什么要通过函数来实现动态分配内存呢? 首先让我们熟悉一下计算机的内存吧!在计算机的系统中大致有这四个内存区域: 1)栈:在栈里面储存一些我们定义的局部变量以及形参(

  • C语言 以字符串的形式读写文件详解及示例代码

    fgetc() 和 fputc() 函数每次只能读写一个字符,速度较慢:实际开发中往往是每次读写一个字符串或者一个数据块,这样能明显提高效率. 读字符串函数fgets fgets() 函数用来从指定的文件中读取一个字符串,并保存到字符数组中,它的原型为: char *fgets ( char *str, int n, FILE *fp ); str 为字符数组,n 为要读取的字符数目,fp 为文件指针. 返回值:读取成功时返回字符数组首地址,也即 str:读取失败时返回 NULL:如果开始读取时

  • c语言重要的字符串与内存函数

    目录 一.字符串函数 1. 求字符串长度的strlen 2.比较字符串大小的strcmp 3.复制字符串的strcpy 4.追加字符串的strcat 5.查找字符串函数的strstr 二.内存函数 1.复制 memcpy,memmove 2.比较 memcmp 一.字符串函数 1. 求字符串长度的strlen size_t strlen ( const char * str ); 字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0'

  • C语言详解如何应用模拟字符串和内存函数

    目录 1.strlen 求字符串长度 使用案例: 1.计数法 2.不创建临时变量计数器-递归 3.指针-指针的方式 2.长度不受限制的字符串函数 1.strcpy 使用案例: 模拟实现: 2.strcat 使用案例: 模拟实现: 3.strcmp-比较字符串首字母的大小 使用案例: 模拟实现: 3.长度受限制的字符串函数  1.strncpy 使用案例: 2.strncat  使用案例: 3.strncmp 使用案例: 4.strstr-找子串  使用案例: 模拟实现: 5.strtok 用法:

  • C语言字符串函数,字符函数,内存函数使用及模拟实现

    目录 求字符串长度 strlen 长度不受限制的字符串函数 strcpy strcat strcmp 长度受限制的字符串函数 strncpy strncat strncmp 字符串查找函数 strstr strtok strerror 字符函数 字符分类函数 字符转换函数 内存操作函数 memcpy memmove memcmp memset 求字符串长度 strlen 函数功能 字符串长度,求一个字符串中字符的个数(不包含’\0’). 函数参数: size_t strlen( const ch

  • C语言实现字符串转浮点函数的示例

      字符串不仅可以转换为整数,也可以转换为浮点数,字符串转浮点数函数原型如下: float __cdecl __mingw_strtof (const char * __restrict__, char ** __restrict__); double __cdecl __mingw_strtod (const char * __restrict__, char ** __restrict__);   strtof函数返回值是一个单精度浮点数,strtod返回值是一个双精度浮点数.   首先来看

  • C语言 module_init函数与initcall案例详解

    module_init这个函数对做驱动的人来说肯定很熟悉,这篇文章用来跟一下这个函数的实现. 在include/linux/init.h里面有module_init的定义,自然,因为一个module可以在内核启动时自动加载进内核,也可以由我们手动在需要时加载进内核,基于这种场景,内核使用了MODULE这个宏,见代码: #ifndef MODULE #ifndef __ASSEMBLY__ ... #define __define_initcall(level,fn,id) \ static in

  • Python中关于元组 集合 字符串 函数 异常处理的全面详解

    目录 元组 集合 字符串 1.字符串的驻留机制 2.常用操作 函数 1.函数的优点: 2.函数的创建:def 函数名([输入参数]) 3.函数的参数传递: 4.函数的返回值: 5.函数的参数定义: 6.变量的作用区域 7.递归函数:函数体内套用该函数本身 8.将函数存储在模块中 9.函数编写指南: Bug 1.Bug常见类型 2.常见异常类型 3.python异常处理机制 pycharm开发环境的调试 编程思想 (1)两种编程思想 (2)类和对象的创建 元组 元组是不可变序列 多任务环境下,同时

  • C语言字符函数isalnum()和iscntrl()详解

      isalnum() 函数用于检查所传的字符是否是字母或者十进制数字.它的函数原型如下: _CRTIMP int __cdecl isalnum(int _C);   返回值为非零(真)表示参数c是字母或者十进制数字,返回值为零(假)表示参数c既不是十进制数字,也不是字母.   下面通过一个简单的例子来演示它的用法. #include <stdio.h> #include <ctype.h> int main() { int var1 = 'a'; int var2 = '8';

  • C语言字符串压缩之ZSTD算法详解

    目录 前言 一.zstd压缩与解压 二.ZSTD压缩与解压性能探索 三.zstd的高级用法 四.总结 前言 最近项目上有大量的字符串数据需要存储到内存,并且需要储存至一定时间,于是自然而然的想到了使用字符串压缩算法对“源串”进行压缩存储.由此触发了对一些优秀压缩算法的调研. 字符串压缩,我们通常的需求有几个,一是高压缩率,二是压缩速率高,三是解压速率高.不过高压缩率与高压缩速率是鱼和熊掌的关系,不可皆得,优秀的算法一般也是采用压缩率与性能折中的方案.从压缩率.压缩速率.解压速率考虑,zstd与l

随机推荐