C进阶 字符串函数+内存函数

字符串函数

1.strlen 函数
用来求解字符串的长度 (必须是字符串以\0 结尾)
头文件 #include<string.h>
用法:
用来计算字符串的长度 字符串是一种特殊的字符数组 以\0结尾 一旦用strlen函数来计算一般的字符数组会出现未定义行为
举例1.求一个字符串的长度(法1)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){

	char arr[] = "abcdef";
	int ret = strlen(arr);

	printf("ret= %d\n",ret);
	system("pause");
	return 0;

}

法2.(函数实现与strlen函数功能一致)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>


int Strlen(char* arr){
	int i=0;
	//遇到 \0 停止循环
	while ( *arr != '\0'){
		i++;
		arr++;
	}
	return i;
}
int main(){

	char arr[] = "abcdef";
	int ret = Strlen(&arr);
	printf("字符串的长度是: %d\n",ret);

	system("pause");
	return 0;
}

法3.递归

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

int Strlen(char* arr){
	if (*arr == '\0'){
		return 0;
	}
	else{
		return 1 + Strlen(arr + 1);
	}
}
int main(){
	char arr[] = "abcdef";
	int ret = Strlen(&arr);
	printf("字符串的长度是: %d\n", ret);

	system("pause");
	return 0;
}

2.strcpy (字符串的拷贝) 在C语言中不能使用 = 对字符串进行赋值
1.将一个字符串复制到str1上面
法1.利用strcpy 来实现

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){
	char str[10] = { 0 };
	strcpy(str, "hehe");
	printf("%s\n", str);

	system("pause");
	return 0;
}

法2.(利用取下标 和strcpy实现的功能一致)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

char*  Strcpy(char* str2, const char* str1){
	//对特殊情况的一种判定
	if (str2 == NULL || str1 == NULL){
		return NULL;
	}
	//asset(str2 != NULL && str2 != NULL);(断言:适用于致命问题)
	int cur = 0;
	while (str1[cur] != '\0'){
		str2[cur] = str1[cur];
		cur++;
	}
	str2[cur] = '\0';//字符串是以\0结尾的    必须加上\0
	return str2;
}

int main(){

	char str2[] = { 0 };

	char* p = NULL;
	if (p != NULL){
		Strcpy(str2,NULL );
	}
	Strcpy(str2, "hehe");
	printf("%s\n", str2);

	system("pause");
	return 0;
}

法3.(利用实现和地址递增 和strcpy实现的功能一致)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

char*  Strcpy(char* str2, const char* str1){

	char* result = str2;
	//对特殊情况的一种判定
	if (str2 == NULL || str1 == NULL){
		return NULL;
	}
	//asset(str2 != NULL && str2 != NULL);(断言:适用于致命问题)
	while (*str1 != '\0'){
		*str2 = *str1;
		str1++;
		str2++;
	}
	*str2 = '\0';//字符串是以\0结尾的    必须加上\0
	
	return  result;
}

int main(){

	char str2[] = { 0 };

	char* p = NULL;
	if (p != NULL){
		Strcpy(str2,NULL );
	}

	printf("%s\n", Strcpy(str2, "hehe"));

	system("pause");
	return 0;
}

3.strcat (字符串的拼接)
1.实现字符串的拼接
法1.strcat 直接实现

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){
	char str1[] = "hehe";
	char str2[] = "haha";


	printf("%s\n", strcat(str1, str2));
	system("pause");
	return 0;
}

法2.写一个函数实现和strcat功能一致

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

char* Strcat(char* dest,const char* src){
	if (dest == NULL || src == NULL){
		return NULL;
	}
	//1.先找到dest 结束的位置
	int cur = 0;
	while (dest[cur] != '\0'){
		cur++;
	}
	//循环结束,下标的位置就是\0
	//2.再把src往dest位置进行拷贝
	int i = 0;
	while (src[i] != '\0'){
		dest[cur + i] = src[i];
			i++;
	}
	dest[cur + i] = '\0';
	return dest;
}
int main(){
	char dest[] = "hehe";
	char src[] = "haha";
	printf("%s\n",Strcat(dest, src));

	system("pause");
	return 0;
}

字符串:
是特殊的字符数组,以\0结尾
字符数组:
不是以\0结尾的

所有和字符串相关的函数都必须用到字符串上
strlen :
求字符串的长度 不计算\0
strcpy :
字符串的拷贝(dest 对应的内存空间足够大,能容纳下拷贝之后的结果包括\0)
strcat:
字符串的拼接(dest 对应的内存空间足够大,能容纳下拼接之后的结果包含\0)

4.strcmp 字符串比较 (字符串的内容)
字符串的比较有两种:
1.比较两个字符串的身份和地址是不是同一个字符串( == )
2.比较两个字符串的内容是不是一样(strcmp)
strcmp 不仅能比较两个字符串的内容是不是一样,而且还能比较字符串的大小.(比较规则:字典序)
strcmp (str,str2)

  1. str1>str2 返回值大于1.
  2. str1<str2 返回值小于1.
  3. str1 == str2 返回值等于0

类型
char* Strcmp(char* str1,const char* str2)

举例1.比较两个字符串
法1.直接借助strcmp函数来进行比较

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){
	char str1[] = "hehe";
	char str2[] = "haha";
	int ret = strcmp(str1, str2);
	printf("%d\n", ret);

	system("pause");
	return 0;
}

拓展:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){
	char str1[] = "hehe";
	char str2[] = "haha";
	if (strcmp(str1,str2)<0){
		printf("str1 < str2\n");
	}
	else if (strcmp(str1, str2)>0){  //这块存在较大问题:导致strcmp函数被调用两次.
		printf("str1 > str2\n");    //假如比较的字符串很大那么会导致系统内存消耗过大浪费空间
	}
	else {
		printf("str1 == str2\n");
	
	}

	system("pause");
	return 0;
}

对上述代码进行优化

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){
	char str1[] = "hehe";
	char str2[] = "haha";
	int ret = strcmp(str1, str2);
	if (ret < 0){
		printf("str1 < str2\n");
	}
	else if (ret > 0){
		printf("str1 > str2\n");    
	}
	else {
		printf("str1 == str2\n");
	}
	system("pause");
	return 0;
}

法2.模拟实现strcmp 功能

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>


char* Strcmp(char* str1,const char* str2){
	assert(str1 != NULL && str2 != NULL);
	while (*str1 != '\0' && *str2  != '\0'){
		if (*str1 < *str2){
			return -1;
		}
		else if (*str1 > *str2){
				return 1;
			}
			else{
				str1++;
				str2++;
			}
		}
	
	//看哪一个字符串先到达 \0 ,那个字符串就更小
	
		if (*str1 == '\0' && *str2 != '\0'){
			return -1;
		}
		else if (*str1 != '\0' && *str2 == '\0'){
				return 1;
			}
			else {
				return 0;
			}

	/*if (*str1 < *str2){
		return -1;
	}
	else if (*str1 > *str2){
		return 1;
	}*/
}
int main(){
	char str1[] = "hehe";
	char str2[] = "haha";
	int ret = Strcmp(str1, str2);

	if (ret < 0){
		printf("str1 < str2\n");
	}
	else if (ret > 0){
		printf("str1 > str2\n");
	}
	else {
		printf("str1 == str2\n");
	}
	system("pause");
	return 0;
}

5.strstr 查找字符串中的子字符串
类型
const char* Strcmp(const char* str1,const char* str2)
返回值是一个指针,指向的是str2在str1中第一次出现的位置(指向str1)

1.找到str2在str1中出现的位置

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){

	char str1[] = "hello world";
	char str2[] = "world";

	char* ret = strstr(str1,str2);
	printf("%p,%p\n",str1,ret);//str1指向的是首元素的地址,ret指向的是str2在str1中的位置

	system("pause");
	return 0;
}

2.模拟实现strstr

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

const char* Strstr(const char* str1, const char* str2){

	assert(str1 != NULL && str2 != NULL);
	if (*str2 == '\0'){
		return NULL;
	}
	//黑指针只是简单的记录开始位置
	const char* black = str1;
	while (*black != '\0'){
		const char* red = black;
		const char* sub = str2;

		while (*red != '\0' && *sub != '\0' && (*red == *sub)){
			red++;
			sub++;
		}
		// 当上面的循环结束, 可能有三种情况:
		// 1. red 遇到 \0
		// 2. sub 遇到 \0
		// 3. *red 和 *sub 不相等


		if (*sub == '\0'){
			return black;
		}
		/*if (*sub != '\0' && *red == '\0'){
			return NULL;
		}*/
		if (*red == '\0'){
			return NULL;
			}
		black++;
	}
	//没有匹配到字符串
	return NULL;
}

int main(){

	char str1[] = "hello world";
	char str2[] = "world";

	const char* ret = Strstr(str1,str2);
	printf("%p,%p\n",str1,ret);//str1指向的是首元素的地址,ret指向的是str2在str1中的位置
	system("pause");
	return 0;
}

6.strtok 表面上看"找标记",其实质是把字符串按照一定的分割符,分割成若干部分.
类型
char* strtok(char* str,const char* delimiters) strtok 要反复调用才能实现完整功能

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main(){
	char str[] = "this is Li Ming";

	char* pch = strtok(str, " ");

	while (pch != NULL){
		printf("%s\n", pch);
		pch = strtok(NULL, " ");
	}
	system("pause");
	return 0;

}

具体执行步骤:

1.strtok(str, " “) 从str的位置开始往后找,遇到” "字符,然后把这个字符修改成\0 返回t对应的指针
2.strtok(NULL, " “)从上一个切分位置的下一个位置开始往后查找” “;把找到的” "修改成 \0 返回i对应的指针
3.strtok(NULL, " “) 从L的位置开始往后查找” “,把找到” "修改成 \0,返回L对应的指针
4.strtok(NULL, " “) 从M的位置开始往后查找” “,把找到” "修改成 \0,返回M对应的指针
5.strtok(NULL, " ") 由于上次操作已经遇到\0 ,接下来不用查找,直接返回NULL.

strtok r如何记录上次切分的位置:
strtok 函数内部有一个static变量,保留了上次切分的位置.

7.strncpy strncat strncmp (都是防止内存不够而设计的)

strncpy strncat strncmp和strcpy strcat strcmp 使用方式全部一致,唯一的区别是strncpy strncat strncmp 能掌握住内存的不够,防止越界

1.实现两个字符串的拷贝

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){
	char str1[] = "hehe";
	char str2[] = "hahaha";
	//在这块对内存有了有效的遏制防止内存越界
	strncpy(str1, str2, sizeof(str1)-1);//sizeof(str1)-1 最后给\0留一个位置
	printf("%s\n", str1);

	system("pause");
	return 0;
}

2.实现两个字符串的连接

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){
	char str1[] = "hehe";
	char str2[] = "hahaha";
	//在这块对内存有了有效的遏制防止内存越界
	strncat(str1, str2, sizeof(str1)-1);//sizeof(str1)-1 最后给\0留一个位置
	printf("%s\n", str1);

	system("pause");
	return 0;
}

内存函数

8.memcpy 拷贝的是内存

void* memcpy(void* destination,void* source,size_t num) size_t num 只拷贝多少个字节
void* 是一种特殊的指针类型,void*是一个例外只含有地址没有大小因此不能解引用,不能进行±整数,不能指针相减
1.将一个的内容拷贝到另一个的内容,根据字节的设置从而打印出数字

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){
	
	int arr1[] = { 1, 2, 3, 4 };
	int arr2[10] = {0};
	memcpy(arr2, arr1, 4);// 4 代表拷贝的字节数

	for (int i = 0; i < 4;i++){
		printf(" %d ",arr2[i]);
	}
	system("pause"); 
	return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){

	short  arr1[] = { 1, 2, 3, 4 };
	short  arr2[10] = { 0 };
	memcpy(arr2, arr1, 4);// 4 代表拷贝的字节数

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

2.模拟实现 memcpy

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

void* Memcpy(void* dest, void* src, size_t num){
	assert(dest != NULL && src != NULL);
	//
	void* ret = dest;
	for (size_t i = 0; i < num;i++){
		*(char*)dest = *(char*)src;
		dest = (char*)dest+1;//本身是dest++: 但是由于dest的类型是void*不能进行相加运算.
		src =  (char*)src +1;
	}
	return ret;
}
int main(){

	int  arr1[] = { 1, 2, 3, 4 };
	int  arr2[10] = { 0 };
	Memcpy(arr2, arr1, 4);// 4 代表拷贝的字节数

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

但是memcpy存在一系列的问题,当遇到缓冲区重叠的时候,此时就要从后往前进行拷贝(利用memmove函数)

9.memmove 函数也是内存拷贝
如果缓冲区重合了,就从后往前拷贝,如果不重叠就按memcpy的方式来
1.模拟实现mommove函数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

void* Memcpy(void* dest, void* src, size_t num){
	assert(dest != NULL && src != NULL);
	//
	void* ret = dest;
	for (size_t i = 0; i < num;i++){
		*(char*)dest = *(char*)src;
		dest = (char*)dest+1;//本身是dest++: 但是由于dest的类型是void*不能进行相加运算.
		src =  (char*)src +1;
	}
	return dest;
}

void* Memmove(void* dest, void* src, size_t num){
	assert(dest != NULL && src != NULL);

	//先判定是否重合
	char* cdest = (char*)dest;
	char* csrc = (char*)src;
	//代表缓冲区重合
	if (csrc < cdest && cdest < csrc + num){
		char* pdest = cdest + num - 1;
		char* psrc = csrc + num - 1;
		for (size_t i = 0; i < num; i++){
			*pdest = *psrc;
			pdest--;
			psrc--;
		}
	}
	else {
		Memcpy(dest, src, num);
	}
	return dest;

}
int main(){

	int  arr1[] = { 1, 2, 3, 4 };
	int  arr2[10] = { 0 };
	Memcpy(arr2, arr1, 4);// 4 代表拷贝的字节数

	for (int i = 0; i < 4; i++){
		printf(" %d ", arr2[i]);
	}
	system("pause");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值