C語(yǔ)言進(jìn)階教程之字符函數(shù)&字符串函數(shù)
1、strlen
功能:求字符串長(zhǎng)度
#include<stdio.h> #include<string.h> int main() { printf("%d\n", strlen("abcdef"));//6 return 0; }
注意事項(xiàng):
- 字符串以 '\0' 作為結(jié)束標(biāo)志,strlen函數(shù)返回的是在字符串中 '\0' 前面出現(xiàn)的字符個(gè)數(shù)(不包含 '\0' )。
- 參數(shù)指向的字符串必須要以 '\0' 結(jié)束。
- 注意函數(shù)的返回值為size_t,是無(wú)符號(hào)的( 易錯(cuò) )
注:
#include<stdio.h> #include<string.h> int main() { if (strlen("abc") - strlen("abcdef") > 0) printf(">"); else printf("<="); return 0; }
解析:
size_t strlen ( const char * str );
- strlen庫(kù)函數(shù)的返回類型是size_t,是無(wú)符號(hào)數(shù)。
- sizeof -- 操作符 -- 計(jì)算大小的。而size_t本質(zhì):unsigned int,size_t是專門(mén)為sizeof的返回類型設(shè)計(jì)的 。既然size_t是無(wú)符號(hào)整型的,所以值恒>0
- 而上述代碼中,abc的長(zhǎng)度是3,abcdef的長(zhǎng)度是6。3-6的值是把-3當(dāng)成一個(gè)無(wú)符號(hào)數(shù),補(bǔ)碼轉(zhuǎn)原碼再打印就是一個(gè)非常大的正數(shù)。所以>
1.1、三種模擬實(shí)現(xiàn)
法一:計(jì)數(shù)器法:
#include <stdio.h> #include<assert.h> int my_strlen(const char* str) { assert(str); int count = 0; while (*str != '\0')//判斷字符串是否結(jié)束 { count++; str++; } return count; } int main() { int len = my_strlen("abcdef"); printf("%d\n", len); // 6 return 0; }
法二:遞歸法:
#include<stdio.h> int my_strlen(char* s) { if (*s == '\0') return 0; else return 1 + my_strlen(s + 1); } int main() { char arr[] = "abcdef"; int len = my_strlen(arr); printf("%d\n", len); // 6 return 0; }
法三:指針-指針:
#include<stdio.h> int my_strlen(char* s) { char* p = s; while (*p != '\0') p++; return p - s; } int main() { char arr[] = "abcdef"; int len = my_strlen(arr); //6 printf("%d\n", len); return 0; }
2、長(zhǎng)度不受限制的字符串函數(shù)
2.1、strcpy
功能:拷貝字符串
#include<stdio.h> #include<string.h> int main() { char arr1[] = "abcdef"; //char arr1[] = { 'a','b','c','e','f','\0' }; char arr2[20] = "xxxxxxxxxxx"; strcpy(arr2, arr1); //此時(shí)arr2="abcdef\0xxxx" printf("%s\n", arr2); // abcdef return 0; }
strcpy函數(shù)的第一個(gè)參數(shù)放目的地arr2,第二個(gè)參數(shù)放源字符串?dāng)?shù)據(jù)arr1。把a(bǔ)rr1的內(nèi)容拷到arr2上。
注意事項(xiàng):
- 源字符串必須以 '\0' 結(jié)束。
- 會(huì)將源字符串中的 '\0' 拷貝到目標(biāo)空間。
- 目標(biāo)空間必須足夠大,以確保能存放源字符串。
- 目標(biāo)空間必須可變。
2.1.1、模擬實(shí)現(xiàn)
#include<stdio.h> #include<assert.h> char* my_strcpy(char* dest, const char* src) { char* ret = dest; assert(dest && src); while (*dest++ = *src++) { ; } return ret; } int main() { char arr1[] = {'a', 'b', 'c', 'd', 'e', 'f', '\0'}; char arr2[20] = "xxxxxxxxxxxx"; my_strcpy(arr2, arr1); printf("%s\n", arr2); // abcdef return 0; }
2.2、strcat
功能:連接字符串
#include<stdio.h> #include<string.h> int main() { char arr1[30] = "hello"; char arr2[] = "world";// {'w', 'o', 'r', 'l', 'd', '\0'}; strcat(arr1, arr2); printf("%s\n", arr1);// helloworld return 0; }
把a(bǔ)rr2的字符追加到arr1上去。
注意事項(xiàng):
- 源字符串必須以 '\0' 結(jié)束。
- 目標(biāo)空間必須有足夠的大,能容納下源字符串的內(nèi)容。
- 目標(biāo)空間必須可修改。
2.2.1、模擬實(shí)現(xiàn)
#include<stdio.h> #include<assert.h> char* my_strcat(char* dest, const char* src) { char* ret = dest; assert(dest && src); //1. 目標(biāo)空間中的\0 while (*dest) { dest++; } //2. 追加內(nèi)容到目標(biāo)空間 while (*dest++ = *src++) { ; } return ret; } int main() { char arr1[30] = "hello"; char arr2[] = "world";// {'w', 'o', 'r', 'l', 'd', '\0'}; printf("%s\n", my_strcat(arr1, arr2)); // helloworld return 0; }
2.3、strcmp
功能:字符串比較
strcmp是比較的是對(duì)應(yīng)位置上的字符ASCII大小,而不是字符串長(zhǎng)度。
#include<stdio.h> #include<string.h> int main() { char arr1[] = "abcdef"; char arr2[] = "bbq"; int ret = strcmp(arr1, arr2); printf("%d\n", ret); // -1 return 0; }
注意:
- 第一個(gè)字符串大于第二個(gè)字符串,則返回大于0的數(shù)字
- 第一個(gè)字符串等于第二個(gè)字符串,則返回0
- 第一個(gè)字符串小于第二個(gè)字符串,則返回小于0的數(shù)字
2.3.1、模擬實(shí)現(xiàn)
#include<stdio.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++; } return *str1 - *str2; /*if (*str1 > *str2) return 1; else return -1;*/ } int main() { char arr1[] = "abc"; char arr2[] = "abc"; int ret = my_strcmp(arr1, arr2); /*printf("%d\n", ret);*/ if (ret<0) { printf("arr1<arr2"); } else if (ret >0) { printf("arr1>arr2"); } else { printf("arr1==arr2"); } return 0; }
3、長(zhǎng)度受限制的字符串函數(shù)
3.1、strncpy
功能:拷貝指定元素個(gè)數(shù)的函數(shù)
#include<stdio.h> #include<string.h> int main() { char arr1[] = "xxxxxxxxxxxxxxxx"; char arr2[] = "hello bit"; strncpy(arr1, arr2, 5); printf("%s\n", arr1); //helloxxxxxxxxxxx }
- 此函數(shù)不受到 '\0' 的影響,拷貝num個(gè)字符從源字符串到目標(biāo)空間。
- 目標(biāo)空間必須有足夠的大,能容納下源字符串的內(nèi)容。
- 如果源字符串的長(zhǎng)度小于num,則拷貝完源字符串之后,在目標(biāo)的后邊追加0,直到num個(gè)。
如下:
int main() { char arr1[] = "xxxxxxxxxxxxxxxx"; char arr2[] = "he"; strncpy(arr1, arr2, 5); printf("%s\n", arr1); //he\0\0\0 ---》he }
3.1.1、模擬實(shí)現(xiàn)
#include<stdio.h> #include<assert.h> char* my_strncpy(char* dest, const char* str, size_t n) { assert(dest && str); char* ret = dest; while (n--) { *dest++ = *str++; } return ret; } int main() { char arr1[] = "xxxxxxxxxx"; char arr2[] = "abcde"; printf("%s\n", my_strncpy(arr1, arr2, 4)); // abcdxxxxxx return 0; }
3.2、strncat
- 功能:連接指定元素個(gè)數(shù)的字符串函數(shù)
- strncat從目標(biāo)字符串從左向右數(shù)到第一個(gè) '\0' 的位置開(kāi)始連接源指定字符串
#include<stdio.h> #include<string.h> int main() { char arr1[20] = "hello"; char arr2[] = "world"; printf("%s\n", strncat(arr1, arr2, 3)); //hellowor return 0; }
注意:
strncat追加后,會(huì)主動(dòng)在追加后放一個(gè) '\0' 進(jìn)去,確保其是個(gè)字符串。
3.2.1、模擬實(shí)現(xiàn)
#include<stdio.h> #include<assert.h> char* my_strncat(char* dest, const char* str, size_t n) { assert(dest && str); char* ret = dest; while (*dest) { dest++; } while (n--) { *dest++ = *str++; } *dest = '\0'; return ret; } int main() { char arr1[20] = "hello\0xxxxx"; char arr2[] = "bitxxxxx"; printf("%s\n", my_strncat(arr1, arr2, 3)); //hellobit return 0; }
3.3、strncmp
功能:實(shí)現(xiàn)指定位置的字符數(shù)比較函數(shù)
#include<stdio.h> #include<string.h> int main() { char arr1[] = "abcdef"; char arr2[] = "abcqqqqq"; printf("%d\n", strncmp(arr1, arr2, 4));//-1 printf("%d\n", strncmp(arr1, arr2, 3));//0 return 0; }
3.3.1、模擬實(shí)現(xiàn)
#include<stdio.h> #include<assert.h> int my_strncmp(char* dest, const char* str, size_t n) { int ret = 0; assert(dest && str); while (n && !(*dest - *str)) { n--; dest++; str++; } if (n && *dest - *str > 0) return 1; else if (n && *dest - *str < 0) return -1; return ret; } int main() { char arr1[] = "abcdef"; char arr2[] = "abcqqqqq"; printf("%d\n", my_strncmp(arr1, arr2, 3)); //0 return 0; }
4、字符串查找
4.1、strstr
功能:判斷一個(gè)字符串是否為另一字符串的子集,若是,返回從第一個(gè)相等一直到末尾
#include<stdio.h> #include<string.h> int main() { char arr1[] = "abbbcdef"; char arr2[] = "bbc"; char* ret = strstr(arr1, arr2); if (NULL == ret) printf("沒(méi)找到\n"); else printf("%s\n", ret); // bbcdef return 0; }
4.1.1、模擬實(shí)現(xiàn)
#include<stdio.h> #include<assert.h> char* my_strstr(const char* str, const char* substr) { const char* s1 = str; const char* s2 = substr; const char* cur = str; assert(str && substr); if (*substr == '\0') { return (char*)str; } while (*cur) { s1 = cur; s2 = substr; while (*s1 && *s2 && *s1 == *s2) { s1++; s2++; } if (*s2 == '\0') return (char*)cur; cur++; } return NULL; } int main() { char arr1[] = "abbbcdef"; char arr2[] = "bbcq"; char* ret = my_strstr(arr1, arr2); if (NULL == ret) printf("沒(méi)找到\n"); //沒(méi)找到 else printf("%s\n", ret); return 0; }
4.2、strtok
功能:把一串字符串按照分隔符來(lái)切割
注意:
char * strtok ( char * str, const char * sep );
- 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 指針。
#include <stdio.h> #include <string.h> int main() { const char* p = "@.#,"; char arr[] = "en@yu.xia#sh,ge"; char buf[50] = { 0 };// "en@yu.xia#sh,ge"; strcpy(buf, arr); /*char* str = NULL; for (str = strtok(buf, p); str != NULL; str=strtok(NULL, p)) { printf("%s\n", str); }*/ char* str = strtok(buf, p); printf("%s\n", str); str = strtok(NULL, p);//en printf("%s\n", str); str = strtok(NULL, p);//yu printf("%s\n", str); str = strtok(NULL, p);//sh printf("%s\n", str); str = strtok(NULL, p);//ge printf("%s\n", str); //strtok - 開(kāi)始返回NULL return 0; }
5、錯(cuò)誤信息報(bào)告
5.1、strerror
功能:把錯(cuò)誤碼翻譯成錯(cuò)誤信息
C語(yǔ)言中‘,規(guī)定了一些信息,錯(cuò)誤碼 - 錯(cuò)誤信息
#include <stdio.h> #include <string.h> int main() { const char* p = "@.#,"; char arr[] = "en@yu.xia#sh,ge"; char buf[50] = { 0 };// "en@yu.xia#sh,ge"; strcpy(buf, arr); /*char* str = NULL; for (str = strtok(buf, p); str != NULL; str=strtok(NULL, p)) { printf("%s\n", str); }*/ char* str = strtok(buf, p); printf("%s\n", str); str = strtok(NULL, p);//en printf("%s\n", str); str = strtok(NULL, p);//yu printf("%s\n", str); str = strtok(NULL, p);//sh printf("%s\n", str); str = strtok(NULL, p);//ge printf("%s\n", str); //strtok - 開(kāi)始返回NULL return 0; }
用途示例:
C語(yǔ)言可以操作文件,打開(kāi)文件 - fopen
當(dāng)庫(kù)函數(shù)使用的時(shí)候,發(fā)生錯(cuò)誤會(huì)把errno這個(gè)全局的錯(cuò)誤變量設(shè)置為本次執(zhí)行庫(kù)函數(shù)產(chǎn)生的錯(cuò)誤碼,errno是C語(yǔ)言提供的一個(gè)全局變量,可以直接使用,放在errno.h文件中的
#include<stdio.h> #include <errno.h> #include<string.h> int main() { //打開(kāi)文件 FILE* pf = fopen("test.txt", "r"); if (NULL == pf) { //出錯(cuò)誤的原因是什么 printf("%s\n", strerror(errno)); //No such file or directory return 0; } //讀文件 //... //關(guān)閉文件 fclose(pf); pf = NULL; return 0; }
6、字符操作
6.1、字符分類函數(shù)
函數(shù) | 如果他的參數(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 | 任何可打印字符,包括圖形字符和空白字符 |
例如:isdigit
char ch = '0'; if (ch >= '0' && ch <= '9') { //復(fù)雜 } if (isdigit(ch)) { //方便快捷 }
6.2、字符轉(zhuǎn)換
int tolower ( int c ); //把大寫(xiě)轉(zhuǎn)為小寫(xiě) int toupper ( int c ); //把小寫(xiě)轉(zhuǎn)為大寫(xiě)
#include<stdio.h> #include <ctype.h> int main() { char ch = 0; while (ch = getchar()) { if (islower(ch)) { ch = toupper(ch); } else { ch = tolower(ch); } printf("%c", ch); } return 0; }
7、內(nèi)存操作函數(shù)
7.1、memcpy
功能:可拷貝不同類型的數(shù)據(jù)
#include<stdio.h> #include<string.h> int main() { int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[5] = { 0 }; memcpy(arr2, arr1, 5 * sizeof(arr1[0])); int i = 0; for (i = 0; i < 5; i++) { printf("%d ", arr2[i]); // 1 2 3 4 5 } return 0; }
注意:
void * memcpy ( void * destination, const void * source, size_t num );
- 函數(shù)memcpy從source的位置開(kāi)始向后復(fù)制num個(gè)字節(jié)的數(shù)據(jù)到destination的內(nèi)存位置。
- 這個(gè)函數(shù)在遇到 '\0' 的時(shí)候并不會(huì)停下來(lái)。
- 如果source和destination有任何的重疊,復(fù)制的結(jié)果都是未定義的。
7.1.1、模擬實(shí)現(xiàn)
#include<stdio.h> #include <assert.h> void* my_memcpy(void* dest, const void*src, size_t num) { void* ret = dest; assert(dest && src); while (num--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } return ret; } int main() { int arr3[] = { 1,2,3,4,5,6,7,8,9,10 }; int arr4[5] = { 0 }; my_memcpy(arr4, arr3+5, 5*sizeof(arr3[0])); int i = 0; for (i = 0; i < 5; i++) { printf("%d ", arr4[i]); //6 7 8 9 10 } return 0; }
其實(shí),C語(yǔ)言只要求:
memcpy能拷貝不重疊的內(nèi)存空間就可以了
memmove去處理那些重疊拷貝
7.2、memmove
功能:同樣可拷貝不同類型的數(shù)據(jù),不過(guò)可以重疊
#include<stdio.h> #include<string.h> int main() { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; memmove(arr + 2, arr, 20); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr[i]); //1 2 1 2 3 4 5 8 9 10 } return 0; }
注意:
- 和memcpy的差別就是memmove函數(shù)處理的源內(nèi)存塊和目標(biāo)內(nèi)存塊是可以重疊的。
- 如果源空間和目標(biāo)空間出現(xiàn)重疊,就得使用memmove函數(shù)處理。
7.2.1、模擬實(shí)現(xiàn)
#include<stdio.h> #include <assert.h> void* my_memmove(void* dest, const void* src, size_t num) { void* ret = dest; assert(dest && src); if (dest < src) { //前->后 while (num--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } } else { //后->前 while (num--) { *((char*)dest+num) = *((char*)src + num); } } return ret; } int main() { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; my_memmove(arr + 2, arr, 20); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr[i]); //1 2 1 2 3 4 5 8 9 10 } return 0; }
7.3、memset
功能:把一塊內(nèi)存空間設(shè)置成你想要的值,以字節(jié)為單位來(lái)修改
#include<stdio.h> #include<string.h> int main() { //char arr[20] = { 0 }; //memset(arr, 'x', 10); //printf("%s\n", arr); //xxxxxxxxxx int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; memset(arr, '\0', 10); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr[i]); // 0 0 0 4 5 6 7 8 9 10 } //01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ...將前10個(gè)字節(jié)改為0 //00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 return 0; }
7.4、memcmp
功能:內(nèi)存比較
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
比較從ptr1和ptr2指針開(kāi)始的num個(gè)字節(jié),不在乎有無(wú) '\0' ,你讓它比較幾個(gè)字節(jié)就比較幾個(gè)字節(jié)。
#include<stdio.h> #include<string.h> int main() { int arr1[] = { 1,2,7,4,5 }; int arr2[] = { 1,2,3,4,5 }; printf("%d\n", memcmp(arr1, arr2, 9)); //1 // 9表示比較前9個(gè)字節(jié) return 0; }
總結(jié)
到此這篇關(guān)于C語(yǔ)言進(jìn)階教程之字符函數(shù)&字符串函數(shù)的文章就介紹到這了,更多相關(guān)C語(yǔ)言字符函數(shù)&字符串函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++修煉之構(gòu)造函數(shù)與析構(gòu)函數(shù)
本章節(jié)我們將學(xué)習(xí)類的6個(gè)默認(rèn)成員函數(shù)中的構(gòu)造函數(shù)與析構(gòu)函數(shù),并對(duì)比C語(yǔ)言階段的內(nèi)容來(lái)學(xué)習(xí)它們的各自的特性,感興趣的同學(xué)可以參考閱讀2023-03-03Cocos2d-x學(xué)習(xí)筆記之開(kāi)發(fā)環(huán)境搭建
這篇文章主要介紹了Cocos2d-x學(xué)習(xí)筆記之開(kāi)發(fā)環(huán)境搭建,本文使用Visual Studio作為開(kāi)發(fā)IDE,是不同于其它教程的,需要的朋友可以參考下2014-09-09QT編寫(xiě)地圖實(shí)現(xiàn)獲取區(qū)域邊界
區(qū)域邊界是一些坐標(biāo)點(diǎn)集合,而且不同的行政區(qū)劃得到的區(qū)域邊界點(diǎn)數(shù)組集合個(gè)數(shù)不同。本文將具體介紹QT在編寫(xiě)地圖時(shí)如何實(shí)現(xiàn)獲取區(qū)域邊界,需要的可以參考一下2022-01-01