本章重點(diǎn)
重點(diǎn)介紹處理字符和字符串的庫函數(shù)的使用和注意事項(xiàng)。
- 求字符串長度
- strlen()
- 長度不受限制的的字符串函數(shù)
- strcpy()
- strcat()
- strcmp()
- 長度受限制的的字符串函數(shù)
- strncpy()
- strncat()
- strncmp()
- 字符串查找
- strstr()
- strtok()
- 錯(cuò)誤信息報(bào)告
- strerror()
- 字符操作
- 內(nèi)存操作函數(shù)
- memcpy()
- memmove()
- memset()
- memcmp()
前言
C語言中對(duì)字符的字符串的處理很頻繁,但是C語言本身是沒有字符串類型的,字符串通常放在
常量字符串
中或者字符數(shù)組
中。
字符串常量
適用于那些對(duì)它不做修改的字符串函數(shù)。
1、字符串函數(shù)
1.1、strlen()—統(tǒng)計(jì)字符串長度
//頭文件<string.h>
size_t strlen(const char* str);
- 首先傳的參數(shù)需要是個(gè)指針類型的。
- 字符串以
'\0'
作為結(jié)束標(biāo)志,strlen()函數(shù)返回的是在字符串中'\0'
前面出現(xiàn)的字符個(gè)數(shù)(不包含'\0'
)。 - 參數(shù)指向的字符串必須要以
'\0'
結(jié)束。 - 注意函數(shù)的返回值為size_t,是無符號(hào)整型的
- 學(xué)會(huì)strlen()函數(shù)的模擬實(shí)現(xiàn)。
1.2、strcpy()—字符串拷貝
//頭文件<string.h>
char* strcpy(char* destination, const char* source)
- 源字符串必須以
'\0'
結(jié)束。 - 會(huì)將源字符串中的
'\0'
拷貝到目標(biāo)空間。 - 返回值為目標(biāo)字符串的首字符地址。
- 目標(biāo)空間必須足夠大,以確保能存放源字符串。
- 目標(biāo)空間必須可變。
- 學(xué)會(huì)模擬實(shí)現(xiàn)。
簡單使用介紹:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char name[20] = { 0 };
strcpy(name, "zhangsan");
printf("%s\n", name);
return 0;
}
輸出:
1.3、strcat()—字符串追加
//頭文件<string.h>
char* strcat(char* destination, const char* source)
- 源字符串必須以
'\0'
結(jié)束。 - 源字符串在目標(biāo)字符串有\(zhòng)0的地方開始追加。并不是說只會(huì)在目標(biāo)字符串末尾處開始追加,只要目標(biāo)字符串中間某個(gè)位置有
\0
,那就直接從這個(gè)位置開始追加。 - 目標(biāo)空間必須有足夠的大,能容納下源字符串的內(nèi)容。
- 目標(biāo)空間必須可修改
1、簡單使用介紹:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
char arr2[20] = "hello ";
strcat(arr2, "world");
printf("%s\n", arr2);
return 0;
}
輸出:
2、這里說明一下:源字符串在目標(biāo)字符串有\(zhòng)0的地方開始追加。并不是說只會(huì)在目標(biāo)字符串末尾處開始追加,只要目標(biāo)字符串中間某個(gè)位置有\0
,那就直接從這個(gè)位置開始追加。
如下代碼:“hel\0lo”,中間位置有個(gè)\0,所以在追加"world"是,就直接從"hel"初開始追加了。最后輸出結(jié)果就是:
“helworld”。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
char arr2[20] = "hel\0lo ";
strcat(arr2, "world");
printf("%s\n", arr2);
return 0;
}
輸出:
2、模擬實(shí)現(xiàn):
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <assert.h>
char* my_strcat(char* dest, const char* source)
{
char* ret = dest;
assert(dest && source);
//1、找到目標(biāo)字符串的\0。
while (*dest != '\0')
{
dest++;
}
//2、拷貝
while (*dest++ = *source++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello ";
my_strcat(arr1, "world");
printf("%s\n", arr1);
return 0;
}
那能不能實(shí)現(xiàn)字符串自己給自己追加?如下:
答案:是不能的。
int main()
{
char arr1[20] = "hello ";
my_strcat(arr1, arr1); //如何實(shí)現(xiàn)這樣的效果呢?
printf("%s\n", arr1);
return 0;
}
1.4、strcmp()—比較字符串大小
//頭文件<string.h>
int strcmp(const char* str1, const char* str2);
- 返回值:
- 第一個(gè)字符串<第二個(gè)字符串,就返回小于0的數(shù)字
- 第一個(gè)字符串=第二個(gè)字符串,就返回0
- 第一個(gè)字符串>第二個(gè)字符串,就返回大于0的數(shù)字
那具體是怎么比較的呢?是依次比較各個(gè)字符串中字符的ASCII值。
比如:首先arr1中的字符’a’和arr2中的字符’a’進(jìn)行比較,發(fā)現(xiàn)ASCII一樣,然后再比較字符’b’…
之后當(dāng)比較到arr1中的字符’d’和arr2中的字符’f’是,發(fā)現(xiàn)arr2中的’f’的ASCII值比arr1中的’d’的ASCII值大。
所以最終結(jié)果為arr2大。
char arr1[] = "abcd";
char arr2[] = "abcf";
1、簡單使用:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcd";
char arr2[] = "abcf";
int ret = strcmp(arr1, arr2); //arr1小于arr2
if (ret < 0)
printf("<\n");
else if (ret == 0)
printf("=\n");
else
printf(">\n");
return 0;
}
輸出:
2、模擬實(shí)現(xiàn):
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <assert.h>
int my_strcmp(const char* str1,const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0; //判斷相等
str1++;
str2++;
}
if (*str1 > *str2)
return 1;
else
return -1;
}
int main()
{
char arr1[] = "abcd";
char arr2[] = "abcf";
int ret = my_strcmp(arr1, arr2);
if (ret < 0)
printf("<\n");
else if (ret == 0)
printf("=\n");
else
printf(">\n");
return 0;
}
//判斷>或者<的返回值還可以在優(yōu)化:
//將下面一段代碼替換為最后一行優(yōu)化的代碼
if (*str1 > *str2)
return 1;
else
return -1;
//替換這個(gè)優(yōu)化的代碼
return *str1 - *str2;
關(guān)于以上庫函數(shù)不安全的說明
上面所說到了庫函數(shù),其實(shí)是相對(duì)不安全的,比如:
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcd";
char arr2[] = "abcdfr";
//arr2的字符長度比arr1的字符長度長,當(dāng)讓arr2拷貝到arr1時(shí),arr1數(shù)組會(huì)放不下,
//放不下編譯器也會(huì)放,那就呆滯了越界訪問,以至于改變了其它內(nèi)存中的數(shù)據(jù),這是相當(dāng)危險(xiǎn)的。
strcpy(arr1, arr2);
return 0;
}
那這個(gè)時(shí)候,就應(yīng)用誕生了相對(duì)來說安全一點(diǎn)的庫函數(shù):長度受限制的的字符串函數(shù)。
長度受限制的字符串函數(shù)是什么意思呢?下面介紹:
1.5、strncpy()–長度受限制拷貝
int strncmp ( const char * str1, const char * str2, size_t num );
多個(gè)參數(shù):num。這個(gè)參數(shù)就是限制長度的參數(shù),比如說讓arr2的字符串拷貝到arr1中去,但是只允許拷貝3個(gè)字節(jié)的字符:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "aaaaa";
char arr2[] = "bbbbb";
//讓arr2的數(shù)據(jù)拷貝到arr1中去,但是只拷貝3個(gè)字節(jié)。
strncpy(arr1, arr2,3);
printf("%s\n", arr1);
return 0;
}
輸出:
可以看到輸出結(jié)果:只會(huì)將arr2中的前3個(gè)字符拷貝到arr1中,arr1前3個(gè)也字符會(huì)改變,并且后面的字符不會(huì)改變。
1.6、strncat()—長度受限制追加
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = "hello\0xxxxxx";
char arr2[] = "world";
strncat(arr1, arr2, 3);
printf("%s\n", arr1);
return 0;
}
輸出:這里有個(gè)點(diǎn)要注意以下:在使用strncat()時(shí),在追加完畢后,會(huì)自動(dòng)在目標(biāo)字符串末尾添加一個(gè)\0
表示一個(gè)字符的結(jié)束。
這里采用調(diào)試查看:
1.7、strncmp()—長度受限制比較
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abc";
strncmp(arr1, arr2, 3); //只比較3個(gè)字符,結(jié)果應(yīng)該為相等。
return 0;
}
1.8、strstr()—查找子串
const char * strstr ( const char * str1, const char * str2 );
參數(shù)說明:
- str1是母字符串的地址
- str2是子串的地址
比如現(xiàn)在有兩個(gè)字符串:
char arr1[] = "abcdef";
char arr2[] = "cde"
strstr(arr1,arr2);
需要在arr1(母字符串)中尋找有沒有arr2(子串)的內(nèi)容。首先arr2中的字符串內(nèi)容為:“cde”,而arr1中的字符串:“abcdef”,正好全部包含"cde"。那么此時(shí)strstr()函數(shù)會(huì)返回arr1中包含子串的首字符地址。也就是會(huì)返回arr1中字符c
的地址。那如果我們?cè)谝?code>%s打印時(shí),就會(huì)將arr1的"cdef"的值全部打印出來,因?yàn)閺钠鹗嘉恢谩痗’到’\0’結(jié)束,就是"cdef"。
所以strstr()函數(shù)的返回值是個(gè)char*類型的。
如果沒有查找到字串,就會(huì)返回一個(gè)NULL指針。
1、使用演示:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "cde";
char* ret = strstr(arr1, arr2);
if (ret == NULL)
{
printf("沒有找到\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
輸出:
1.9、strtok()—切割字符串
char* strtok(char* str, const char* sep);
-
sep參數(shù)是個(gè)字符串,定義了用作分隔符的字符集合。
比如現(xiàn)在有一個(gè)字符串:“zhengbo@helloworld.com”,假如字符
@
和字符.
就是我們分隔符,通過這兩個(gè)符號(hào),可以將字符串切割為一段一段的。那我們就可以這樣定義這個(gè)sep參數(shù):const char* sep = "@.";
-
第一個(gè)參數(shù)指定一個(gè)字符串,它包含了0個(gè)或者多個(gè)由sep字符串中一個(gè)或者多個(gè)分隔符分隔的標(biāo)記。
這里的第一個(gè)參數(shù)就是要切割的字符串:
char arr[] = "zhengbo@helloworld.com";
-
strtok函數(shù)找到了str中的下一個(gè)標(biāo)記,并將其用
\0
結(jié)尾,返回一個(gè)指向這個(gè)標(biāo)記的指針。(注:strtok函數(shù)會(huì)改變被操作的字符串,所以在使用strtok函數(shù)切分的字符串一般都是臨時(shí)拷貝的內(nèi)容沒那個(gè),并且可修改。)strtok函數(shù)找到了str中的下一個(gè)標(biāo)記
這句話的意思就是說,strtok找到了@
分隔符,就會(huì)把@
分隔符變?yōu)?code>'\0',那arr數(shù)組就會(huì)變成如下的樣子:char arr[] = "zhengbo\0helloworld.com";
然后
返回一個(gè)指向這個(gè)標(biāo)記的指針
,就是把分隔好的字符串:“zhengbo\0”,通過返回字符'z'
的地址,作為指針返回過去。但是這樣我們會(huì)發(fā)現(xiàn)一個(gè)問題:就是會(huì)把a(bǔ)rr數(shù)組里面的內(nèi)容給修改。那如果下面程序還需要使用arr數(shù)組呢?那情況就不對(duì)。所以說我們先應(yīng)該使用strcmp()函數(shù)把a(bǔ)rr數(shù)組給臨時(shí)拷貝一份給另外一個(gè)數(shù)組,然后把臨時(shí)拷貝的數(shù)組交給strtok來進(jìn)行操作,那這樣既能提取出來分隔的字符串,又能不對(duì)原數(shù)組arr進(jìn)行修改。具體實(shí)現(xiàn)如下代碼:
#include <stdio.h> #include <string.h> int mian() { const char* sep = "@."; char arr[] = "zhengbo@helloworld.com"; char cp[30] = { 0 }; strcmp(cp,arr); //臨時(shí)拷貝一份 strtok(cp, sep); //對(duì)臨時(shí)拷貝的數(shù)組進(jìn)行分隔 return 0; }
-
strtok函數(shù)的第一個(gè)參數(shù)不為NULL,函數(shù)將找到str中第一個(gè)標(biāo)記,strtok函數(shù)將保存它在字符串中的位置。
這個(gè)是說,我們?cè)谑状问褂胹trtok函數(shù)時(shí),需要傳第一個(gè)參數(shù),因?yàn)榈谝粋€(gè)參數(shù)里面保存了分隔符的地址,有了一個(gè)參數(shù)后,函數(shù)將找到str中第一個(gè)標(biāo)記,也就是說找到了
@
標(biāo)記(分隔符),然后返回首字符z
的地址,作為函數(shù)返回值,然后保存下來。 -
strtok函數(shù)的第一個(gè)參數(shù)為NULL,函數(shù)將在同一個(gè)字符串中被保存的位置開始,查找下一個(gè)標(biāo)記。
到這一步,再次調(diào)用strtok函數(shù),需要找第二個(gè),第三個(gè),第四個(gè)分割符的時(shí)候就不需要傳第一個(gè)參數(shù)了,所以到這個(gè)地方我們就能明白,只有在找第一個(gè)分隔符的時(shí)候才傳第一個(gè)參數(shù)。好,那問題又來了:那不傳第一個(gè)參數(shù),如何找到,下一個(gè)需要分割為字符串的首字符地址呢?原因是這樣的:其實(shí)在找到第一個(gè)分隔符之后,NULL指針表示一種狀態(tài),NULL指針會(huì)記錄著上一個(gè)分割后的起始位置,也就已經(jīng)記著了第一個(gè)分隔符后面的字符地址了。然后在根據(jù)sep中記錄的分隔符,分割出一段字符串。
-
如果字符串中不存在更多的標(biāo)記,則返回NULL指針。
到這一步,是說,在真?zhèn)€arr數(shù)組里面沒找到分隔符,那就直接strtok函數(shù)返回NULL指針。
1、效果演示:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
//創(chuàng)建分隔符集合
const char* sep = "@.";
//待分割的字符串
char arr[] = "zhengbo@helloworld.com";
//創(chuàng)建一個(gè)臨時(shí)數(shù)組
char cp[30] = { 0 };
//拷貝一份臨時(shí)數(shù)據(jù)
strcpy(cp,arr);
//切割出zhengbo@,并把@換為\0了,且把z字符的地址,返回給了ret。
char* ret = strtok(cp, sep);
//打印出:zhengbo
printf("%s\n", ret);
//打印helloworld,這里的NULL指針表示一種狀態(tài),NULL指針記錄了'h'的地址
ret = strtok(NULL, sep);
printf("%s\n", ret);
//打印com,這里NULL指針記錄了'c'的地址
ret = strtok(NULL, sep);
printf("%s\n", ret);
return 0;
}
輸出:
2、優(yōu)化:上面的代碼分割一個(gè)字符串就需要打印一次,其實(shí)這里可以寫個(gè)for循環(huán),來優(yōu)化下代碼:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
const char* sep = "@.";
char arr[] = "zhengbo@helloworld.com";
char cp[30] = { 0 };
//拷貝一份臨時(shí)數(shù)據(jù)
strcpy(cp,arr);
//切割出zhengbo@,并把@換為\0了,且把z字符的地址,返回給了ret。
char* ret = NULL;
//優(yōu)化部分
for (ret = strtok(cp, sep); ret != NULL; ret = strtok(NULL, sep))
{
printf("%s\n", ret);
}
return 0;
}
1.10、strerror()
返回錯(cuò)誤碼,所對(duì)應(yīng)的錯(cuò)誤信息。
//頭文件:<errno.h>
char* strerror (int errnum);
在C語言中,庫函數(shù)在執(zhí)行失敗的時(shí)候,都會(huì)設(shè)置錯(cuò)誤碼。
雖說設(shè)置的都有錯(cuò)誤碼,但是我們?cè)趺礃硬拍苤厘e(cuò)誤碼所對(duì)應(yīng)的錯(cuò)誤信息呢?
這個(gè)時(shí)候strerror()函數(shù)就起作用了。只需要把錯(cuò)誤碼傳參進(jìn)去,這個(gè)函數(shù)就會(huì)返回錯(cuò)誤碼所對(duì)應(yīng)錯(cuò)誤信息字符串的首字符地址。
1、代碼演示:
//在X86平臺(tái)上運(yùn)行
#include <stdio.h>
#include <errno.h>
int main()
{
printf("%s\n", strerror(0));
printf("%s\n", strerror(1));
printf("%s\n", strerror(2));
printf("%s\n", strerror(3));
return 0;
}
輸出:
2、情景演示
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <errno.h>
int main()
{
//使用fopen()表示打開一個(gè)文件,并且r表示以只讀的方式進(jìn)行。
//如果打開成功會(huì)返回一個(gè)指針,如果打開失敗會(huì)返回NULL指針。
//現(xiàn)在本地沒有test.txt文件,所以會(huì)打開文件失敗,返回NULL指針。
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
//errno是C語言中設(shè)置一個(gè)全局變量,用來專門存放錯(cuò)誤碼的。
printf("%s\n", strerror(errno));
return 1;
}
return 0;
}
輸出:
2、字符分類函數(shù)
函數(shù) | 如果它的參數(shù)符合下列條件就返回真 |
---|---|
iscntrl | 任何控制字符 |
isspace <ctype.h> | 空白字符:空格’ ‘,換頁’\f’,換行’\n’,回車’\r’,制表符’\t’,垂直制表符’\v’ |
isdigit <ctype.h> | 十進(jìn)制數(shù)字0~9 |
isxdigit | 十六進(jìn)制數(shù)字,包括所有十進(jìn)制數(shù)字,小寫字母af,大寫字母AF |
islower | 小寫字母a-z |
isupper | 大寫字母A-Z |
isalpha | 字母az或AZ |
isalnum | 字母或數(shù)字,az、AZ、0~9 |
ispunct | 標(biāo)點(diǎn)符號(hào),任何不屬于數(shù)字或字母的圖形字符(可打?。?/td> |
isgraph | 任何圖形字符 |
isprint | 任何可打印字符,包括圖形字符和空白字符 |
3、字符轉(zhuǎn)換函數(shù)
字符轉(zhuǎn)換:
1、tolower()-------------將大寫字母轉(zhuǎn)為小寫
int tolower(int c); //將大寫字母轉(zhuǎn)為小寫,如果傳參數(shù)表示大寫字母,給什么值,輸出什么值。
代碼演示:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <ctype.h>
int main()
{
printf("%c\n", tolower('A'));
return 0;
}
輸出:
2、toupper()----------------將小寫字母轉(zhuǎn)為大寫
int toupper(int c); //將小寫字母轉(zhuǎn)為大寫,如果傳參數(shù)表示小寫字母,給什么值,輸出什么值。
代碼演示:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <ctype.h>
int main()
{
printf("%c\n", toupper('g'));
return 0;
}
輸出:
4、內(nèi)存操作函數(shù)
4.1、memcpy函數(shù)—內(nèi)存拷貝(不能用來拷貝重疊內(nèi)存)
void* memcpy (void* destination, const void* source, size_t num);
- 函數(shù)memcpy從source的位置開始向后復(fù)制num個(gè)__字節(jié)__的數(shù)據(jù)到destination的內(nèi)存位置。
- 這個(gè)函數(shù)在遇到’\0’的時(shí)候并不會(huì)停下來。
- 如果source和destination有任何的重疊,復(fù)制的結(jié)果都是未定義的。
上面講到字符函數(shù)也有兩個(gè)拷貝:strcpy、strncpy。
但是這兩個(gè)庫函數(shù)都是指針字符串進(jìn)行拷貝的。
那現(xiàn)在有兩個(gè)整型數(shù)組,如何拷貝呢?
比如:
- int arr1[] = {1,2,3,4,5,6};
- int arr2[10] = {0};
這個(gè)時(shí)候就需要使用memcpy()庫函數(shù)了。
在介紹這個(gè)庫函數(shù)前,先來思考一下這個(gè)庫函數(shù)誕生的原因:如果需要拷貝字符類型的數(shù)據(jù)用到了strcpy、strncpy函數(shù),那如果需要拷貝整型數(shù)據(jù)的呢?需要產(chǎn)生一個(gè)專用于整型拷貝的庫函數(shù)嗎?如果需要拷貝浮點(diǎn)型呢?如果需要拷貝結(jié)構(gòu)體呢?不可能說都會(huì)產(chǎn)生一個(gè)對(duì)應(yīng)的拷貝庫函數(shù)。
而是說直接用一個(gè)memcpy()函數(shù),這個(gè)函數(shù)是直接對(duì)內(nèi)存進(jìn)行操作的,它拷貝的是內(nèi)存塊里面的數(shù)據(jù)。而無論是字符還是整形,或者是浮點(diǎn)型,再或者是結(jié)構(gòu)體。它們的數(shù)據(jù)都是存放在內(nèi)存中的。所以說可以直接用memcpy()函數(shù)進(jìn)行統(tǒng)一拷貝操作。
1、參數(shù)介紹:
//頭文件 <string.h>
void * memcpy ( void * destination, const void * source, size_t num );
- destination目標(biāo)地址
- source 源地址
- 參數(shù)num的單位是字節(jié)。
2、代碼演示:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7 };
int arr2[10] = { 0 };
//因?yàn)橐粋€(gè)整型是4個(gè)字節(jié),arr1里面有7個(gè)整型數(shù)字,所以是28個(gè)字節(jié),
//memcpy的三個(gè)參數(shù)num的單位是字節(jié),所以應(yīng)傳參28
//將arr1的數(shù)據(jù)拷貝到arr2中
memcpy(arr2, arr1, 28);
return 0;
}
調(diào)試查看:
3、模擬實(shí)現(xiàn)memcpy()函數(shù)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src);
//用于返回目標(biāo)地址。
void* ret = dest;
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7 };
int arr2[10] = { 0 };
//因?yàn)橐粋€(gè)整型是4個(gè)字節(jié),arr1里面有7個(gè)整型數(shù)字,所以是28個(gè)字節(jié),
//memcpy的三個(gè)參數(shù)num的單位是字節(jié),所以應(yīng)傳參28
my_memcpy(arr2, arr1, 28);
return 0;
}
4.2、memmove函數(shù)------內(nèi)存拷貝(可以用來重疊內(nèi)存之間的拷貝)
memcpy函數(shù)和memmove函數(shù)基本功能大致一樣,但是memmove有個(gè)比memcpy強(qiáng)大的小功能:
1、memcpy函數(shù)是不能用來處理重疊的內(nèi)存之間的數(shù)據(jù)拷貝。
2、memmove函數(shù)是可以處理重疊內(nèi)存之間的數(shù)據(jù)拷貝的。
3、 memcpy只是memmove的一個(gè)子集。
memmove函數(shù)的參數(shù)和memmove函數(shù)的參數(shù)是一樣的:
//頭文件 <string.h>
void * memmove ( void * destination, const void * source, size_t num );
既然參數(shù)一樣,那兩個(gè)函數(shù)的用法也是一樣的。
假如如下是數(shù)組arr1重疊部分:
下面來實(shí)現(xiàn)內(nèi)存重疊的代碼演示:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1, arr1 + 2, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
輸出:
4.3、memcmp—內(nèi)存比較
//頭文件 <string.h>
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
- num參數(shù)是字節(jié)。
- 比較從ptr1和ptr2指針開始的num個(gè)__字節(jié)__。
- 返回值如下:
- ptr1內(nèi)存塊中存儲(chǔ)的數(shù)據(jù)比ptr1內(nèi)存塊中存儲(chǔ)的數(shù)據(jù)大,就返回>0的值
- ptr1內(nèi)存塊中存儲(chǔ)的數(shù)據(jù)比ptr1內(nèi)存塊中存儲(chǔ)的數(shù)據(jù)小,就返回<0的值
- 如果將所指定的num字節(jié)全部比較完畢后,還是一樣的大小,會(huì)返回0.
1、代碼演示:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 1,3,2 };
//這里num為12,表示比較12個(gè)字節(jié)的內(nèi)容,一個(gè)int占用4個(gè)字節(jié),所以一共比較3個(gè)數(shù)字。
int ret = memcmp(arr1, arr2, 12);
printf("%d\n", ret);
return 0;
}
輸出:
分析:是如何比較出來大小的呢?
首先arr1中的數(shù)字在內(nèi)存中是這樣存儲(chǔ)的:
01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00
然后arr2中的數(shù)字在內(nèi)存中是這樣存儲(chǔ)的:
01 00 00 00 03 00 00 00 02 00 00 00
因?yàn)槲覀冎付酥槐容^12個(gè)字節(jié)的數(shù)據(jù),所以兩個(gè)數(shù)組開始從頭比較,直到比較到第五個(gè)字節(jié)(如下圖):
arr1的數(shù)據(jù)是02,arr2的數(shù)據(jù)是03。這樣一來比較大小就有了結(jié)果。是arr2大。所以返回-1<0的值。
4.4、memset—內(nèi)存設(shè)置
void * memset ( void * ptr, int value, size_t num );
參數(shù)說明:
- ptr:需要填充的內(nèi)存塊的地址。
- value:要被填充的內(nèi)容,(看著是int類型的,其實(shí)可以傳char類型的數(shù)據(jù),因?yàn)樽址趦?nèi)存中存儲(chǔ)也是按照ASCII值存儲(chǔ)的)。
- num:要被填充多少個(gè)字節(jié)。
1、代碼演示:
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "hello bbo";
//表示,從整個(gè)字符數(shù)組首字符開始,一直填充5個(gè)'x'字符。
memset(arr, 'x', 5);
printf("%s\n", arr);
return 0;
}
輸出:文章來源:http://www.zghlxwxcb.cn/news/detail-522008.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-522008.html
到了這里,關(guān)于C語言進(jìn)階---字符串+內(nèi)存函數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!