南京建設(shè)工程管理局網(wǎng)站游戲代理怎么找渠道
🍕博客主頁:?自信不孤單
🍬文章專欄:C語言
🍚代碼倉庫:破浪曉夢
🍭歡迎關(guān)注:歡迎大家點(diǎn)贊收藏+關(guān)注
字符串函數(shù)和內(nèi)存函數(shù)
文章目錄
- 字符串函數(shù)和內(nèi)存函數(shù)
- 前言
- 1. 字符串函數(shù)介紹
- 1.1 strlen函數(shù)
- 1.2 strcpy函數(shù)
- 1.3 strcat函數(shù)
- 1.4 strcmp函數(shù)
- 1.5 strncpy函數(shù)
- 1.6 strncat函數(shù)
- 1.7 strncmp函數(shù)
- 1.8 strstr函數(shù)
- 1.9 strtok函數(shù)
- 1.10 strerror函數(shù)
- 1.11 字符分類函數(shù)
- 2. 內(nèi)存函數(shù)的介紹
- 2.1 memcpy
- 2.2 memmove
- 2.3 memcmp
- 2.4 memset
- 3. 模擬庫函數(shù)的實(shí)現(xiàn)
- 3.1 模擬strlen函數(shù)
- 3.2 模擬strcpy函數(shù)
- 3.3 模擬strcat函數(shù)
- 3.4 模擬strcmp函數(shù)
- 3.5 模擬strstr函數(shù)
- 3.6 模擬memcpy函數(shù)
- 3.7 模擬memmove函數(shù)
前言
C語言中對(duì)字符和字符串的處理很是頻繁,但是C語言本身是沒有字符串類型的,字符串通常放在常量字符串中或者字符數(shù)組中。其中字符串常量適用于那些對(duì)它不做修改的字符串函數(shù)。
1. 字符串函數(shù)介紹
字符串函數(shù)需要包含頭文件
#include <string.h>
1.1 strlen函數(shù)
size_t strlen(const char* str);
strlen函數(shù)(string length)的作用是計(jì)算返回字符串中結(jié)束標(biāo)識(shí)符
'\0'
之前出現(xiàn)的的字符個(gè)數(shù),因此,strlen函數(shù)所處理的字符串必須是以結(jié)束標(biāo)識(shí)符'\0'
結(jié)尾的字符串。其返回值類型為size_t 類型,該類型為無符號(hào)類型。
strlen函數(shù)的應(yīng)用:
#include <stdio.h>
int main()
{const char* str1 = "abcdef";const char* str2 = "bbb";if (strlen(str2) - strlen(str1) > 0){printf("str2>str1\n");}else{printf("srt1>str2\n");}return 0;
}
輸出結(jié)果為:
str1>str2
這里strlen(str2)的返回值為6,strlen(str1)的返回值為3,但為什么輸出的是str1>str2呢?
由于strlen()的返回值是無符號(hào)類型,故兩個(gè)無符號(hào)數(shù)相減也是無符號(hào)數(shù),相減后的無符號(hào)數(shù)大于0,所以輸出str1>str2。要想使用相減來比較字符串長度的大小,可以強(qiáng)制類型轉(zhuǎn)換為有符號(hào)整型。
如:
#include<stdio.h>
#include<string.h>
int main()
{const char* str1 = "abcdef";const char* str2 = "bbb";if ((int)strlen(str2) - (int)strlen(str1) > 0){printf("str2 > str1\n");}else{printf("srt1 < str2\n");}return 0;
}
1.2 strcpy函數(shù)
char* strcpy(char* destination, const char* source);
strcpy函數(shù)(string copy)的作用是,可以將字符串從源地址復(fù)制至目的地址,并返回目的空間的起始地址,并且它會(huì)將源地址內(nèi)的結(jié)束標(biāo)識(shí)符
'\0'
一并拷貝過去,因此源地址必須以'\0'
結(jié)尾,且目的地址也將以'\0'
結(jié)尾,通俗來講就是用來實(shí)現(xiàn)字符串的復(fù)制和拷貝。并且,因?yàn)槠渥饔脼榭截愖址?#xff0c;因此目標(biāo)地址內(nèi)的空間必須足夠大,要有足夠的空間容納下源地址內(nèi)的字符串,同時(shí)目的地址的空間必須是可修改的。
strcpy函數(shù)的應(yīng)用:
#include <stdio.h>
#include <string.h>
int main()
{char arr1[20];char arr2[15] = "hello world";printf("%s", strcpy(arr1, arr2));return 0;
}
輸出結(jié)果為:
hello world
這里要特別注意的是strcpy函數(shù)返回的是目標(biāo)空間的起始地址,該函數(shù)設(shè)置返回值類型的目的是為了實(shí)現(xiàn)鏈?zhǔn)皆L問。
1.3 strcat函數(shù)
char* strcat(char* destination, const char* source);
strcat函數(shù)(string catenate)的作用是,將源地址的字符串追加補(bǔ)充至目的地址處,并返回目的空間的首地址。與字符串拷貝函數(shù)相同,它在進(jìn)行補(bǔ)充追加時(shí)是從目的地址的結(jié)束標(biāo)識(shí)符處
'\0'
開始追加的,追加至源地址的結(jié)束標(biāo)識(shí)符處停止。且它同樣要求目標(biāo)地址內(nèi)的空間必須足夠大,要有足夠的空間容納下源地址內(nèi)的字符串,同時(shí)目的地址的空間必須是可修改的。
strcat函數(shù)的應(yīng)用:
#include <stdio.h>
#include <string.h>
int main()
{char arr1[20] = "hello";char arr2[10] = " world";printf("%s\n", strcat(arr1, arr2));return 0;
}
輸出結(jié)果為:
hello world
1.4 strcmp函數(shù)
int strcmp(const char* str1, const char* str2);
strcmp函數(shù)(string compare)的作用為按照順序依次比較兩字符串對(duì)應(yīng)位置字符的ASCII碼值(注意不是比較兩字符串的長度),直到結(jié)束標(biāo)識(shí)符
'\0'
或?qū)?yīng)位置的字符不同。若比較至結(jié)束標(biāo)識(shí)符都沒有不同則兩字符串相等,若兩字符串對(duì)應(yīng)位置字符有不同,對(duì)應(yīng)位置上字符ASCII碼值小的字符串小于另一個(gè)字符串。標(biāo)準(zhǔn)規(guī)定:
第一個(gè)字符串大于第二個(gè)字符串,則返回大于0的數(shù)字
第一個(gè)字符串等于第二個(gè)字符串,則返回0
第一個(gè)字符串小于第二個(gè)字符串,則返回小于0的數(shù)字
strcmp函數(shù)的應(yīng)用:
#include<stdio.h>
#include<string.h>
int main()
{const char arr1[] = "abcd";const char arr2[] = "abz";int ret = strcmp(arr1, arr2);if (ret > 0){printf("arr1 > arr2\n");}else if (ret == 0){printf("arr1 = arr2\n");}else{printf("arr1 < arr2\n");}return 0;
}
輸出結(jié)果為:
arr1 < arr2
1.5 strncpy函數(shù)
char* strncpy(char* destination, const char* source, size_t num);
strncpy函數(shù)(string number copy)的作用為將指定長度的字符串復(fù)制到字符數(shù)組中,即表示把源地址中字符串開始的前n個(gè)字符拷貝到目的地址中,并返回目的空間的首地址。與strcpy相同,它同樣會(huì)將源地址內(nèi)的結(jié)束標(biāo)識(shí)符
'\0'
一并拷貝過去,因此源地址必須以'\0'
結(jié)尾,且目的地址也將以'\0'
結(jié)尾。并且,因?yàn)槠渥饔脼榭截愖址?#xff0c;因此目標(biāo)地址內(nèi)的空間必須足夠大,要有足夠的空間容納下源地址內(nèi)的字符串,同時(shí)目的地址的空間必須是可修改的。
strncpy函數(shù)的應(yīng)用:
#include <stdio.h>
#include <string.h>
int main()
{char arr1[20] = "xxxxxxxxxxxxxx";char arr2[12] = "hello world";printf("%s", strncpy(arr1, arr2, 10));return 0;
}
輸出結(jié)果為:
hello worlxxxx
1.6 strncat函數(shù)
char* strncat(char* destination, const char* source, size_t num);
strncat函數(shù)(string num catenate)的作用為從源地址處將指定長度的字符串追加補(bǔ)充到目的地址中與strcat函數(shù)類似,它在進(jìn)行補(bǔ)充追加時(shí)也是從目的地址的結(jié)束標(biāo)識(shí)符處
'\0'
開始追加的,不同的是追加至參數(shù)(單位是字節(jié))限制的字符數(shù)處停止。但它同樣要求目標(biāo)地址內(nèi)的空間必須足夠大,要有足夠的空間容納下補(bǔ)充的字符串 ,同時(shí)目的地址的空間必須是可修改的。返回值為目的空間的首地址
strncat函數(shù)的應(yīng)用:
#include <stdio.h>
#include <string.h>
int main()
{char arr1[20] = "hello";char arr2[10] = " world";printf("%s\n", strncat(arr1, arr2, 4));return 0;
}
輸出結(jié)果為:
hello wor
1.7 strncmp函數(shù)
int strncmp(const char* str1, const char* str2, size_t num);
strncmp函數(shù)(string number compare)的作用為有限制(單位是字節(jié))的按照順序依次比較兩字符串對(duì)應(yīng)位置字符的ASCII碼值(注意不是比較兩字符串的長度),直到參數(shù)限制位數(shù)位置上全部比較結(jié)束或?qū)?yīng)位置的字符不同。若參數(shù)限制位數(shù)位置上的字符都比較結(jié)束且都沒有不同則兩字符串相等,若兩字符串對(duì)應(yīng)位置字符有不同,對(duì)應(yīng)位置上字符ASCII碼值小的字符串小于另一個(gè)字符串。
標(biāo)準(zhǔn)規(guī)定:
第一個(gè)字符串大于第二個(gè)字符串,則返回大于0的數(shù)字
第一個(gè)字符串等于第二個(gè)字符串,則返回0
第一個(gè)字符串小于第二個(gè)字符串,則返回小于0的數(shù)字
strncmp函數(shù)的應(yīng)用:
#include<stdio.h>
#include<string.h>
int main()
{const char arr1[] = "abcd";const char arr2[] = "abz";int ret = strncmp(arr1, arr2, 2);if (ret > 0){printf("arr1 > arr2\n");}else if (ret == 0){printf("arr1 = arr2\n");}else{printf("arr1 < arr2\n");}return 0;
}
輸出結(jié)果為:
arr1 = arr2
1.8 strstr函數(shù)
char* strstr(const char* str1, const char* str2);
strstr函數(shù)(string string)的作用為從一個(gè)字符串中尋找其字串,通俗來講就是從一個(gè)字符串中尋找另一個(gè)字符串。若找到目標(biāo)字串則返回指向目標(biāo)字串的指針,若沒有找到目標(biāo)字串則返回空指針。
strstr函數(shù)的應(yīng)用:
#include<stdio.h>
#include<string.h>
int main()
{const char arr1[] = "abcdefg";const char arr2[] = "cde";char* ret = strstr(arr1, arr2);//從ar1中尋找arr2if (ret == NULL){printf("找不到該字符串!\n");}else{printf("成功找到該字符串\"%s\"!\n", ret);}return 0;
}
輸出結(jié)果為:
成功找到該字符串"cdefg"!
1.9 strtok函數(shù)
char* strtok(char* str, const char* sep);
strtok函數(shù)(string token)的作用為將字符串分解為一組字符串。該函數(shù)有兩個(gè)數(shù)組作為參數(shù),它的實(shí)際作用便是將其中一個(gè)數(shù)組為分割數(shù)組,在另一個(gè)數(shù)組中尋找這些分割符,并在分割符處將這個(gè)數(shù)組內(nèi)的字符串加上結(jié)束標(biāo)識(shí)符
'\0'
,將其分割成一組(多個(gè))字符串。若第一個(gè)參數(shù)不為NULL,將找到字符數(shù)組中的第一個(gè)標(biāo)記并保存它在字符串中的位置;若第一個(gè)參數(shù)為NULL,將在同一個(gè)字符串中被保存的位置開始,查找下一個(gè)標(biāo)記。返回值:該函數(shù)返回被分解的第一個(gè)子字符串,如果沒有可檢索的字符串,則返回一個(gè)空指針。
strtok函數(shù)的應(yīng)用:
#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = "1592272237@qq.com";char arr2[30] = { 0 };strcpy(arr2, arr1);const char* arr3 = "@.";printf("賬號(hào):%s\n", strtok(arr2, arr3));//找到第一個(gè)標(biāo)記停止printf("域名前綴:%s\n", strtok(NULL, arr3));//從保存好的位置開始往后找printf("域名后綴:%s\n", strtok(NULL, arr3));//從保存好的位置開始往后找return 0;
}
輸出結(jié)果為:
賬號(hào):1592272237
域名前綴:qq
域名后綴:com
- strtok函數(shù)是會(huì)對(duì)數(shù)組本身進(jìn)行操作的,所以我們?yōu)榱吮Wo(hù)原始數(shù)據(jù),在定義并初始化好字符數(shù)組之后,又定義了一個(gè)新的數(shù)組并將原始數(shù)據(jù)拷貝過去,作為臨時(shí)拷貝供我們進(jìn)行操作。
- 接著我們定義并初始化了分割符數(shù)組,函數(shù)將根據(jù)分割符數(shù)組arr3對(duì)臨時(shí)拷貝arr2進(jìn)行分割。第一次執(zhí)行函數(shù)時(shí)之前沒有標(biāo)記,于是直接進(jìn)行操作找到第一個(gè)標(biāo)記并分割打印。
- 此時(shí)就已經(jīng)存在標(biāo)記了,再連續(xù)兩次找到前一次執(zhí)行作下的標(biāo)記按照分割符將數(shù)組分割完畢并打印。
我們可以將上述代碼優(yōu)化為:
#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = "1592272237@qq.com";char arr2[30] = { 0 };strcpy(arr2, arr1);const char* arr3 = "@.";char* str = NULL;for (str = strtok(arr2, arr3); str != NULL; str = strtok(NULL, arr3)){printf("%s\n", str);}return 0;
}
1.10 strerror函數(shù)
char* strerror(int errnum);
strerror函數(shù)(string error)的作用為返回錯(cuò)誤碼對(duì)應(yīng)的信息。即根據(jù)接收到的錯(cuò)誤碼(錯(cuò)誤碼errno為全局變量),返回錯(cuò)誤原因的詳細(xì)信息。
strerror函數(shù)的應(yīng)用:
#include<stdio.h>
#include<string.h>
int main()
{int i = 0;for (i = 0; i <= 4; i++){printf("錯(cuò)誤原因?yàn)?#xff1a;%s\n", strerror(i));}return 0;
}
輸出結(jié)果為:
1.11 字符分類函數(shù)
函數(shù) | 如果他的參數(shù)符合下列條件就返回真 |
---|---|
iscntrl | 任何控制字符 |
isspace | 空白字符:空格' ' ,換頁'\f' ,換行'\n' ,回車'\r' ,制表符'\t' 或者垂直制表符'\v' |
isdigit | 十進(jìn)制數(shù)字0~9 |
isxdigi | 十六進(jìn)制數(shù)字,包括所有十進(jìn)制數(shù)字,小寫字母a~f ,大寫字母A~F |
islower | 小寫字母a~z |
isupper | 大寫字母A~Z |
isalpha | 字母a~z 或A~Z |
isalnum | 字母或者數(shù)字,a~z ,A~Z ,0~9 |
ispunct | 標(biāo)點(diǎn)符號(hào),任何不屬于數(shù)字或者字母的圖形字符(可打印) |
isgraph | 任何圖形字符 |
isprint | 任何可打印字符,包括圖形字符和空白字符 |
字符轉(zhuǎn)換:
int tolower(int c);
int toupper(int c);
舉個(gè)栗子:
此代碼的作用是將大寫字符轉(zhuǎn)換為小寫字符
/* isupper example */
#include <stdio.h>
#include <ctype.h>
int main()
{int i = 0;char str[] = "Test String.\n";char c;while (str[i]){c = str[i];if (isupper(c))c = tolower(c);putchar(c);i++;}return 0;
}
輸出結(jié)果為:
test string.
2. 內(nèi)存函數(shù)的介紹
2.1 memcpy
void* memcpy(void* destination, const void* source, size_t num);
memcpy函數(shù)(memory copy)的作用為從源內(nèi)存空間向目的內(nèi)存空間拷貝限制數(shù)量(單位是字節(jié))的數(shù)據(jù)。它與strcpy函數(shù)類似,作用均為拷貝數(shù)據(jù),不同的是strcpy僅僅只操作字符串故會(huì)在結(jié)束標(biāo)識(shí)符
'\0'
處停止,而memcpy函數(shù)操作的是內(nèi)存,內(nèi)存中的數(shù)據(jù)是相鄰的,故不會(huì)在結(jié)束標(biāo)識(shí)符處停止。
返回值:該函數(shù)返回一個(gè)指向目標(biāo)存儲(chǔ)區(qū)destination的指針。
memcpy函數(shù)的應(yīng)用:
#include <stdio.h>
#include <string.h>
struct {char name[40];int age;
} person, person_copy;
int main()
{char myname[] = "Pierre de Fermat";/* using memcpy to copy string: */memcpy(person.name, myname, strlen(myname) + 1);person.age = 46;/* using memcpy to copy structure: */memcpy(&person_copy, &person, sizeof(person));printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);return 0;
}
輸出結(jié)果為:
注:如果源內(nèi)存空間和目標(biāo)內(nèi)存空間有重疊時(shí),memcpy是無法保證內(nèi)存復(fù)制的正確性的。
2.2 memmove
void* memmove(void* destination, const void* source, size_t num);
memmove函數(shù)(memory move)和memcpy函數(shù)都是內(nèi)存復(fù)制函數(shù),他們?cè)谟梅ㄉ弦惨粯?。但是如果目?biāo)區(qū)域和源區(qū)域有重疊的話,memmove是比memcpy更安全的方法,memmove能夠保證源串在被覆蓋之前將重疊區(qū)域的字節(jié)拷貝到目標(biāo)區(qū)域中,復(fù)制后源區(qū)域的內(nèi)容會(huì)被更改。如果目標(biāo)區(qū)域與源區(qū)域沒有重疊,則和memcpy函數(shù)功能是完全相同的。
memmove函數(shù)的應(yīng)用:
#include <stdio.h>
#include <string.h>
int main()
{char str[] = "memmove can be very useful......";memmove(str + 20, str + 15, 11);puts(str);return 0;
}
輸出結(jié)果為:
2.3 memcmp
int memcmp(const void* ptr1,const void* ptr2,size_t num);
memcmp函數(shù)(memory compare)的作用與 strcmp 函數(shù)的作用類似,不過 memcmp 函數(shù)是從內(nèi)存的角度以字節(jié)為單位進(jìn)行處理,故 memcmp 函數(shù)同樣需要第三個(gè)參數(shù)進(jìn)行限制,而不會(huì)在結(jié)束標(biāo)識(shí)符 ’ \0 ’ 處停止比較。
memcmp函數(shù)的應(yīng)用:
#include <stdio.h>
#include <string.h>
int main()
{char buffer1[] = "DWgaOtP12df0";char buffer2[] = "DWGAOTP12DF0";int n;n = memcmp(buffer1, buffer2, sizeof(buffer1));if (n > 0) printf("'%s' is greater than '%s'.\n", buffer1, buffer2);else if (n < 0) printf("'%s' is less than '%s'.\n", buffer1, buffer2);else printf("'%s' is the same as '%s'.\n", buffer1, buffer2);return 0;
}
輸出結(jié)果為:
2.4 memset
void* memset(void* dest, int c, size_t count);
memset函數(shù)(memory set)的作用是復(fù)制字符c(一個(gè)無符號(hào)字符)到參數(shù)dest所指向的字符串的前n個(gè)字符。
返回值是:該值返回一個(gè)指向存儲(chǔ)區(qū)dest的指針。
memset函數(shù)的應(yīng)用:
#include <stdio.h>
#include <string.h>int main()
{char str[50];strcpy(str, "This is string.h library function");puts(str);memset(str, '$', 7);puts(str);return(0);
}
輸出結(jié)果為:
3. 模擬庫函數(shù)的實(shí)現(xiàn)
3.1 模擬strlen函數(shù)
//1.計(jì)數(shù)器
size_t my_strlen1(const char* str)
{assert(str);int count = 0;while (*str){count++;str++;}return count;
}//2.遞歸調(diào)用
size_t my_strlen2(const char* str)
{assert(str);if (*str)return sim_strlen2(str + 1) + 1;elsereturn 0;
}//3.指針相減
size_t my_strlen3(const char* str)
{assert(str);const char* p = str;while (*p++){;}return (p - str - 1);
}
3.2 模擬strcpy函數(shù)
char* my_strcpy(char* destination, const char* source)
{char* ret = destination;assert(destination && source);while (*destination++ = *source++){;}return ret;
}
3.3 模擬strcat函數(shù)
char* my_strcat(char* destination, const char* source)
{char* ret = destination;while (*destination){destination++;}while (*destination++ = *source++){;}return ret;
}
3.4 模擬strcmp函數(shù)
int my_strcmp(const char* s1, const char* s2)
{assert(s1 && s2);while (*s1 == *s2 && *s1 != '\0' && *s2 != '\0'){s1++;s2++;}return *s1 - *s2;
}
3.5 模擬strstr函數(shù)
char* my_strstr(const char* s1, const char* s2)
{assert(s1 && s2);if (*s2 == '\0'){return (char*)s1;}const char* p1 = s1;const char* p2 = s2;const char* start = s1; //用于記錄開始比較的位置while (*p1){ //以防主串可能小于子串,循環(huán)條件不能只為*p1 == *p2while (*p1 == *p2 && *p1 != '\0' && *p2 != '\0') //單字符匹配成功則匹配下一個(gè)字符{p1++;p2++;}if (*p2 == '\0') //匹配成功,返回開始比較的位置return (char*)start;//單趟匹配失敗,子串退回到第一個(gè)字符,進(jìn)行從主串的下一個(gè)字符開始與主串匹配p1 = start + 1;start = p1;p2 = s2;}return NULL; //跳出外層循環(huán)說明匹配失敗
}
3.6 模擬memcpy函數(shù)
void* my_memcpy(void* dest, const void* src, size_t nums)
{assert(src && dest);int i = 0;for (i = 0; i < nums; i++){*((char*)dest + i) = *((char*)src + i);}return (char*)dest;
}
3.7 模擬memmove函數(shù)
void* my_memmove(void* dest, const void* src, size_t nums)
{assert(src && dest);void* ret = dest;int i = 0;if (dest < src)//從前向后{for (i = 0; i < nums; i++){*((char*)dest + i) = *((char*)src + i);}}else//從后向前{for (i = nums - 1; i >= 0; i--){*((char*)dest + i) = *((char*)src + i);}}return ret;
}
到此,關(guān)于《字符串函數(shù)和內(nèi)存函數(shù)》的內(nèi)容就結(jié)束了
感謝大家的觀看
創(chuàng)作不易,如果對(duì)您有幫助,請(qǐng)一鍵三連
您的支持就是我創(chuàng)作最大的動(dòng)力!!!