C语言进阶——常用字符串函数和内存函数

 

目录

一,字符串函数

1.1 strlen()

1.2 strcpy()

1.3 strcat()

1.4 strcmp()

1.5 strstr()

1.6 strtok()

1.7 strerror

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

二,内存函数

2.1 memcpy()

2.2 memmove()

2.3 memcmp()

2.4 memset()


一,字符串函数

1.1 strlen()

size_t strlen (const char* str);

字符串以'\0作为结束标志,strlen函数返回的是在字符串中'\0'前出现的字符个数,不包含'/0',并且参数指向的字符串必须要以'\0'结束,strlen的返回值为size_t,是无符号整数,这个要注意

size_t my_strlen(const char* str)
{
	int count = 0;
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}
void main1()
{
	size_t sz = my_strlen("abc");
	printf("%u\n", sz);
}

1.2 strcpy()

char* strcpy(char* destination, const char* source);

 源字符串必须以'\0'结束,而且拷贝时也会将'\0'拷贝到目标空间,目标空间必须足够大以确保能存放要拷贝的字符串,而且目标空间必须可变,也就是不能是const或常量字符串

下面是使用

void main3()
{
	//char arr1[3] = "";
	//char arr2[] = "hello bit";
	const char* arr1 = "xxxxxxxxxx";
	char arr2[6] = { 'a', 'b', 'c', 'd', 'e' , '\0'};
	strcpy(arr1, arr2);
	printf("%s\n", arr1);
}

 下面是模拟实现和测试

char* my_strcpy1(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest != NULL);
	assert(src != NULL);

	while (*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = *src;//还要将\0拷贝过去
	return ret;
}
//上面的实现有点麻烦,下面的是简化后的,两个的结果相同
char* my_strcpy2(char* dest, const char* src) 
{
	char* ret = dest;
	assert(dest != NULL);
	assert(src != NULL);
	while (*dest++ = *src++) { ; }
	return ret;
}

void main3()
{
	char arr1[20] = "hello world";
	char arr2[] = "xxxxx";
	my_strcpy2(arr1 + 6, arr2);
	printf("%s\n", arr1);
}

1.3 strcat()

char* strcat (char* destination, const char* source);

字符串追加函数。源字符串必须以'\0'结束,目标空间必须足够大并且可修改

char* my_strcat(char*dest, const char *src)
{
	assert(dest && src);

	char* ret = dest;
	//1. 找目标空间中的\0
	while (*dest)
	{
		dest++;
	}
    //2. 开始对\0后的数据进行追加
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}
void main4()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";
	my_strcat(arr1, arr2);
	//my_strcat(arr1, arr1);自己给自己追加,程序直接炸掉
	printf("%s\n", arr1);
}

1.4 strcmp()

int strcmp (const char* str1, const char* str2);

字符串比较函数,其规则如下:

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

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

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

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1 == '\0') return 0;
		str1++;
		str2++;
	}
	return (*str1 - *str2);
}
void main5()
{
	int ret = my_strcmp("bbq", "bcq");
	if (ret > 0) printf(">\n");
	printf("%d\n", ret);
}

1.5 strstr()

char* strstr (const char* str1 ,const char* str2);

这个函数表示从一个字符串中找子字符串,找到了返回原字符串中子字符串第一次出现位置的指针,没找到返回NULL 

char* my_strstr(char *str1, char* str2)
{
	char* cp = str1;
	char* s1 = cp;
	char* s2 = str2;
	if (*str2 == '\0') return str1;
	while (*cp)
	{
		//开始匹配
		s1 = cp; //更新开始匹配的位置
		s2 = str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0') return cp;
		cp++; //一次找没找到
	}
	return NULL; //全部找完了也没没找到
}

void main6()
{
	char arr1[] = "abbbcdef";
	char arr2[] = "bbc";
	char* ret = my_strstr(arr1, arr2);
	if (ret != NULL)
		printf("%s\n", ret);
	else
		printf("找不到\n");
}

1.6 strtok()

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

strtok用得不多,但我们作为学习者还是要了解下用法,下面是strtok得使用规则:

①sep参数是个字符串,里面定义了用作分隔符得字符集合

②第一个参数是一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符得标记

③strtok函数窄带str中得下一个标记,并将其尬舞i欸\0,然后返回一个指向这个标记得指针

④strtok会改变原字符串,所以在使用strtok得时候一般都是在临时拷贝得内容上操作 

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

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

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

有点复杂有点多,直接上代码(strtok了解使用即可,不要求模拟实现)

void main7()
{
	char arr[] = "zpengwei@yeah.net@666#777";
	char copy[30];
	strcpy(copy, arr);

	char sep[] = "@.#";
	char* ret = NULL;
	                                              //有记忆功能
	for (ret = strtok(copy, sep); ret != NULL; ret=strtok(NULL, sep))
	{
		printf("%s\n", ret);
	}
}

1.7 strerror

char* strerror (int errnum);

如果库函数在执行的时候发生了错误,会将一个错误码存放进errno这个变量中,errno是C语言提供的一个全局变量

//打印部分错误码信息
void main12()
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d: %s\n", i, strerror(i)); 
		//将错误码翻译成错误信息,把错误信息字符串的首字母地址传回来
	}
}

 通过具体例子来看待这个函数

void main8()
{
	FILE* pf = fopen("data.txt", "r"); //此时我们的项目路径下没有data.txt这个文件
	if (pf == NULL)
	{
		printf("fopen: %s\n", strerror(errno));
		perror("fopen"); //使用perror和上面打印结果一样
		return 1;
	}
	//读文件
	//...

	//关闭文件
	fclose(pf);
}

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

//strncpy
void main9()
{
	char arr1[20] = "abcdef";
	char arr2[] = "xxx";
	strncpy(arr1, arr2, 5);
}

//strncat
void main10()
{
	char arr1[20] = "abcdef\0yyyyyyyy";
	char arr2[] = "xxxxxxxxx";
	strncat(arr1, arr2, 3);
}

//strncmp
void main11()
{
	char arr1[] = "abcqwertyuiop";
	char arr2[] = "abcdef";
	printf("%d\n", strncmp(arr1, arr2, 4));
}

二,内存函数

2.1 memcpy()

void* memcpy (void* destination, const void* source, size_t num);

 这个函数会从source位置开始复制num个字节的数据到destination的内存位置,并且遇到\0时不会停下来,可以拷贝任意类型的数据,所以将参数类型设定为void*

使用

//将arr1中的内容,拷贝到arr2中,将arr3的内容拷贝到arr4中
void main12()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	memcpy(arr2, arr1, 40);
    //     int*  int*
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		printf("%d ", arr2[i]);
	}

	float arr3[] = { 1.0,2.0,3.0 };
	float arr4[5] = { 0 };
	memcpy(arr4, arr3, 8);
	//    float* float*
	for (i = 0; i < 5; i++)
	{
		printf("%f ", arr2[i]);
	} 
}

 模拟实现,函数拷贝结束后,返回目标空间的起始地址

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

	while (num--)
	{
		//为了使参数的void*支持加减,最好用char*,一个字节一个字节地去拷贝
		*(char*)dest = *(char*)src; 
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}


void main13()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00

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

如果想实现数组内的拷贝,比如下面代码 

void main14()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//             1 2 1 2 3 4 5 8 9 10
	my_memcpy(arr1+2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
}

 我们打算将arr1中的1,2,3,4,5放到3,4,5,6,7的位置上去,但是最后会打印这个

 

 这是因为我们的memcpy是从前面往后面拷贝的,1会覆盖3的位置,2会覆盖4的位置,所以我们再去访问3的位置时最后访问到的还是1,于是造成了上面的情况。

所以memcpy函数是用来处理不重叠的内存拷贝的,如果有重叠的会有专门的函数来解决,就是下面的memmove函数

2.2 memmove()

void* memmove (void* destination, const void* source, size_t num);

和memcoy函数的差别就是memmove函数可以额处理内存重叠情况

void* my_memmove(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);

	if (dest < src) //不重叠的情况
	{
		//前->后
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else            //重叠的情况
	{
		//为了避免重叠问题,从后面往前面拷贝
		while (num--)//20
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}

//将arr1中的3,4,5,6,7换到前面1,2,3,4,5的位置
void main15()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//             3 4 5 6 7 6 7 8 9 10
	my_memmove(arr1, arr1+2, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
}

2.3 memcmp()

int memcmp(const void* ptr1,const void* ptr2, size_T num);

和前面的strcmp函数用法大致相同,memcmp不单单可以比较字符数据

void main16()
{
	int arr1[] = { 1,2,1,4,5,6 };
	int arr2[] = { 1,2,257 };
	int ret = memcmp(arr1, arr2, 10);
	printf("%d\n", ret);
}

2.4 memset()

内存设置函数

void main27()
{
	char arr1[] = "hello bit";
	memset(arr1 + 1, 'x', 4);//以字节为单位设置的
	printf("%s\n", arr1);

	int arr2[10] = { 0 };
	memset(arr2, 1, 40);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值