字符(串)函数和内存操作函数知识点总结(超全)

一.字符串函数

1.strlen

strlen函数是求字符串长度的函数,里面传的是地址,函数返回的是‘\0’前面出现的字符的个数,是无符号整形(注意:如果返回值是一个负数,会自动将其转换成正数,也就是将负数的补码直接看做原码输出),例如此代码:

#include<stdio.h>
#include<string.h>
int main()
{
    
    
	if ((strlen("abc") - strlen("abcdef")) > 0)
	{
    
    
		printf("大于\n");;
	}
	else
	{
    
    
		printf("小于\n");
	}
	return 0;
}

此代码打印的结果是“大于“。strlen的返回值是size_t,是无符号的,两个无符号数相减还是无符号数,这里把-3的补码当做无符号数来处理
负3的原码:10000000000000000000000000000011
负3的反码:11111111111111111111111111111100
负3的补码:11111111111111111111111111111101
直接将补码看做原码输出,因此是一个很大的数字
strlen函数的使用

#include<stdio.h>
#include<string.h>
int main()
{
    
    
	char arr[] = "abc";
	int len = strlen(arr);
	printf("%d\n", len);
	return 0;
}

strlen函数的模拟实现

计数器方式实现:

int my_strlen(char*str)
{
    
    
	assert(str != NULL);
	int count = 0;
	while (*str != '\0')
	{
    
    
		str++;
		count++;
	}
	return count;
}
int main()
{
    
    
	char arr[] = "abc";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

递归方式实现:

int my_strlen(char*str)
{
    
    
    assert(str != NULL);
	if (*str != '\0')
		return 1 + my_strlen(str + 1);
	else
		return 0;
}
int main()
{
    
    
	char arr[] = "abc";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

指针-指针方式实现:

#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strlen(const char*str)
{
    
    
	assert(str != NULL);
	const char*start = str;
	while (*str)
	{
    
    
		str++;
	}
	return str - start;
}
int main()
{
    
    
	char arr[] = "abc";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

2.strcpy

字符串拷贝函数:
1.源字符串必须有’\0’,且会将’\0’拷贝到目标字符串。
2.目标空间必须足够大且可变。
strcpy函数的使用

int main()
{
    
    
	char arr1[] = "*********";
	char arr2[] = "ni hao";
	strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

strcpy函数的模拟实现

char* my_strcpy(char* dest, const char* src)
{
    
    
	assert(dest && src);
	char*ret = dest;
	while (*dest++ = *src++)//拷贝字符串,包括'\0'
	{
    
    
		;
	}
	return ret;//返回的目标空间的起始地址
}

int main()
{
    
    
	char arr1[20] = "*************";
	char arr2[] = "hello world";

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

3.strcat

strcat函数(字符串追加函数):把源字符串的内容追加到目标空间的后面。
1.源字符串必须以’\0’结束。
2.目标空间必须足够大且可以被修改,同时目标空间里必须也要有\0,因为要从目标空间的’\0’处开始追加。
3.不能自己给自己追加,因为会修改掉’\0’,使得字符串没有终止条件了
strcat函数的使用

int main()
{
    
    
	char arr1[20] = "hello ";//目标空间必须足够大
	char arr2[] = "world";
	strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

strcat函数的模拟实现

char* my_strcat(char*dest, const char*src)
{
    
    
	assert(dest && src);
	char*ret = dest;
	//1. 找到目标空间的\0
	while (*dest)
	{
    
    
		dest++;
	}
	//2. 追加
	while (*dest++ = *src++)
	{
    
    
		;
	}
	return ret;
}

int main()
{
    
    
	char arr1[20] = "hello ";
	char arr2[] = "world";

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

	return 0;
}

4.strcmp

strcmp(字符串比较函数):
不是比较字符串的长度,而是比较字符串中对应字符的ASCII码值,当有一个字符串的某个字符的ASCII码值大于另一个字符串对应字符的ASCII码值时,则该字符串大于另一个字符串,返回一个大于0的数字。
strcmp函数的使用

int main()
{
    
    
	int ret = strcmp("abc", "abcdef");
	printf("%d\n", ret);
	return 0;
	//打印的结果是一个小于0的数字
}

strcmp函数的模拟实现

int my_strcmp(const char*s1, const char*s2)
{
    
    
	assert(s1 && s2);
	while (*s1 == *s2)
	{
    
    
		if (*s1 == '\0')
			return 0;
		s1++;
		s2++;
	}
	return *s1 - *s2;
}

int main()
{
    
    
	int ret = my_strcmp("abq", "abcdef");
	printf("%d\n", ret);
	return 0;
}

5.strncpy

1.和strcpy函数类似,但是strcnpy函数可以拷贝具体的字符个数,以避免strcpy拷贝字符多了而目标空间存不下系统报错。
2.如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

6.strncat

和strcat函数类似,但区别在于strncat函数可以追加具体的字符个数,且追加相应的字符个数后会在后面自动补上’\0’(如果追加的长度多于一个字符串的长度时,会将该字符串全部追加完并且在后面补上’\0’)。

7.strncmp

和strcmp函数相似,但strncmp函数可以比较具体的字符个数。

8.strstr

strstr函数,作用为在一个字符串中寻找另外一个字符串第一次出现的位置,返回的是地址,如果找不到的话,则会返回空指针。
strstr函数的使用

int main()
{
    
    
	char arr1[] = "abcdefgbcd";
	char arr2[] = "bcd";
	char*ret = strstr(arr1, arr2);
	if (ret != NULL)
		printf("%s\n", ret);
	else
		printf("找不到\n");
	return 0;
}

strstr函数的模拟实现

char* my_strstr(const char*s1, const char*s2)
{
    
    
	assert(s1 && s2);
	const char *cp = s1;

	if (*s2 == '\0')
		return (char*)s1;

	while (*cp)
	{
    
    
		const char *p1 = cp;
		const char *p2 = s2;//给p1,p2都加上const让两边类型保持一致
		while ((*p1!='\0') && (*p2!='\0') &&  (*p1 == *p2))
		{
    
    
			p1++;
			p2++;
		}
		if (*p2 == '\0')
		{
    
    
			return (char*)cp;
		}
		cp++;
	}
	return NULL;
}
	
int main()
{
    
    
	char arr1[] = "abcdef";
	char arr2[] = "defq";

	char*ret = my_strstr(arr1, arr2);//在arr1中查找arr2字符串第一次出现的位置
	if (ret != NULL)
		printf("%s\n", ret);
	else
		printf("找不到子串\n");

	return 0;
}

9.strtok

1.strtok函数会在字符串中寻找标记(分隔符),并将这个标记改成’\0’,然后返回起始位置。
2.strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。
3.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回 NULL 指针。
4.从寻找第二个标记开始调用strtok函数时传的第一个参数应该为空指针。

int main()
{
    
    
	char arr[] = "[email protected]";//@. 分割符
	char arr2[30] = {
    
     0 };
	strcpy(arr2, arr);
	char*p = ".@";
	char *ret = NULL;
	for (ret = strtok(arr2, p); ret != NULL; ret = strtok(NULL, p))
	{
    
    
		printf("%s\n", ret);
	}
	return 0;
}

10.strerror

strerror(错误报告函数),当库函数使用时发生错误时,返回错误码,把错误码转换成对应的错误信息,返回错误信息对应字符串的起始地址。

char *strerror( int errnum );

二.字符函数

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

字符转换函数
int tolower ( int c ):转换为小写
int toupper ( int c ):转换为大写

三.内存操作函数

内存操作函数可以用于操作数组

1.memcpy

1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
2.这个函数在遇到 ‘\0’ 的时候并不会停下来。
3.如果source和destination有任何的重叠,复制的结果都是未定义的。
4.

void *memcpy( void *dest, const void *src, size_t count );

此函数在实现的时候,不知道未来会被用来拷贝什么类型的数据,所以此函数返回类型为void;第三个参数为要拷贝的字节个数。
5.用于拷贝两个不相关的内存(没有重叠)。
memcpy函数的使用

int main()
{
    
    
	int arr1[] = {
    
     1, 2, 3, 4, 5, 6 };
	int arr2[10] = {
    
     0 };
	memcpy(arr2, arr1, 16);
	return 0;
}

运行效果:
在这里插入图片描述
memcpy函数的模拟实现

void* my_memcpy(void*dest, const void*src, size_t count)
{
    
    
	void*ret = dest;
	assert(dest && src);

	while (count--)
	{
    
    
		*(char*)dest = *(char*)src;
		++(char*)dest;//((char*)dest)++;
		++(char*)src;//((char*)src)++;
	}
	return ret;
}

2.memmove

memmove函数和memcpy函数类似,参数完全相同,但区别在于memmove函数可以进行重叠拷贝。
例:在这里插入图片描述
memmove函数的模拟实现

void* my_memmove(void* dest, const void*src, size_t count)
{
    
    
	void* ret = dest;
	assert(dest && src);
	if (dest < src)
	{
    
    
		//前->后
		while (count--)
		{
    
    
			*(char*)dest = *(char*)src;
			++(char*)dest;
			++(char*)src;
		}
	}
	else
	{
    
    
		//后->前
		while (count--)
		{
    
    
			*((char*)dest + count) = *((char*)src + count);
		}
	}
	return ret;
}

注意:
标准规定memcpy函数只要能够实现不重叠拷贝就行,但在有些编译器下memcpy函数也可以实现重叠拷贝。即便如此,也建议大家以后在重叠拷贝时用memmove函数,以免在部分编译器环境下达不到预期效果。

3.memcmp

int memcmp( const void *buf1, const void *buf2, size_t count );


memcmp(内存比较函数):用于比较buf1和buf2的前count个字节,具体的返回值如下:在这里插入图片描述
和strcmp的区别:strcmp比较的是字符串,strcmp在比较过程中需要注意是否遇到了’\0’,而memcmp比较的是内存块,可以指定比较的字节数。

4.memset

memset函数用于将指定的某一块内存中的后n个字节的内容全部设置为指定的字符。

void *memset( void *dest, int c, size_t count );

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Mubei1314/article/details/113999106