C语言进阶:字符串与内存函数

目录

字符串函数

求字符串长度函数——strlen

函数介绍

函数用法

模拟实现

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

字符串拷贝函数——strcpy

函数介绍

函数用法

模拟实现

字符串追加函数——strcat

函数介绍

函数用法

模拟实现

字符串比较函数——strcmp

函数介绍

函数用法

模拟实现

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

字符串拷贝函数——strncpy

函数介绍

函数用法

模拟实现

字符串追加函数——strncat

函数介绍

函数用法

模拟实现

字符串比较函数——strncmp

函数介绍

函数用法

字符串查找函数——strstr

函数介绍

函数用法

模拟实现

字符串分割函数——strtok

函数介绍

函数用法

字符串报错函数——sterror

函数介绍

函数用法

内存函数

内存拷贝函数——memcpy

函数介绍

函数用法

模拟实现

内存移动函数——memmove

函数介绍

函数用法

模拟实现

内存比较函数——memcmp

函数介绍

函数用法

内存初始化函数——memset

函数介绍

函数用法


字符串函数

求字符串长度函数——strlen

函数介绍

size_t strlen(const char *str)

C语言进阶:字符串与内存函数_第1张图片

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

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

·主要函数的返回值为size_t,是无符号的(易错).

函数用法

#include 
#include
int main()
{
	//1.
	char arr1[] = "abcdef";
	int len = strlen(arr1);
	printf("%d\n", len);//6

	//2.
	char arr2[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
	printf("%d\n", strlen(arr2));//随机值

	//3.
	char arr3[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
	printf("%d\n", strlen(arr3[0]));//err

	//4.打印hehe
	const char *str1 = "abcdef";
	const char *str2 = "bbb";
	if (strlen(str2) - strlen(str1) > 0)
	{
		printf("hehe\n");
	}
	else
	{
		printf("haha\n");
	}

	return 0;
}

1.参数指向的字符串是以'\0'结束,满足strlen的要求

2.参数指向的字符串不是以'\0'结束,但是由于strlen的倔脾气必须要找到'\0'才肯结束,这里就会一直往后找,所以打印的就是随机值

3.传的参数根本就不是地址,strlen以为传进来的a的ascii码值97就是地址,所以这里会发生错误

4.由于stlen的返回值是size_t类型,也就是无符号类型,这里strlen(str2)的值为3,strlen(str1)的值为6,strlen(str2)-strlen(str1)的值为-3,但是由于strlen的返回值是size_t类型,我们知道

无符号数里的-3其实是一个很大的值(大于0的数),因此这里最后会打印hehe

上面说的strlen函数的一些小细节希望大家能够记住哦,细节决定成败!!!

模拟实现

#include
//模拟strlen 计数器的方式
int My_Strlen(const char *p)
{
	int count = 0;
	while (*p)
	{
		p++;
		count++;
	}
	return count;

}
//模拟strlen 不创建临时变量计数器
int My_Strlen(const char *p)
{
	if (*p == '\0')
	{
		return 0;
	}
	else
	{
		return 1 + My_Strlen(p + 1);
	}
}

//模拟strlen 指针-指针
int My_Strlen(char *p)
{
	char *src = p;
	while (*p)
	{
		p++;
	}
	return p - src;
}

int main()
{
	char arr[10] = "abcdef";
	int len = My_Strlen(arr);
	printf("%d\n", len);
	return 0;
}

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

字符串函数分为长度不受限制的字符串函数与长度受限制的字符串函数。长度受限制的字符串函数相较于长度不受限制的字符串函数会安全一些。下面我们来介绍长度不受限制的字符串函数吧。

字符串拷贝函数——strcpy

函数介绍

char *strcpy( char *strDestination, const char *strSource );

·源字符串必须以'\0'结束

·会将源字符串的'\0'拷贝到目标空间

·目标空间必须足够大,以确保能存放源字符串 

·目标空间必须可修改

函数用法

#include 
#include
int main()
{
	//1.
	char arr1[10] = "xxxxxx";
	char arr2[] = "ac";
	printf("%s\n", strcpy(arr1, arr2));//ac

	//2.
	char arr3[] = { 'a', 'b', 'c' };
	printf("%s\n", strcpy(arr1, arr3));//err

	//3.
	char arr4[] = "abcccccccceeeeeeaaaa";
	printf("%s\n", strlen(arr1, arr4));//目标空间不足以存放源字符串

	//4.
	const char arr[10] = "xxx";
	char arr5[] = "aaa";
	printf("%s\n", strcpy(arr, arr5));//目标空间不可修改
	return 0;
}

1.源字符串是以'\0'结尾,目标空间可修改,目标空间足够大,满足strcpy的要求,所以这里会将源字符串的内容包含('\0')一同拷贝到目标空间

2.源字符串不是以'\0'结尾,则strcpy就会向后一直访问到非法内存

3.目标空间不足以存放源字符串的内容

4.目标空间不可修改

需要注意的是我们在写代码时,应当避免出现后面三种情况

模拟实现

#include
#include
char* My_Strcpy(char *dest, const char* src)
{
	assert(dest&&src);
	char *ret = dest;
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "okk";
	printf("%s\n", My_Strcpy(arr1, arr2));
	return 0;
}

字符串追加函数——strcat

函数介绍

char *strcat( char *strDestination, const char *strSource );

·源字符串必须以'\0'结束

·目标空间有足够的大,能容纳下源字符串的内容

·目标空间可修改 

函数用法

#include
#include
int main()
{
	//1.
	char arr[20] = "abcdef";
	char arr1[] = "okk";
	strcat(arr, arr1);
	printf("%s\n", arr);//abcdefokk

	//2.
	char arr2[] = { 'a', 'b', 'c' };
	strcat(arr, arr2);
	printf("%s\n", arr);
	
	//3.
	char arr3[10] = "abcdefgh";
	char arr4[] = "okkkk";
	strcat(arr3, arr4);
	printf("%s\n", arr3);

	//4.
	const char arr5[20] = "xxxxx";
	char arr6[] = "okkk";
	strcat(arr5, arr6);
	printf("%s\n", arr5);
	return 0;
}

1.源字符串以'\0'结束,并且目标空间足够大,能容纳下源字符串内容,目标空间可修改,符合strcat的要求所以最后打印的结果是abcdefokk。

2.源字符串没有以'\0'结束,因为strcat和strlen一样,必须要找到'\0'才肯停下来,所以这里会非法访问空间从而会发生错误。

3.目标空间不够大,不能够容纳源字符串的内容。

4.目标空间不可修改,同样不行。

以上就是strcat函数使用起来需要注意的细节了

模拟实现

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

int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "okk";
	printf("%s\n", My_Stract(arr1, arr2));
	return 0;
}

字符串比较函数——strcmp

函数介绍

int strcmp( const char *string1, const char *string2 );

C语言进阶:字符串与内存函数_第2张图片

二个字符串都必须以'\0'作为字符串的结尾,否则会发生越界访问

·标准规定:

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

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

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

函数用法

#include
#include
int main()
{
	char arr[] = "abcdef";
	char arr1[] = "abb";
	char arr2[] = "abcdef";
	char arr3[] = "abe";
	printf("%d\n", strcmp(arr, arr1));//1
	printf("%d\n", strcmp(arr, arr2));//0
	printf("%d\n", strcmp(arr, arr3));//-1

	return 0;
}

这里的字符串都以'\0'作结束,所以三次依次比较的结果是1,0,-1。作者用的编译器是VS2013,MSDN上面也说了当第一个字符串小于第二个字符串时,返回一个小于0的数(并不一定是-1)

当第一个字符串当于第二个字符串时,返回一个大于0的数(并不一定是1)

模拟实现

int My_Strcmp(const char *dest, const char*src)
{
	assert(dest&&src);
	while(*dest==*src)
	{
		if (*dest=='\0')
		{
			return 0;
		}
		dest++;
		src++;
		
	}
	return *dest - *src;
}

int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "abb";
	int len = My_Strcmp(arr1, arr2);
	printf("%d\n", len);
	if (len > 0)
	{
		printf(">\n");
	}
	else if (len == 0)
	{
		printf("=\n");
	}
	else
	{
		printf("<\n");
	}
	return 0;
}

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

字符串拷贝函数——strncpy

函数介绍

char *strncpy( char *strDest, const char *strSource, size_t count );

C语言进阶:字符串与内存函数_第3张图片

·目标字符串空间够大,并且能修改

·如果源字符串的长度小于count,则拷完源字符串之后,在目标的后边追加\0,直到count个 

函数用法

#include
#include
int main()
{
	char arr[20] = "abcdef";
	char arr1[] = "obj";
	strncpy(arr, arr1, 5);
	printf("%s\n", arr);
	return 0;
}

C语言进阶:字符串与内存函数_第4张图片

模拟实现

//模拟实现strncpy函数
char *My_Strncpy(char *dest, const char*src, size_t count)
{
	assert(dest&&src);
	char* ret = dest;
	//count是无符号类型,当count小于源字符串长度时我们需要特别注意
	while (count && (*dest = *src))
	{
		count--;
        dest++;
        src++;
	}
	while (count)
	{
		*dest++ = '\0';
		count--;
	}
	return ret;
}
int main()
{
	char arr[20] = "abcdef";
	char arr1[] = "obj";
	My_Strncpy(arr, arr1, 2);
	printf("%s\n", arr);
	return 0;
}

字符串追加函数——strncat

函数介绍

char *strncat( char *strDest, const char *strSource, size_t count );

C语言进阶:字符串与内存函数_第5张图片

函数用法


int main()
{
	char arr[20] = "abc\0xxxxxxx";
	char arr1[] = "def";
	strncat(arr, arr1, 5);
	printf("%s\n", arr);
	return 0;
}

C语言进阶:字符串与内存函数_第6张图片

 源字符串应以'\0'结尾,在目标字符串的\0后面追加count个源字符串的字符,结尾会默认添加\0,若count超于源字符串的长度时,追加完源字符串之后便不会再追加其他内容。

模拟实现

#include
//模拟实现strncat
char *My_Strncat(char *dest, const char *src, size_t count)
{
	assert(dest&&src);
	char *ret = dest;//拿一个指针记录dest起始位置
	//判断dest是否已经指向'\0'
	while (*dest)
	{
		dest++;
	}
	while (count && (*dest++ = *src++))
	{
		count--;
	}
	//若count>源字符串长度,则不再增加,若小于则在后面主动添加一个'\0'
	if (count == 0)
	{
		*dest = '\0';
	}
	return ret;
}
int main()
{
	char arr[20] = "abc\0xxxxxxx";
	char arr1[] = "def";
	My_Strncat(arr, arr1, 2);
	printf("%s\n", arr);
	return 0;
}

字符串比较函数——strncmp

函数介绍

int strncmp( const char *string1, const char *string2, size_t count );

C语言进阶:字符串与内存函数_第7张图片

·比较两个字符串的前count个字符,并返回相关的数值。

函数用法

int main()
{
	char arr[] = "abcdef";
	char arr1[] = "abbd";
	int len = strncmp(arr, arr1, 3);
	printf("%d\n",len);
	return 0;
}

字符串查找函数——strstr

函数介绍

char *strstr( const char *string, const char *strCharSet );

C语言进阶:字符串与内存函数_第8张图片

查找子字符串是否在目标字符串中,若存在则返回子字符串在目标字符串首次出现的位置,若不存在则返回空指针。

函数用法


int main()
{
	char arr[20] = "abdabcd ef";
	char arr1[] = "abcd";
	char arr2[] = "aaac";
	char *ret = strstr(arr, arr1);
	char *len = strstr(arr, arr2);
	printf("%s\n", ret);
	printf("%s\n", len);
	return 0;
}

C语言进阶:字符串与内存函数_第9张图片

模拟实现

//模拟实现strstr字符串查找函数
char *My_Strstr(const char *dest, const char *src)
{
	assert(dest&&src);
	char *s1;
	char *s2;
	char *cp = dest;
	//特殊情况
	if (*src == '\0')
	{
		return dest;
	}
	while (*cp)
	{
		s1 = cp;
		s2 = src;
		while (*s1&&*s2&&*s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cp;
		}
		cp++;
	}
	//找不到
	return NULL;
	
}
int main()
{
	char arr1[] = "i am a good student, hehe student";
	char arr2[] = "student";
	//查找arr1中arr第一次出现的位置
	char *ret = My_Strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		printf("%s\n",ret);
	}
	return 0;
}

字符串分割函数——strtok

函数介绍

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

C语言进阶:字符串与内存函数_第10张图片

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

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

·strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针

·strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置

·strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记

·如果字符串中不存在更多的标记,则返回NULL指针

函数用法

int main()
{
	char arr[] = "www.yakjafg.com";
	printf("%s\n", strtok(arr,"."));
	printf("%s\n", strtok(NULL, "."));
	printf("%s\n", strtok(NULL, "."));

	return 0;
}

C语言进阶:字符串与内存函数_第11张图片


int main()
{
	char arr[30] = "abc@jkajn-adf@nck";
	char *ret = "@-";
	char *str = NULL;
	for (str = strtok(arr, ret); str != NULL; str = strtok(NULL, ret))
	{
		printf("%s\n", str);
	}
	return 0;
}

 C语言进阶:字符串与内存函数_第12张图片

字符串报错函数——sterror

函数介绍

char *strerror( int errnum );

C语言进阶:字符串与内存函数_第13张图片

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

·当程序发生错误时,程序会自动将错误码存入内置全局变量errno中,此时我们调用strerror函数即可获得此次错误的报错信息

·更直接的报错函数perror,优点简单方便假如自定义信息,缺点就是必须打印错误信息

函数用法

int main()
{
	FILE *pFile;
	pFile = fopen("unexist.ent", "r");
	if (pFile == NULL)
	{
		printf("Error opening file unexist.ent:%s\n", strerror(errno));
		return 0;
	}
}

内存函数

内存拷贝函数——memcpy

函数介绍

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

C语言进阶:字符串与内存函数_第14张图片

·函数memcpy从src的位置开始向后复制num个字节的数据到dest的内存位置

·这个函数在遇到'\0'的时候并不会停下来

·如果src和dest有任何的重叠,复制的结果都是未定义的

·memcpy只要完成了不重叠的内存拷贝就算完成了它的任务

函数用法

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

C语言进阶:字符串与内存函数_第15张图片

模拟实现

void * My_Memcpy(void *dest, const void *src, size_t num)
{
	void *ret = dest;
	assert(dest&&src);
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	My_Memcpy(arr + 4, arr, 16);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

内存移动函数——memmove

函数介绍

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

C语言进阶:字符串与内存函数_第16张图片

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

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

函数用法

int main()
{
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	memmove(arr+2, arr, 16);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);

	}
	return 0;
}

C语言进阶:字符串与内存函数_第17张图片

模拟实现

C语言进阶:字符串与内存函数_第18张图片

void * My_Memmove(void *dest, const void *src,size_t count)
{
	assert(dest&&src);
	void *ret = dest;
	//dest在src的前面
	if (dest < src)
	{
		while (count--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	//dest在src的后面
	else
	{
		while (count--)
		{
			*((char*)dest + count) = *((char*)src + count);

		}
	}
	return ret;
}
int main()
{
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	My_Memmove(arr+2, arr, 16);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);

	}
	return 0;
}

内存比较函数——memcmp

函数介绍

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

C语言进阶:字符串与内存函数_第19张图片

·比较buf1和buf2开始的count个字节

·buf1小于buf2的话,返回小于0的数

·buf1等于buf2的话,返回0

·buf1大于buf2的话,返回大于0的数 

函数用法

int main()
{
	int arr[] = { 1, 2, 3, 5, 6 };
	int arr1[] = { 1, 2, 3, 4, 3 };
	int len = memcmp(arr, arr1, 16);
	printf("%d\n", len);
	return 0;
}

C语言进阶:字符串与内存函数_第20张图片

这里我们比较了arr与arr1里面16个字节的内容,很明显arr是大于arr1的,返回了大于0的数,但并不是说返回大于0的数就一定要是1。当arr小于arr1时,返回小于0的数,也并不是说返回小于0的数就一定要是-1。 

内存初始化函数——memset

函数介绍

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

C语言进阶:字符串与内存函数_第21张图片

将目标空间前count个字节的数据初始化为整型c 

函数用法


int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 ,10};
	memset(arr, 5, 16);//将arr数组内前16个字节的数据都初始化为5
	return 0;
}

C语言进阶:字符串与内存函数_第22张图片

以上就是字符串与内存函数的所有内容了,码字不易如果觉得该内容对你有帮助的话,可以给作者点赞关注一波哦,你的点赞与关注就是对作者最大的支持。

你可能感兴趣的:(C语言,c语言)