那些C语言中你不知道的字符串函数(坑)

1.strcpy()

在字符串拷贝函数中,它的函数编写不难,如下

char* Strcpy(char* dest, const char* src) {
	assert(dest != NULL && src != NULL);
	
	char* result = dest;
	while (*src != '\0') {
		*dest = *src;
		src++;
		dest++;
	}
	*dest = '\0';
	return result;
}

但是,我们要注意的是, 目标内存的空间大小能否存储下源字符串的内容,在C语言中这一点,只能通过程序员来保证,所以往后再使用此类函数时候,一定要注意这一点.

2.strstr()函数

主要用来判断两个字符串是否为父子关系,也就是说str2字符串是否为Str1字符串的子串.我们自定义的函数里面使用了红黑指针用来标记子字符串首地址.

const char* Strstr(const char* str1, const char* str2) {
	//避免违法内存
	assert(str1 != NULL && str2 != NULL);

	if (*str2 == '\0') {
		//此时说明str2是一个空字符串
		return NULL;
	}
	
	const char* black = str1;
	while (*black != '\0') {
		const char* red = black;
		const char* sub = str2;
		
		while((*red == *sub) && *red != '\0' && *sub != '\0' ) {
			//三个结束条件
			//1. *red *sub不一样
			//2. red到头未找到
			//3. sub到头找到
			red++;
			sub++;
		}
		if (*sub == '\0') {//if顺序不可调换
			return black;	//sub到头,找到子字符串
		}
		if (*red == '\0') { //red到头没找到子字符串
			return NULL;
		}
		black++;		//继续处理下次循环匹配
	}
	return NULL;   //到头也没找到
}

3.strcat()函数 字符串拼接函数

char* Strcat(char* dest, const char* src) {
	if (dest == NULL || src == NULL) {
		return NULL;
	}
	// 1. 先找到 dest 的结束位置
	int cur = 0;
	while (dest[cur] != '\0') {
		cur++;
	}
	// 循环结束之后, cur 下标位置就是 \0
	// 2. 再把 src 往 dest 的结束位置进行拷贝
	int i = 0;
	while (src[i] != '\0') {
		dest[cur + i] = src[i];
		i++;
	}
	// 最后的设置 \0 千万不要遗漏
	dest[cur + i] = '\0';
	return dest;
}

4.字符串内个数  strlen()

int Strlen(const char* str) {
    assert(str != NULL);
	int size = 0;
	while (*str != '\0') {
		size++;
		str++;
	}
	return size;
}

5.strcmp()两字符串按照字典序比较大小

int Strcmp(const 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 < *str2) {
		return -1;
	} else if (*str1 > *str2) {
		return 1;
	} else {
		return 0;
	}
}

6.内存拷贝memcpy()

void* Memcpy(void* dest, const 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;
		src = (char*)src + 1;
	}
	return ret;
}

        以上的字符串函数和内存拷贝函数中,都要注意目标存储空间的大小能否容纳下源字符串或内容的大小.在C语言中这一点,只能通过程序员来保证,所以往后再使用此类函数时候,一定要注意这一点.

7.memmove()

在改良的条件下,多传入一个函数用于规避以上的内存访问越界问题中,memMove()函数能避免此类问题.

void* Memmove(void* dest, const 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;
}

 此函数的功能在于,发现两个内存空间重叠时,会调换拷贝的方式为:从后往前拷贝;

如果不重叠,则按照memcpy()拷贝,

 

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