摘要:字符串常量適用于那些對(duì)它不做修改的字符串函數(shù)。同時(shí),語(yǔ)言提供了一系列庫(kù)函數(shù)來(lái)對(duì)操作字符串,這些庫(kù)函數(shù)都包含在頭文件中。目標(biāo)空間必須足夠大,以確保能存放源字符串。拷貝個(gè)字符從源字符串到目標(biāo)空間。
前言:
????????字符串是一種非常重要的數(shù)據(jù)類型,但是C語(yǔ)言不存在顯式的字符串類型,C語(yǔ)言中的字符串都以字符串常量的形式出現(xiàn)或存儲(chǔ)在字符數(shù)組中。字符串常量適用于那些對(duì)它不做修改的字符串函數(shù)。同時(shí),C 語(yǔ)言提供了一系列庫(kù)函數(shù)來(lái)對(duì)操作字符串,這些庫(kù)函數(shù)都包含在頭文件 string.h 中。?
目錄
strncpy函數(shù)的模擬實(shí)現(xiàn)
strncat函數(shù)的模擬實(shí)現(xiàn)
strncmp函數(shù)的模擬實(shí)現(xiàn)
memmove函數(shù)的模擬實(shí)現(xiàn)
size_t strlen ( const char * str );
源字符串必須以 "/0" 結(jié)束。 會(huì)將源字符串中的 "/0" 拷貝到目標(biāo)空間。 目標(biāo)空間必須足夠大,以確保能存放源字符串。 目標(biāo)空間必須可變。 學(xué)會(huì)模擬實(shí)現(xiàn)。
例1:
#include #include int main(){ int len1 = strlen("abcdef"); printf("%d/n", len1); //6 char arr[] = {"a","b","c","d","e","f"}; //錯(cuò)誤寫法 int len2 = strlen(arr); printf("%d/n", len2); //隨機(jī)值 return 0;}
執(zhí)行結(jié)果:?
例2:
int main(){ if(strlen("abc") - strlen("abcdef") > 0) printf("hehe/n"); else printf("haha/n"); system("pause"); return 0;}
執(zhí)行結(jié)果:
?由于此時(shí)的strlen沒(méi)有進(jìn)行定義,它的默認(rèn)類型為無(wú)符號(hào)類型,那么兩個(gè)無(wú)符號(hào)數(shù)相加減最后得出的數(shù)是一個(gè)很大的數(shù),所以最后的結(jié)果必然是大于0的
(1)計(jì)數(shù)器
#include #include int my_strlen(const char *str){ int count = 0; assert(str != NULL); while(*str != "/0") { count++; str++; } return count;}int main(){ int len = my_strlen("abcdef"); printf("%d/n", len); return 0;}
?(2)指針-指針
#include int my_strlen(const char *str){ const char *p = str; while(*p != "/0") { p++; } return p-str;}int main(){ int len = 0; char arr[10]="abcdef"; len = my_strlen(arr); printf("%d/n", len); return 0;}
(3)遞歸
不創(chuàng)建臨時(shí)變量求字符串長(zhǎng)度
#includeint my_strlen(const char *str){ if(*str=="/0") return 0; else return 1+my_strlen(str+1);}int main(){ int len = 0; char arr[10]="abcdef"; len = my_strlen(arr); printf("%d/n", len); return 0;}
char* strcpy(char * destination, const char * source);
例:
#include int main(){ char arr1[] = "abcdefghi"; char arr2[] = "bit"; //錯(cuò)誤示范 //char *arr1 = "abcdefghi"; //p指向常量字符串,而常量字符串無(wú)法被修改 //char arr2[] = {"b","i","t"}; //由于此時(shí)沒(méi)有給"/0",由于找不到"/0"會(huì)導(dǎo)致向后越界訪問(wèn) strcpy(arr1, arr2); printf("%s/n", arr1); return 0;}
#include #include char *my_strcpy(char *dest, const char *src){ assert(dest != NULL); assert(src != NULL); char *ret = dest; //拷貝src指向的字符串到dest指向的空間,包含"/0" while(*dest++ = *src++) { ; } //返回目的的空間的初始地址 return ret;//"/0"}int main(){ char arr1[] = "abcdefgh"; char arr2[] = "bit"; my_strcpy(arr1, arr2); printf("%s/n", arr1); return 0;}
char * strcat ( char * destination, const char * source );
例:?
#include int main(){ char arr1[30] = "hello/0xxxxxxx"; char arr2[] = "wolrd"; strcat(arr1, arr2); printf("%s/n", arr1); //錯(cuò)誤示范 char arr3[] = "hello"; char arr4[] = "world"; strcat(arr3, arr4); printf("%s/n", arr3); //由于arr3數(shù)組沒(méi)有定義空間大小 //此時(shí)就開辟了"hello/0"6個(gè)字節(jié) //當(dāng)arr4數(shù)組追加過(guò)去后就產(chǎn)生了越界訪問(wèn),產(chǎn)生報(bào)錯(cuò) return 0;}
調(diào)試結(jié)果:?
執(zhí)行結(jié)果:
總結(jié):此時(shí)我們可以看到,arr2數(shù)組內(nèi)的的字符串從arr1數(shù)組中的"/0"開始進(jìn)行追加
當(dāng)arr2數(shù)組內(nèi)的字符串追加過(guò)去后,后面的‘/0’也一并追加了過(guò)去
當(dāng)目標(biāo)空間不夠大時(shí),就會(huì)造成訪問(wèn)越界
#include #include char *my_strcat(char *dest, const char *src){ assert(dest != NULL); assert(src); char *ret = dest; //1.找到目的字符串的"/0" while(*dest != "/0") { dest++; } //2.追加 while(*dest++ = *src++) { ; } return ret;} int main(){ char arr1[30] = "hello"; char arr2[] = "wolrd"; my_strcat(arr1, arr2); printf("%s/n", arr1); return 0;}
int strcmp (const char * str1, const char * str2 );
此函數(shù)開始比較每個(gè)字符串的第一個(gè)字符。 如果它們彼此相等,則繼續(xù)使用以下對(duì),直到字符不同或到達(dá)終止空字符為止。?
標(biāo)準(zhǔn)規(guī)定:
#include #include int main(){ char *p1 = "qbc"; char *p2 = "abc"; // int ret = strcmp(p1, p2); // printf("%d/n", ret); if(strcmp(p1, p2) > 0) { printf("p1 > p2/n"); } else if(strcmp(p1, p2) == 0) { printf("p1 == p2/n"); } else if(strcmp(p1, p2) < 0) { printf("p1 < p2/n"); } return 0;}
#include #include int my_strcmp(const char *str1, const char *str2){ assert (str1 && str2); // 比較 while(*str1++ == *str2++) { if(*str1 == "/0") { return 0;//等于 } } if(*str1 > *str2) return 1;//大于 else return -1;//小于 //return (*str1 - *str2); //通過(guò)相減判斷大于或小于}int main(){ char *p1 = "abcdef"; char *p2 = "abqwe"; int ret = my_strcmp(p1, p2); printf("ret = %d/n", ret); return 0;}
char * strncpy ( char * destination, const char * source, size_t num );//單位是字節(jié)
?例1:
int main(){ char arr1[10] = "abcdefgh"; char arr2[] = "bit"; stcncpy(arr1, arr2, 6); return 0;}
調(diào)試結(jié)果:?
?例2:
#include #include int main(){ char arr1[10] = "abcdefgh"; char arr2[] = "bit"; strncpy(arr1, arr2, 6); return 0;}
調(diào)試結(jié)果:?
?由此可見(jiàn),strncpy函數(shù)能拷貝任意長(zhǎng)度的字符,當(dāng)拷貝的字符長(zhǎng)度不夠拷貝數(shù)時(shí),用 "/0" 進(jìn)行補(bǔ)充,直到拷貝數(shù)相等
#include #include void my_strncpy(char *dest, const char *src, int n){ assert(src); char* p1 = dest; const char* p2 = src; while (n--) { *p1++ = *p2++; }}int main(){ char arr1[20] = "hello" char arr2[] = "world"; my_strncpy(arr1, arr2, 3); return 0;}
char * strncat ( char * destination, const char * source, size_t num );
例1:
#include #include int main(){ char arr1[30] = { "hello/0xxxxxx" }; char arr2[] = "world"; strncat(arr1, arr2, 4); return 0;}
調(diào)試結(jié)果:?
例2:
int main(){ char arr1[30] = { "hello/0xxxxxxxxx" }; char arr2[] = "world"; strncat(arr1, arr2, 8); return 0;}
調(diào)試結(jié)果:
?由此可見(jiàn),不管追加幾個(gè)數(shù),都會(huì)在追加字符串后加上 "/0",而一旦追加數(shù)超過(guò)了追加字符串的長(zhǎng)度,在追加完整字符串后面再加上"/0"后便結(jié)束了
#include#include#includevoid my_strncat(char* dest, const char* src, int len1, int len2, int n){ char* ret = dest + len1; assert(src); assert(n <= len2); while ((n--) && (*ret++ = *src++)) { ; }}int main(){ char arr1[20] = "abcd"; char arr2[] = "efghi"; int len1 = strlen(arr1); int len2 = strlen(arr2); int n = 0; scanf("%d", &n); my_strncat(arr1, arr2, len1, len2, n); return 0;}
int strncmp ( const char * str1, const char * str2, size_t num );
例:
#include #include int main(){ const char* p1 = "abcdef"; const char* p2 = "abcqwer"; int ret = strncmp(p1, p2, 4); printf("%d/n", ret);}
執(zhí)行結(jié)果:
#include#include#includeint my_strncmp(const char *dest, const char *src, int n){ int ret = 0; assert(dest); assert(src); assert(n); while( (n--) && !(ret = (unsigned char)*dest-(unsigned char)*src) && *dest ) { dest++; src++; } return ret;}int main(){ char arr1[] = "abcdef"; char arr2[] = "abcedef"; int n = 0; int ret = 0; int i = 0; scanf("%d",&n); ret = my_strncmp(arr1, arr2, n); if(ret == 0) { for(i=0; i"); for(i=0; i
char * strstr ( const char *, const char * );
例:
int main(){ char *p1 = "abcdefabcdef"; char *p2 = "def"; char * ret = strstr(p1, p2); if(ret == NULL) { printf("子串不存在"); } else { printf("%s/n", ret); } system("Pause"); return 0;}
執(zhí)行結(jié)果:
?由此可得出,當(dāng)有主字符串中存在兩個(gè)及以上子串時(shí),優(yōu)先按第一次出現(xiàn)相同的地址進(jìn)行打印,并且會(huì)一直打印完剩下的字符串
#include #include //KMP 算法char *my_strstr(const char *p1, const char *p2){ assert(p1 != NULL); assert(p2 != NULL); char *s1 = NULL; char *s2 = NULL; char *cur = (char*)p1;//當(dāng)前指針current if(*p2 == "/0") { return (char*)p1; } while(*cur) { s1 = cur; s2 = (char*)p2; while(*s1 && *s2 && (*s1 == *s2)) { s1++; s2++; } if(*s2 == "/0") { return cur;//找到子串 } cur++; } return NULL;//找不到子串}int main(){ char *p1 = "abcdef"; char *p2 = "def"; char * ret = my_strstr(p1, p2); if(ret == NULL) { printf("子串不存在/n"); } else { printf("%s/n", ret); } return 0;}
char * strtok (char *str, const char *sep);
例:
#include #include int main(){ char arr[] = "qpzyahxf@163.com"; char *p = "@."; char buf[1024] = {0}; //strtok會(huì)改變字符串內(nèi)容,buf防止原字符串被切割(保護(hù)原始數(shù)據(jù)) strcpy(buf, arr); //切割buf中的字符串 char *ret = NULL; for(ret = strtok(arr, p); ret != NULL; ret = strtok(NULL, p)) { printf("%s/n", ret); } // char *ret = strtok(arr, p); // printf("%s/n", ret); // ret = strtok(NULL, p); // printf("%s/n", ret); // ret = strtok(NULL, p); // printf("%s/n", ret); return 0;}
執(zhí)行結(jié)果:
#include char *my_strtok(char *str1 ,char *str2){ static char *p_last = NULL; if(str1 == NULL && (str1 = p_last) == NULL) { return NULL; } char *s = str1; char *t = NULL; while(*s != "/0") { t = str2; while(*t != "/0") { if(*s == *t) { p_last = s + 1; if( s - str1 == NULL) { str1 = p_last; break; } *s = "/0"; return str1; } t++; } s++; } return NULL;}int main() { char arr[] = "qpzyahxf@163.com"; char *ret = NULL; char *p = "@."; for(ret = my_strtok(arr, p); ret != NULL; ret = my_strtok(NULL, p)) { printf("%s/n", ret); } return 0; }
char * strerror(int errum);
返回錯(cuò)誤碼,所對(duì)應(yīng)的錯(cuò)誤信息。
???????例1:
#include #include int main(){ int i = 0; //1-10錯(cuò)誤碼的返回返回信息 for(i = 0; i <= 10; i++) { printf("%d %s/n", i, strerror(i)); } system("pause"); return 0;}
執(zhí)行結(jié)果:?
在實(shí)際在使用的時(shí)候,錯(cuò)誤碼并非由我們來(lái)控制的,而是接收系統(tǒng)返回的錯(cuò)誤信息
例2:
#include #include string.h>#include char *str = strerror(errno);//需引用頭文件errno.h printf("%s/n", str); //errno 是一個(gè)全局的錯(cuò)誤碼的變量 //當(dāng)c語(yǔ)言的庫(kù)函數(shù)在執(zhí)行過(guò)程中,發(fā)生了錯(cuò)誤,就會(huì)把對(duì)應(yīng)的錯(cuò)誤碼,復(fù)制到errno中
例3:
#include #include int main(){ //打開文件 FILE *pf = fopen("test.txt", "r"); if(pf == NULL) { printf("%s/n", strerror(errno));//知道錯(cuò)誤的原因 } else { printf("open file success./n"); } return 0;}
執(zhí)行結(jié)果:?
函數(shù) | 如果他的參數(shù)符合下列條件就返回真 |
iscntrl | 任何控制字符 |
isspace | 空白字符:空格‘ ’,換頁(yè)‘/f’,換行"/n",回車‘/r’,制表符"/t"或者垂直制表符"/v" |
isdigit | 十進(jìn)制數(shù)字 0~9 |
isxdigit | 十六進(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 | 任何可打印字符,包括圖形字符和空白字符 |
注:0位假,非0為真
int tolower ( int c ); //tolower 轉(zhuǎn)小寫字母int toupper ( int c );//toupper 轉(zhuǎn)大寫字母
例1:
#include #include int main(){ char ch = tolower("Q"); putchar(ch); system("pause"); return 0;}
執(zhí)行結(jié)果:?
例2:
#include #include int main(){ //大寫字母轉(zhuǎn)小寫 char arr[] = "No Mercy"; int i = 0; while(arr[i]) { if(isupper(arr[i])) { arr[i] = tolower(arr[i]); } i++; } printf("%s/n", arr); return 0;}
執(zhí)行結(jié)果:?
在之前的學(xué)習(xí)中,我們了解了字符串拷貝可以使用strcpy函數(shù),但是strcpy函數(shù)具有局限性。
當(dāng)拷貝的數(shù)據(jù)不是字符串時(shí),比如說(shuō)int類型、float類型,還能使用strcpy函數(shù)嗎?
strcpy函數(shù)在拷貝的時(shí)候是以/0為字符串拷貝的結(jié)束標(biāo)志,那么在拷貝其它類型數(shù)據(jù)的時(shí)候,拷貝該結(jié)束的時(shí)候不一定存在/0。所以使用strcpy函數(shù)肯定是行不通的。那怎么辦呢?
此時(shí)我們就可以使用memcpy函數(shù)-- - 內(nèi)存拷貝函數(shù),用來(lái)拷貝任意類型數(shù)據(jù)。
void *memcpy ( void * destination, const void * source, size_t num );//void* - 通用類型的指針-無(wú)類型指針//dest destination 表示內(nèi)存拷貝的目的位置//src source 表示內(nèi)存拷貝的起始位置//size_t num 表示內(nèi)存拷貝的字節(jié)數(shù)
例:
int main(){ int arr1[] = { 1,2,3,4,5 }; int arr2[5] = { 0 }; memcpy(arr2, arr1, sizeof(arr1)); return 0;}
調(diào)試結(jié)果:
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;//++(char*)dest //src = (char*)src + 1;//++(char*)src *((char*)dest)++ = *((char*)src)++; } return ret; }int main(){ int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[10] = { 0 }; my_memcpy(arr2, arr1, 20); return 0;}
void * memmove ( void * destination, const void * source, size_t num ); //void* - 通用類型的指針-無(wú)類型指針//dest destination 表表示內(nèi)存移動(dòng)的目的位置//src source 表示內(nèi)存移動(dòng)的起始位置//size_t num 表示移動(dòng)內(nèi)存的字節(jié)數(shù)
void *my_memmove( void *dest, const void *src, size_t num) { void * ret = dest; assert(dest && src); if (dest <= src || (char *)dest >= ((char *)src + num)) { 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 arr1[10] = {0,1,2,3,4,5,6,7,8,9}; int arr2[10] = {0}; my_memmove(arr1 + 2, arr1, 20); return 0;}
void* memset(void* dest, int c, size_t count);
作用:Sets buffers to a specified character.(將緩沖區(qū)設(shè)置為指定的字符)
以字節(jié)為內(nèi)存設(shè)置單位
例:
#include#includeint main(){ char arr[] = "abcdefg"; memset(arr, "*", 4); printf("%s", arr); return 0;}
執(zhí)行結(jié)果:
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
例:
#include#includeint main(){ int arr1[5] = { 1,2,3,4,5 }; int arr2[5] = { 1,2,3,4,8 }; int ret = memcmp(arr1, arr2, sizeof(arr1)); if (ret > 0) { printf("arr1 > arr2"); } else if (ret == 0) { printf("arr1 == arr2"); } else { printf("arr1 < arr2"); } return 0;}
執(zhí)行結(jié)果:
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/118797.html
目錄 ? ?一、數(shù)據(jù)類型介紹 二、類型的意義 三、類型的基本歸類 整型家族 浮點(diǎn)數(shù)家族 構(gòu)造類型(自定義類型) 指針類型 空類型 四、整形在內(nèi)存中的存儲(chǔ) 原碼、反碼、補(bǔ)碼 大小端字節(jié)序 為什么有大端和小端? 一道經(jīng)典筆試題 ?一、數(shù)據(jù)類型介紹 數(shù)據(jù)從大的方向分為兩類: 內(nèi)置類型自定義類型內(nèi)置類型我們前面已經(jīng)學(xué)習(xí)過(guò),如下: char? ? ? ? ? ? //字符數(shù)據(jù)類型 short? ? ? ...
目錄 一、枚舉 (一)枚舉類型的定義 (二)使用枚舉的原因? (三)枚舉的優(yōu)點(diǎn)? (四)枚舉的大小 (五)枚舉的使用 二、聯(lián)合(共用體) (一)聯(lián)合類型的定義 (二)聯(lián)合的特點(diǎn) (三)面試題 (四)聯(lián)合大小的計(jì)算 一、枚舉 枚舉顧名思義就是:列舉?。? ?即把可能的取值一一列舉出來(lái)。 比如我們現(xiàn)實(shí)生活中: 一周當(dāng)中從周一至周日的7天,可以一一列舉;性別有:男、女、保密,可以一一列舉;月份有...
在過(guò)往學(xué)習(xí)的JavaScript都是在基礎(chǔ),現(xiàn)在為大家介紹更為深入的JavaScript知識(shí)。 JavaScript函數(shù) JavaScript函數(shù)和Java函數(shù)是有一部分相似的,所以學(xué)習(xí)起來(lái)也會(huì)相對(duì)簡(jiǎn)單 基本構(gòu)造 1.直接構(gòu)造 //function代表函數(shù)標(biāo)志,name為函數(shù)名稱,參數(shù)可有可無(wú) functionname(參數(shù)){ //... return; } 2....
小編寫這篇文章的主要目的,主要是來(lái)給大家解答下關(guān)于python數(shù)學(xué)建模的一些相關(guān)的介紹,涉及到內(nèi)容涵蓋Numpy的一些相關(guān)的應(yīng)用具體的一些介紹。另外,還會(huì)涉及到相關(guān)的Pandas學(xué)習(xí)知識(shí),具體內(nèi)容下面給大家詳細(xì)解答下。 1 Numpy介紹與應(yīng)用 1-1Numpy是什么 NumPy是一個(gè)運(yùn)行速度非常快的數(shù)學(xué)庫(kù),一個(gè)開源的的python科學(xué)計(jì)算庫(kù),主要用于數(shù)組、矩陣計(jì)算,包含: 一個(gè)強(qiáng)大的...
小編寫這篇文章的一個(gè)主要目的,主要是來(lái)給大家去做一個(gè)介紹。介紹的內(nèi)容主要是關(guān)于建模知識(shí)的一些相關(guān)介紹,包括其Pandas的一些相關(guān)學(xué)習(xí),就具體的操作內(nèi)容,下面就給大家詳細(xì)解答下。 Numpy學(xué)習(xí) 1 Numpy介紹與應(yīng)用 1-1Numpy是什么 NumPy是一個(gè)運(yùn)行速度非常快的數(shù)學(xué)庫(kù),一個(gè)開源的的python科學(xué)計(jì)算庫(kù),主要用于數(shù)組、矩陣計(jì)算,包含: 一個(gè)強(qiáng)大的N維數(shù)組對(duì)象ndarr...
閱讀 685·2023-04-25 22:50
閱讀 1525·2021-10-08 10:05
閱讀 983·2021-09-30 09:47
閱讀 1912·2021-09-28 09:35
閱讀 814·2021-09-26 09:55
閱讀 3404·2021-09-10 10:51
閱讀 3426·2021-09-02 15:15
閱讀 3289·2021-08-05 09:57