真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

【C語(yǔ)言進(jìn)階】一篇帶你掌握字符串和內(nèi)存函數(shù)-創(chuàng)新互聯(lián)

目錄
  • 一:strlen
    • 模擬實(shí)現(xiàn):
  • 二:strcpy
    • 模擬實(shí)現(xiàn):
  • 三:strcat
    • 模擬實(shí)現(xiàn):
  • 四:strcmp
    • 模擬實(shí)現(xiàn):
  • 五:strncpy
    • 模擬實(shí)現(xiàn):
  • 六:strncat
    • 模擬實(shí)現(xiàn):
  • 七:strncmp
    • 模擬實(shí)現(xiàn):
  • 八:strstr
    • 模擬實(shí)現(xiàn):
  • 九:strtok
    • 代碼實(shí)現(xiàn):
  • 九:strerror
  • 十:perror
  • 十一:一些字符函數(shù)
    • 字符分類函數(shù):
    • 字符轉(zhuǎn)換函數(shù):
  • 十二:memcpy
    • 模擬實(shí)現(xiàn):
  • 十三:memmove
    • 模擬實(shí)現(xiàn):
  • 十四:memcmp
  • 十四:memset

成都創(chuàng)新互聯(lián)公司是專業(yè)的鼓樓網(wǎng)站建設(shè)公司,鼓樓接單;提供成都做網(wǎng)站、網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設(shè),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行鼓樓網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!一:strlen

strlen:計(jì)算字符串長(zhǎng)度函數(shù)
size_t strlen ( const char * str );

注意事項(xiàng):

  • 字符串以'\0'作為結(jié)束標(biāo)志,strlen函數(shù)返回值是在字符串中'\0'前面出現(xiàn)的字符個(gè)數(shù)(不包含'\0'
  • 參數(shù)是一個(gè)字符指針變量
  • 參數(shù)指向的字符串必須要以'\0'結(jié)束,否則計(jì)算出的長(zhǎng)度是隨機(jī)值
  • 注意函數(shù)的返回值為size_t,是無(wú)符號(hào)的

?因?yàn)榉祷刂凳?code>size_t,所以就要避免出現(xiàn)下面這樣的代碼:strlen("abc") - strlen("abcde"),strlen("abc")算出的結(jié)果是3,strlen("abcde")算出的結(jié)果是5,可能想著3-5得到-2,實(shí)際上并不是這樣的,這里算出的3和5都是無(wú)符號(hào)整型,算出的-2也是一個(gè)無(wú)符號(hào)整型,-2在內(nèi)存中以補(bǔ)碼的形式存儲(chǔ),從無(wú)符號(hào)整型的視角看去,這串補(bǔ)碼就表示一個(gè)很大的正數(shù)。

模擬實(shí)現(xiàn):
//常規(guī)實(shí)現(xiàn)
int my_strlen1(const char* arr)
{assert(arr != NULL);
	int count = 0;
	while (*arr)
	{count++;
		arr++;
	}
	return count;
}

//遞歸實(shí)現(xiàn)
int my_strlen2(const char* arr)
{assert(arr!=NULL);
	if (*arr == '\0')
	{return 0;
	}
	else
	{return 1 + my_strlen2(arr + 1);
	}
}

//指針減指針實(shí)現(xiàn)
int my_strlen3(const char* arr)
{assert(arr != NULL);
	const char* start = arr;
	while (*arr)
	{arr++;
	}
	return arr - start;
}

int main()
{char arr[] = "abcdef";
	int len = my_strlen3(arr);
	printf("%d\n", len);
	return 0;
}
二:strcpy

strcpy:字符串拷貝函數(shù),把源字符串拷貝到目標(biāo)空間
char * strcpy ( char * destination, const char * source );

注意事項(xiàng):

  • 函數(shù)有兩個(gè)參數(shù),其中source指向待拷貝的字符串,也叫做源字符串,destination是目標(biāo)空間的地址
  • 源字符串必須以’\0’結(jié)束
  • 會(huì)把源字符串中的 ‘\0’ 也拷貝到目標(biāo)空間
  • 目標(biāo)空間必須足夠大,以確保能存放源字符串,否則會(huì)出現(xiàn)非法訪問(wèn)
  • 目標(biāo)空間必須可變,例如把源字符串拷貝到一個(gè)字符串常量里面是不可取的
模擬實(shí)現(xiàn):
char* my_strcpy(char* dest, const char* src)
{assert(dest && src);
	char* ret = dest;
	while (*dest++ = *src++)
	{;
	}
	return ret;
}

int main()
{char arr1[20] = {0 };
	char arr2[] = "hello world";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}
三:strcat

strcat:字符串追加函數(shù),將源字符串追加到目標(biāo)字符串后面,目標(biāo)中的終止字符’\0’會(huì)被源字符串的第一個(gè)字符覆蓋
char * strcat ( char * destination, const char * source );

注意事項(xiàng):

  • 函數(shù)有兩個(gè)參數(shù),其中source指向要追加的字符串,也叫做源字符串,destination是目標(biāo)空間的地址
  • 目標(biāo)空間中必須要有'\0',作為追加的起始地址
  • 源字符串中也必須要有'\0'作為追加的結(jié)束標(biāo)志
  • 目標(biāo)空間必須足夠大,能容納下源字符串的內(nèi)容
  • 目標(biāo)空間必須可修改
  • 自己給自己追加會(huì)陷入死循環(huán)
模擬實(shí)現(xiàn):
char* my_strcat(char* dest, const char* src)
{assert(dest && src);
	char* ret = dest;
	//找目標(biāo)空間的'\0'
	while (*dest != '\0')
	{dest++;
	}
	//追加
	while (*dest++ = *src++)
	{;
	}
	return ret;
}

int main()
{char arr1[20] = "hello ";
	char arr2[] = "world";
	my_strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}
四:strcmp

strcmp:字符串比較函數(shù)
int strcmp ( const char * str1, const char * str2 );

注意事項(xiàng):

  • 這里比較的不是兩個(gè)字符串的長(zhǎng)度,而是對(duì)應(yīng)位置上的ASCII值
  • 第一個(gè)字符串大于第二個(gè)字符串,則返回大于0的數(shù)字
  • 第一個(gè)字符串等于第二個(gè)字符串,則返回0
  • 第一個(gè)字符串小于第二個(gè)字符串,則返回小于0的數(shù)字
模擬實(shí)現(xiàn):
int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);
	while (*str1 == *str2)//如果相等就進(jìn)去,兩個(gè)指針加加,但是可能會(huì)出現(xiàn)兩個(gè)字符串相等的情況,兩個(gè)指針都指向'\0',此時(shí)比較就結(jié)束了
	{if (*str1 == '\0')
		{	return 0;
		}
		str1++;
		str2++;
	}
	if (*str1 >*str2)
	{return 1;
	}
	else
	{return -1;
	}
}

int main()
{char arr1[] = "abq";
	char arr2[] = "abq";
	int ret=my_strcmp(arr1, arr2);
	printf("%d\n", ret);
	return 0;
}
五:strncpy

strncpy:長(zhǎng)度受限的字符串拷貝函數(shù)
char * strncpy ( char * destination, const char * source, size_t num );

注意事項(xiàng):

  • 拷貝num個(gè)字符從源字符串到目標(biāo)空間。
  • 如果源字符串的長(zhǎng)度小于num,則拷貝完源字符串之后,在目標(biāo)的后邊追加0,直到num個(gè)。
模擬實(shí)現(xiàn):
char* my_strncpy(char* dest, const char* src, int num)
{assert(dest && src);
	char* ret = dest;
	while (num)
	{if (*src == '\0')//此時(shí)說(shuō)明src指針已經(jīng)指向了待拷貝字符串的結(jié)束標(biāo)志'\0'處,src指針就不用再++了
		{	*dest = '\0';
			dest++;
		}
		else
		{	*dest = *src;
			dest++;
			src++;
		}
		num--;
	}
	return ret;
}

int main()
{char arr1[20] = "xxxxxxxxxxxxxxxxxxx";
	my_strncpy(arr1, "abcdef", 10);
	printf("%s\n", arr1);
	return 0;
}
六:strncat

strncat:長(zhǎng)度受限的字符串追加函數(shù)
char * strncat ( char * destination, const char * source, size_t num );

注意事項(xiàng):

  • 從源字符串的第一個(gè)字符開(kāi)始往后數(shù)num個(gè)字符追加到目標(biāo)空間的后面,外加一個(gè)終止字符。
  • 如果源字符串的長(zhǎng)度小于 num,則僅復(fù)制終止字符之前的內(nèi)容。
模擬實(shí)現(xiàn):
char* my_strncat(char* dest, const char* src, int sz)
{assert(dest && src);
	char* ret = dest;
	//找目標(biāo)空間的\0
	while (*dest != '\0')
	{dest++;
	}
	//追加
	while (sz)
	{*dest++ = *src++;
		sz--;
	}
	*dest = '\0';
	return ret;
}

int main()
{char arr1[20] = "abc\0xxxxxxxxxxx";
	my_strncat(arr1, "defjhigk", 3);
	printf("%s\n", arr1);
	return 0;
}
七:strncmp

strncmp:長(zhǎng)的受限的字符串比較函數(shù)
int strncmp ( const char * str1, const char * str2, size_t num );

注意事項(xiàng):

  • 比較到出現(xiàn)另個(gè)字符不一樣或者一個(gè)字符串結(jié)束或者num個(gè)字符全部比較完。
模擬實(shí)現(xiàn):
int my_strncmp(const char* str1, const char* str2, int sz)
{assert(str1 && str2);
	while (sz)
	{if (*str1< *str2)
		{	return -1;
		}
		else if (*str1 >*str2)
		{	return 1;
		}
		else if(*str1 == '\0'||*str2 =='\0')//當(dāng)有一個(gè)為'\0',說(shuō)明比較就可以結(jié)束了
		{	if (*str1 == '\0' && *str2 == '\0')//如果二者都是'\0',說(shuō)明兩個(gè)字符串相等
			{		return 0;
			}
			else if(*str1 =='\0')//如果str1為'\0',說(shuō)明str1小,str2大
			{		return -1;
			}
			else//如果src為'\0',說(shuō)明str1大,str2小
			{		return 1;
			}
		}
		sz--;
		str1++;
		str2++;
	}
}

int main()
{int ret = my_strncmp("abcdef", "abcd", 5);
	printf("%d\n", ret);
	return 0;
}
八:strstr

strstr:字符串查找函數(shù)
const char * strstr ( const char * str1, const char * str2 );

注意事項(xiàng):

  • 在str1指向的字符串中查找str2指向的字符串
  • 返回一個(gè)指向str1中第一次出現(xiàn)的str2的指針
  • 如果 str2 不是 str1 的一部分,則返回一個(gè)空指針
  • 匹配過(guò)程不包括終止空字符,但它到此為止
模擬實(shí)現(xiàn):
char* my_strstr(char* str1, char* str2)
{assert(str1 && str2);
	if (*str2 == '\0')
	{return str1;
	}
	char* s1 = str1;
	char* s2 = str2;
	char* cp = str1;
	while (*cp)
	{s1 = cp;
		s2 = str2;
		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
		{		s1++;
				s2++;
		}
		if (*s2 == '\0')
		{	return cp;
		}
		cp++;
	}
	return NULL;
}

int main()
{char arr1[] = "abbvcbcbbdbbvbnui";
	char arr2[] = "bbvb";
	char* ret = my_strstr(arr1, arr2);
	if (ret == NULL)
	{printf("找不到\n");
	}
	else
	{printf("%s\n", ret);
	}
	
	return 0;
}
九:strtok

strtok:字符串拆分函數(shù)
char * strtok ( char * str, const char * sep );

注意事項(xiàng):

  • sep參數(shù)是個(gè)字符串,定義了用作分隔符的字符集合
  • 第一個(gè)參數(shù)指定一個(gè)字符串,它包含了0個(gè)或者多個(gè)由sep字符串中一個(gè)或者多個(gè)分隔符分割的標(biāo)記
  • strtok函數(shù)找到str中的下一個(gè)標(biāo)記,并將其用 \0 結(jié)尾,返回一個(gè)指向這個(gè)標(biāo)記的指針。(注:strtok函數(shù)會(huì)改變被操作的字符串,所以在使用strtok函數(shù)切分的字符串一般都是臨時(shí)拷貝的內(nèi)容并且可修改。)
  • strtok函數(shù)的第一個(gè)參數(shù)不為 NULL ,函數(shù)將找到str中第一個(gè)標(biāo)記,strtok函數(shù)將保存它在字符串中的位置
  • strtok函數(shù)的第一個(gè)參數(shù)為 NULL ,函數(shù)將在同一個(gè)字符串中被保存的位置開(kāi)始,查找下一個(gè)標(biāo)記
  • 如果字符串中不存在更多的標(biāo)記,則返回 NULL 指針
代碼實(shí)現(xiàn):
int main()
{char arr[] = "konglong@qq.com";
	char* p = "@.";
	char buf[20] = {0 };
	strcpy(buf, arr);
	char* ret=NULL;
	for (ret = strtok(buf, p); ret != NULL; ret = strtok(NULL, p))
	{printf("%s\n", ret);
	}
	return 0;
}
九:strerror

strerror:把錯(cuò)誤碼轉(zhuǎn)換成錯(cuò)誤信息的函數(shù)
char * strerror ( int errnum );

注意事項(xiàng):

  • C語(yǔ)言的庫(kù)函數(shù)在運(yùn)行的時(shí)候,如果發(fā)生錯(cuò)誤,就會(huì)把錯(cuò)誤碼存在一個(gè)變量中,這個(gè)變量是:errno
  • 返回的指針指向靜態(tài)分配的字符串(錯(cuò)誤信息字符串)

一些錯(cuò)誤碼對(duì)應(yīng)的錯(cuò)誤信息:

int main()
{printf("%s\n", strerror(0));
	printf("%s\n", strerror(1));
	printf("%s\n", strerror(2));
	printf("%s\n", strerror(3));
	printf("%s\n", strerror(4));
	printf("%s\n", strerror(5));
	return 0;
}
//結(jié)果:
No error
Operation not permitted
No such file or directory
No such process
Interrupted function call
Input/output error

strerror函數(shù)的一般用法:

int main()
{//打開(kāi)文件
	FILE* pf = fopen("test.c", "r");
	if (pf == NULL)
	{printf("%s\n", strerror(errno));//需要包含頭文件#includereturn 1;
	}
	//讀文件
	//關(guān)閉文件
	fclose(pf);
	return 0;
}
//打開(kāi)失敗時(shí)屏幕顯示:
No such file or directory

?fopen是一個(gè)打開(kāi)文件的函數(shù),第一參數(shù)是文件名,第二個(gè)參數(shù)是打開(kāi)方式,如果打開(kāi)成功會(huì)返回一個(gè)有限的指針,打開(kāi)失敗會(huì)返回一個(gè)空指針,此時(shí)我們就可以通過(guò)strerror函數(shù)去查看為什么打開(kāi)失敗

十:perror

perror:直接打印錯(cuò)誤信息的函數(shù)
void perror ( const char * str );

注意事項(xiàng):

  • str指向一個(gè)字符串,這個(gè)字符串包含要在錯(cuò)誤消息本身之前打印的自定義消息。如果是空指針,則不會(huì)打印前面的自定義消息,但仍會(huì)打印錯(cuò)誤消息
  • 如果參數(shù)str不是空指針,則打印str后跟冒號(hào) (:)和一個(gè)空間。然后,無(wú)論str是否為空指針,都會(huì)打印生成的錯(cuò)誤描述,后跟換行符 ('\n'

perror函數(shù)的一般用法:

int main()
{//打開(kāi)文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{perror("fopen");
		return 1;
	}
	//讀文件
	//關(guān)閉文件
	fclose(pf);
	return 0;
}
//打開(kāi)失敗時(shí)顯示:
fopen: No such file or directory
十一:一些字符函數(shù)字符分類函數(shù):
函數(shù)如果它的參數(shù)復(fù)合下列條件就返回真(一個(gè)非零數(shù)字)
iscntrl任何控制字符
isspace空白字符:空格’ ‘,換頁(yè)’\f’,換行’\n’,回車(chē)’\r’,制表符’\t’或者垂直制表符’\v’
isdigit十進(jìn)制數(shù)字0~9
isxdigit十六進(jìn)制數(shù)字,包括所有十進(jìn)制數(shù)字,小寫(xiě)字母a~f,大寫(xiě)字母A~F
islower小寫(xiě)字母a~z
isupper大寫(xiě)字母A~Z
isalpha字母a~z或A~Z
isalnum字母或者數(shù)字,a~z,A~Z ,0~9
ispunct標(biāo)點(diǎn)符號(hào),任何不屬于數(shù)字或者字母的圖形字符(可打?。?/td>
isgraph任何圖形字符
isprint任何可打印字符,包括圖形字符和空白字符
字符轉(zhuǎn)換函數(shù):

tolower:將大寫(xiě)字母轉(zhuǎn)換為小寫(xiě)字母
int tolower ( int c );

注意事項(xiàng):

  • 如果 c 是大寫(xiě)字母并且具有小寫(xiě)等效字母,則將 c 轉(zhuǎn)換為其小寫(xiě)等效項(xiàng)。如果無(wú)法進(jìn)行此類轉(zhuǎn)換,則返回的值為 c 不變。
  • 大寫(xiě)字母是以下任意字母:A B C D E F G H I J K L M N O P Q R S T U V W X Y Z,分別翻譯為:a b c d e f g h i j k l m n o p q r s t u v w x y z
  • 這里是值傳遞,不會(huì)改變實(shí)參

toupper:將小寫(xiě)字母轉(zhuǎn)換成大寫(xiě)字母
int toupper ( int c );

注意事項(xiàng):

  • 如果 c 是小寫(xiě)字母并且具有大寫(xiě)等效字母,則將 c 轉(zhuǎn)換為其大寫(xiě)等效字母。如果無(wú)法進(jìn)行此類轉(zhuǎn)換,則返回的值為 c 不變
  • 這里是值傳遞,不會(huì)改變實(shí)參

應(yīng)用:

int main()
{char arr[] = "I Have An Apple";
	int i = 0;
	while (arr[i])
	{if (isupper(arr[i]))
		{	printf("%c", tolower(arr[i]));//把轉(zhuǎn)換的小寫(xiě)字母直接打印出來(lái)
		}
		else
		{	printf("%c", arr[i]);
		}
		i++;
	}
	return 0;
}
//結(jié)果:
i have an apple

int main()
{char arr[] = "I Have An Apple";
	int i = 0;
	while (arr[i])
	{if (isupper(arr[i]))
		{	arr[i] = tolower(arr[i]);//用轉(zhuǎn)換后的小寫(xiě)字符替換原有的大寫(xiě)字符
		}
		printf("%c", arr[i]);
		i++;
	}
	return 0;
}

?以上介紹的這些函數(shù)都是針對(duì)字符串或者字符的,那如果我們要拷貝其他類型的數(shù)據(jù)呢?用上面這些函數(shù)自然就行不通了,此時(shí)就要用到即將介紹的內(nèi)存函數(shù)了。

十二:memcpy

memcpy:內(nèi)存拷貝函數(shù)
void * memcpy ( void * destination, const void * source, size_t num );

注意事項(xiàng):
?這里的destination指向要在其中賦值內(nèi)容的目標(biāo)數(shù)組,source指向要復(fù)制的數(shù)據(jù)源,num是要復(fù)制的字節(jié)數(shù),注意這里前兩個(gè)指針的的類型還有函數(shù)返回值都是void*,這是因?yàn)?,memcpy這個(gè)函數(shù)是內(nèi)存拷貝函數(shù),它有可能拷貝整型,浮點(diǎn)型,結(jié)構(gòu)體等等各種類型的數(shù)據(jù)……雖然返回類型是void*,但他也是必不可少的,void*也表示一個(gè)地址,用戶可以把它強(qiáng)制轉(zhuǎn)換成自己需要的類型去使用。

應(yīng)用:

//把a(bǔ)rr1中的1、2、3、4、5拷貝到arr2數(shù)組中
int main()
{int arr1[] = {1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = {0 };
	memcpy(arr2, arr1, 20);//拷貝5個(gè)整型,就是20個(gè)字節(jié)
	return 0;
}

//把a(bǔ)rr1中的3、4、5、6拷貝到arr2數(shù)組中
int main()
{int arr1[] = {1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = {0 };
	memcpy(arr2, arr1+2, 16);//此時(shí)只要改變參數(shù)中數(shù)據(jù)源的地址就可以,把3的地址傳過(guò)去就行,復(fù)制4個(gè)整型就是1個(gè)字節(jié)
	return 0;
}
模擬實(shí)現(xiàn):
void* my_memcpy(void* dest, const void* src, size_t num)
{assert(dest && src);
	void* ret = dest;
	while (num)
	{*(char*)dest = *(char*)src;
		((char*)dest)++;
		((char*)src)++;
		num--;
	}
	return ret;
}

int main()
{int arr1[] = {1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = {0 };
	my_memcpy(arr2, arr1+2, 16);
	return 0;
}

?上面代碼中模擬出來(lái)的my_memcpy函數(shù)已經(jīng)可以實(shí)現(xiàn)把a(bǔ)rr1數(shù)組中的元素拷貝到arr2數(shù)組里面去。但當(dāng)我們想把a(bǔ)rr1數(shù)組中的1、2、3、4、5拷貝到arr1數(shù)組中的3、4、5、6、7上去時(shí),就會(huì)發(fā)生錯(cuò)誤,如下圖:
在這里插入圖片描述
?原因是:當(dāng)1拷貝到3上時(shí),原來(lái)的3已經(jīng)被1替換,當(dāng)2拷貝到4上的時(shí)候,原來(lái)的4已將被2替換。所以當(dāng)拷貝arr[2]到arr[4]上的時(shí)候,原本arr[2]里面存放的3已將被1替換了,同理,所以才得出了不符合我們預(yù)期的結(jié)果。那如何解決這個(gè)問(wèn)題呢?先來(lái)分析這個(gè)問(wèn)題產(chǎn)生的原因,這是因?yàn)樵纯臻g與目標(biāo)空間之間有重疊,這里的arr[2]、arr[3]、arr[4]既是源空間也是目標(biāo)空間,當(dāng)拷貝1和2的時(shí)候把源空間中開(kāi)沒(méi)有拷貝的3和4就給覆蓋了,此時(shí)源空間arr[2]和arr[3]里面存的就不再是3和4了,而是1和2,所以此時(shí)拷貝arr[2]和arr[3]里面的數(shù)據(jù),其實(shí)拷貝的就是1和2。為了解決這個(gè)問(wèn)題,我們可以從后往前拷貝,此時(shí)就不會(huì)出現(xiàn)這樣的問(wèn)題
在這里插入圖片描述
?解決的思路就是:先拷貝重疊區(qū)域的元素,避免其還沒(méi)拷貝就被覆蓋掉。但并不是一遇到源空間和目標(biāo)空間重疊就從后王前拷貝,比如下面這樣,此時(shí)要把3、4、5、6、7拷貝到1、2、3、4、5里面
在這里插入圖片描述
?此時(shí)就不能用上面的方法從后往前拷貝了,但是可以根據(jù)上面提到的解決思路:先拷貝重疊區(qū)域的元素,所以此時(shí)就應(yīng)該從前往后拷貝,即按照3、4、5、6、7的順序去拷貝
?因此在拷貝的時(shí)候,是按照從前往后的順序還是從后往前的順序得看具體的情況。當(dāng)目標(biāo)空間的起始位置在源空間的前面時(shí),就得從前往后進(jìn)行拷貝。當(dāng)目標(biāo)空間的起始位置在源空間的后面的時(shí)候,就要從后往前拷貝。當(dāng)源空間和目標(biāo)空間沒(méi)有任何重疊的時(shí)候,不管是從前往后拷貝還是從后往前拷貝效果都一樣。
?接下來(lái)介紹的memmove函數(shù)就可以完成重疊空間的元素拷貝。

十三:memmove

memmove:內(nèi)存拷貝函數(shù)
void * memmove ( void * destination, const void * source, size_t num );
?它的參數(shù)、返回值與memcpy函數(shù)一模一樣。這里就不過(guò)多介紹。對(duì)于這兩個(gè)函數(shù)來(lái)說(shuō),目標(biāo)空間必須足夠大,不然就會(huì)發(fā)生越界訪問(wèn)。

模擬實(shí)現(xiàn):
void* my_memmove(void* dest, const void* src, int num)
{assert(dest && src);
	void* ret = dest;
	if (dest< src)
	{//從前向后
		while (num--)
		{	*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{//從后往前
		while (num--)//num為1的時(shí)候,下面的num就是0
		{	*((char*)dest + num) = *((char*)src + num);//通過(guò)num的減減就可以實(shí)現(xiàn)對(duì)每一個(gè)字節(jié)的訪問(wèn)
		}
	}
	return ret;
}

int main()
{int arr1[] = {1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1+2, arr1, 20);
	return 0;
}
十四:memcmp

memcmp:內(nèi)存比較函數(shù)
int memcmp ( const void * ptr1, const void * ptr2, size_t num );

注意事項(xiàng):

  • 比較從ptr1和ptr2指針開(kāi)始的num個(gè)字節(jié)
  • 兩個(gè)內(nèi)存塊中不匹配的第一個(gè)字節(jié)在 ptr1 中的值低于 ptr2 中的值返回一個(gè)小于零的數(shù)子,相等返回零,兩個(gè)內(nèi)存塊中不匹配的第一個(gè)字節(jié)在 ptr1 中的值大于在 ptr2 中的值返回一個(gè)大于零的數(shù)子

應(yīng)用

int main()
{int arr1[] = {1,2,6 };//01 00 00 00 02 00 00 00 06 00 00 00
	int arr2[] = {1,2,5 };//01 00 00 00 02 00 00 00 05 00 00 00
	int ret = memcmp(arr1, arr2, 9);
	printf("%d\n", ret);
	return 0;
}//結(jié)果:
1
十四:memset

memset:內(nèi)存設(shè)置函數(shù)
void * memset ( void * ptr, int value, size_t num );

注意事項(xiàng):

  • 以字節(jié)為單位來(lái)設(shè)置內(nèi)存中的數(shù)據(jù),把從ptr開(kāi)始往后的num個(gè)字節(jié)設(shè)置成value
  • 形參value也可以是字符,字符其實(shí)也是整型,因?yàn)樽址趦?nèi)存中存的是其ASCII
  • value如果是整數(shù)的話,需要注意它的取值范圍,因?yàn)橐粋€(gè)字節(jié)大可以存儲(chǔ)255,超過(guò)255就會(huì)發(fā)生截?cái)?/li>

應(yīng)用:

int main()
{char arr[] = "hello word";
	memset(arr, 'x', 5);//先把"hello"改成"xxxxx"
	printf("%s\n", arr);
	memset(arr + 6, 'y', 4);//再把"word"改成"yyyy"
	printf("%s\n", arr);
	return 0;
}
//

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧


新聞標(biāo)題:【C語(yǔ)言進(jìn)階】一篇帶你掌握字符串和內(nèi)存函數(shù)-創(chuàng)新互聯(lián)
網(wǎng)頁(yè)路徑:http://weahome.cn/article/hhssh.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部