字符串函數的實現, memmove() 函數的實現和解析

  • strlen 函數的實現
int my_strlen(char* dst) {
	assert(dst);
	char* ret = dst;
	int count = 0;
	while (*ret!='\0') {
		++ret;
		++count;
	}
	return count;
}
  • strcat 函數的實現
har* my_strcat(char* dst, const char* src) {
	assert(dst && src);
	char* ret = dst;           // 因爲後邊 dst需要++,所以用ret保存原來的位置
	while (*dst != '\0') {    //先找到 dst 上'\0' 的位置
		++dst;
	}
	while (*dst++ = *src++);  //當 dst 到 '\0'了,再將 src 傳給 dst
	return ret;
}

和strcpy 不同的是 strcpy是拷貝,strcat是追加拷貝。

  • strcmp 函數的實現
int my_strcmp(const char* str1,const char* str2) {
	assert(str1 && str2);
	unsigned char* s1 = (unsigned char*)str1;
	unsigned char* s2 = (unsigned char*)str2;
	while (*s1 && *s2) {
		if (*s1 > *s2) {
			return 1;
		}
		else if (*s1 < *s2) {
			return -1;
		}
		else {
			++s1;
			++s2;
		}
	}
	if (*s1 == '\0'&&*s2 == '\0') {
		return 0;
	}
	else if (*s1 == '\0') {
		return -1;
	}
	else {
		return 1;
	}
}

strcmp 函數居然是根據字符串中字符的 ASCII 碼大小來比較字符串大小的,我有一點不解,假如有兩個字符串 str1 = “abbb” 和 str1 = “baaa”,用 strcmp 函數的話,結果是 str2 大於 str1,僅僅是因爲 str2 的第一個字符 b 的 ASCII 碼大於 str1 的 a。我的想法是應該比較總的 ASCII 碼的大小。(僅僅是我自己的臆想,還是按照人家的來吧!)

  • strstr 函數的實現
    判斷一個字符串是不是另一個字符串的子串,如果是,則該函數返回 str2 在 str1 中首次出現的地址,否則,返回NULL。
char* my_strstr(const char* src, const char* sub) {
	assert(src && sub);
	const char* srci = src;
	const char* subi = sub;
	while (*srci != '\0') {
		while (*srci == *subi && *subi != '\0') {
			++srci;
			++subi;

		}
		if (*subi == '\0') {
			return src;
		}
		else {
			subi = sub;
			++src;
			srci = src;
		}
	}
}
  • memcpy 函數的實現
void* my_memcpy(void* dst, const void* src, size_t num) {
	assert(dst && src);       
	char* str_dst = (char*)dst;
	char* str_src = (char*)src;
	for (size_t i = 0; i < num; ++i) {
		str_dst[i] = str_src[i];   // 等價於 *(str_src + i)
	}
	return dst;
}

memcpy函數和strcpy函數的一個區別在於,memcpy可以拷貝任意類型的數據,而strcpy函數只能拷貝字符串

  • memmove 函數的實現

    memmove 函數有兩種實現的方法。
    在這裏插入圖片描述
    如圖要將紅色部分的數據拷貝到黑色部分,第一種情況是內存的前重疊,和不重疊,直接從 src 的前往 src 的後拷貝給 dst,不會影響結果。但是如果是內存的後重疊,如下圖:
    在這裏插入圖片描述
    如果還是按照從前往後進行拷貝,把 src 的第一個數據拷給 dst 的第一個數據時,就已經改變了 src 後邊的數據,因爲 dst 第一個數據所在位置剛好重疊與 src 後邊的數據,這樣拷貝,已經改變了還沒有拷貝給 dst 的數據,後邊拷貝的數據並不是我們最初想要的。所以這種內存後重疊,我們就要從後往前進行拷貝,也就是說,先把 src 的最後一個數據拷貝給 dst 的最後一個數據,然後把 src 的倒數第二個數據拷貝給 dst 的倒數第二個數據,以此類推。這樣做就不會改變還沒有拷貝給 dst 的 src 數據。
    以下有兩種拷貝方式,第一種是:給前重疊或者不重疊從前往後拷貝,給後重疊或者不重疊從後往前拷貝(從前往後或者從後往前拷貝都不會影響到內存不重疊的拷貝)。 第二種是:給內存前重疊或者不重疊的從前往後拷貝,給內存後重疊的從後往前拷貝。

    第一種

void* my_memmove(void* dst, const void* src, size_t num) {
	assert(src && dst);
	char* str_dst = (char*)dst;
	char* str_src = (char*)src;
	if (str_dst < str_src) { //前重疊或者不重疊,從前往後拷貝
		for (size_t i = 0; i < num; ++i) {
			str_dst[i] = str_src[i];
		}
	}
	else {//後重疊或者是不重疊,從後往前拷貝
		for (int i = num-1 ; i >= 0; --i) {
			str_dst[i] = str_src[i];
		}
	}
	return dst;
 }
**第二種**
void* my_memmove(void* dst, const void* src, size_t num) {
	assert(src && dst);
	char* str_dst = (char*)dst;
	char* str_src = (char*)src;
	if (str_src < str_dst && str_dst<str_src +num) {   //後重疊 從後往前拷貝
		for (int i = num - 1; i >= 0; --i) {
			str_dst[i] = str_src[i];
		}
	}
	else {   //前重疊或者不重疊,從前往後拷貝
		for (size_t i = 0; i < num; ++i) {
			str_dst[i] = str_src[i];
		}
	}
	return dst;
}

值得一提的是,字符串數組可以用這種方式初始化(char str[] = “abcdefg”),但是不可以用這種方式賦值,這裏就可以用到字符串函數 strcpy memcpy memmove

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章