您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關C語言中字符串和內存函數的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
字符串是一種非常重要的數據類型,但是C語言不存在顯式的字符串類型,C語言中的字符串都以字符串常量的形式出現或存儲在字符數組中。字符串常量適用于那些對它不做修改的字符串函數。同時,C 語言提供了一系列庫函數來對操作字符串,這些庫函數都包含在頭文件 string.h 中。
size_t strlen ( const char * str );
字符串已經 '\0' 作為結束標志,strlen函數返回的是在字符串中 '\0' 前面出現的字符個數(不包含 '\0' )
參數指向的字符串必須要以 '\0' 結束
注意函數的返回值為size_t,是無符號的( 易錯 )
學會strlen函數的模擬實現
源字符串必須以 '\0' 結束。 會將源字符串中的 '\0' 拷貝到目標空間。 目標空間必須足夠大,以確保能存放源字符串。 目標空間必須可變。 學會模擬實現。
例1:
#include <stdio.h> #include <string.h> int main() { int len1 = strlen("abcdef"); printf("%d\n", len1); //6 char arr[] = {'a','b','c','d','e','f'}; //錯誤寫法 int len2 = strlen(arr); printf("%d\n", len2); //隨機值 return 0; }
執行結果:
例2:
int main() { if(strlen("abc") - strlen("abcdef") > 0) printf("hehe\n"); else printf("haha\n"); system("pause"); return 0; }
執行結果:
由于此時的strlen沒有進行定義,它的默認類型為無符號類型,那么兩個無符號數相加減最后得出的數是一個很大的數,所以最后的結果必然是大于0的
(1)計數器
#include <stdio.h> #include <assert.h> 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 <stdio.h> 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)遞歸
不創建臨時變量求字符串長度
#include<stdio.h> int 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);
將按源指向的 C 字符串復制到按目的地指向的陣列中,包括終止空字符 (并停止在那個時候)
源字符串必須以 '\0' 結束
會將源字符串中的 '\0' 拷貝到目標空間
目標空間必須足夠大,以確保能存放源字符串
目標空間必須可變。 學會模擬實現
例:
#include <stdio.h> int main() { char arr1[] = "abcdefghi"; char arr2[] = "bit"; //錯誤示范 //char *arr1 = "abcdefghi"; //p指向常量字符串,而常量字符串無法被修改 //char arr2[] = {'b','i','t'}; //由于此時沒有給'\0',由于找不到'\0'會導致向后越界訪問 strcpy(arr1, arr2); printf("%s\n", arr1); return 0; }
#include <stdio.h> #include <assert.h> 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 );
將源字符串的副本附加到目的地字符串。終止無效字符在目的地由源的第一個字符覆蓋,并在源的末尾包含空字符由目的地兩者的連結形成的新字符串
源字符串必須以 '\0' 結束
目標空間必須有足夠的大,能容納下源字符串的內容
目標空間必須可修改
字符串自己如何給自己追加
例:
#include <stdio.h> int main() { char arr1[30] = "hello\0xxxxxxx"; char arr2[] = "wolrd"; strcat(arr1, arr2); printf("%s\n", arr1); //錯誤示范 char arr3[] = "hello"; char arr4[] = "world"; strcat(arr3, arr4); printf("%s\n", arr3); //由于arr3數組沒有定義空間大小 //此時就開辟了'hello\0'6個字節 //當arr4數組追加過去后就產生了越界訪問,產生報錯 return 0; }
調試結果:
執行結果:
總結:此時我們可以看到,arr2數組內的的字符串從arr1數組中的'\0'開始進行追加
當arr2數組內的字符串追加過去后,后面的‘\0'也一并追加了過去
當目標空間不夠大時,就會造成訪問越界
#include <stdio.h> #include <assert.h> 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 );
此函數開始比較每個字符串的第一個字符。 如果它們彼此相等,則繼續使用以下對,直到字符不同或到達終止空字符為止。
標準規定:
第一個字符串大于第二個字符串,則返回大于0的數字
第一個字符串等于第二個字符串,則返回0
第一個字符串小于第二個字符串,則返回小于0的數字
那么如何判斷兩個字符串?
#include <stdio.h> #include <string.h> 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 <stdio.h> 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); //通過相減判斷大于或小于 } } 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 );//單位是字節
將源的前 num 個字符復制到目標。 如果在復制 num 個字符之前找到源 C 字符串的結尾(由空字符表示),則用零填充目標,直到總共寫入了 num 個字符。
拷貝num個字符從源字符串到目標空間。
如果源字符串的長度小于num,則拷貝完源字符串之后,在目標的后邊追加0,直到num個。
例1:
int main() { char arr1[10] = "abcdefgh"; char arr2[] = "bit"; stcncpy(arr1, arr2, 6); return 0; }
調試結果:
例2:
#include <stdio.h> #include <string.h> int main() { char arr1[10] = "abcdefgh"; char arr2[] = "bit"; strncpy(arr1, arr2, 6); return 0; }
調試結果:
由此可見,strncpy函數能拷貝任意長度的字符,當拷貝的字符長度不夠拷貝數時,用 '\0' 進行補充,直到拷貝數相等
#include <stdio.h> #include <assert.h> 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 );
將源的前 num 個字符附加到目標,再加上一個終止空字符
如果 source 中 C 字符串的長度小于 num,則只復制終止空字符之前的內容。
例1:
#include <stdio.h> #include <string.h> int main() { char arr1[30] = { "hello\0xxxxxx" }; char arr2[] = "world"; strncat(arr1, arr2, 4); return 0; }
調試結果:
例2:
int main() { char arr1[30] = { "hello\0xxxxxxxxx" }; char arr2[] = "world"; strncat(arr1, arr2, 8); return 0; }
調試結果:
由此可見,不管追加幾個數,都會在追加字符串后加上 '\0',而一旦追加數超過了追加字符串的長度,在追加完整字符串后面再加上'\0'后便結束了
#include<stdio.h> #include<assert.h> #include<string.h> void 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 );
比較到出現另個字符不一樣或者一個字符串結束或者num個字符全部比較完。
例:
#include <stdio.h> #include <string.h> int main() { const char* p1 = "abcdef"; const char* p2 = "abcqwer"; int ret = strncmp(p1, p2, 4); printf("%d\n", ret); }
執行結果:
#include<stdio.h> #include<assert.h> #include<string.h> int 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<n; i++) printf("%c",arr1[i]); printf("="); for(i=0; i<n; i++) printf("%c",arr2[i]); } else if(ret < 0) { for(i=0; i<n; i++) printf("%c",arr1[i]); printf("<"); for(i=0; i<n; i++) printf("%c",arr2[i]); } else { for(i=0; i<n; i++) printf("%c",arr1[i]); printf(">"); for(i=0; i<n; i++) printf("%c",arr2[i]); } return 0; }
char * strstr ( const char *, const char * );
返回指向 str1 中第一次出現 str2 的指針,如果 str2 不是 str1 的一部分,則返回空指針。
例:
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; }
執行結果:
由此可得出,當有主字符串中存在兩個及以上子串時,優先按第一次出現相同的地址進行打印,并且會一直打印完剩下的字符串
#include <stdio.h> #include <assert.h> //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;//當前指針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);
sep參數是個字符串,定義了用作分隔符的字符集合
第一個參數指定一個字符串,它包含了0個或者多個由sep字符串中一個或者多個分隔符分割的標記。
strtok函數找到str中的下一個標記,并將其用 \0 結尾,返回一個指向這個標記的指針。(注:strtok函數會改 變被操作的字符串,所以在使用strtok函數切分的字符串一般都是臨時拷貝的內容并且可修改。)
strtok函數的第一個參數不為 NULL ,函數將找到str中第一個標記,strtok函數將保存它在字符串中的位置。
strtok函數的第一個參數為 NULL ,函數將在同一個字符串中被保存的位置開始,查找下一個標記。
如果字符串中不存在更多的標記,則返回 NULL 指針。
例:
#include <stdio.h> #include <string.h> int main() { char arr[] = "qpzyahxf@163.com"; char *p = "@."; char buf[1024] = {0}; //strtok會改變字符串內容,buf防止原字符串被切割(保護原始數據) 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; }
執行結果:
#include <stdio.h> 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);
返回錯誤碼,所對應的錯誤信息。
例1:
#include <stdio.h> #include <string.h> int main() { int i = 0; //1-10錯誤碼的返回返回信息 for(i = 0; i <= 10; i++) { printf("%d %s\n", i, strerror(i)); } system("pause"); return 0; }
執行結果:
在實際在使用的時候,錯誤碼并非由我們來控制的,而是接收系統返回的錯誤信息
例2:
#include <stdio.h> #include string.h> #include <errno.h> char *str = strerror(errno);//需引用頭文件errno.h printf("%s\n", str); //errno 是一個全局的錯誤碼的變量 //當c語言的庫函數在執行過程中,發生了錯誤,就會把對應的錯誤碼,復制到errno中
例3:
#include <stdio.h> #include <errno.h> int main() { //打開文件 FILE *pf = fopen("test.txt", "r"); if(pf == NULL) { printf("%s\n", strerror(errno));//知道錯誤的原因 } else { printf("open file success.\n"); } return 0; }
執行結果:
函數 | 如果他的參數符合下列條件就返回真 |
iscntrl | 任何控制字符 |
isspace | 空白字符:空格‘ ',換頁‘\f',換行'\n',回車‘\r',制表符'\t'或者垂直制表符'\v' |
isdigit | 十進制數字 0~9 |
isxdigit | 十六進制數字,包括所有十進制數字,小寫字母a~f,大寫字母A~F |
islower | 小寫字母a~z |
isupper | 大寫字母A~Z |
isalpha | 字母a~z或A~Z |
isalnum | 字母或者數字,a~z,A~Z,0~9 |
ispunct | 標點符號,任何不屬于數字或者字母的圖形字符(可打印) |
isgraph | 任何圖形字符 |
isprint | 任何可打印字符,包括圖形字符和空白字符 |
注:0位假,非0為真
int tolower ( int c ); //tolower 轉小寫字母 int toupper ( int c ); //toupper 轉大寫字母
例1:
#include <stdio.h> #include <ctype.h> int main() { char ch = tolower('Q'); putchar(ch); system("pause"); return 0; }
執行結果:
例2:
#include <stdio.h> #include <ctype.h> int main() { //大寫字母轉小寫 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; }
執行結果:
在之前的學習中,我們了解了字符串拷貝可以使用strcpy函數,但是strcpy函數具有局限性。
當拷貝的數據不是字符串時,比如說int類型、float類型,還能使用strcpy函數嗎?
strcpy函數在拷貝的時候是以\0為字符串拷貝的結束標志,那么在拷貝其它類型數據的時候,拷貝該結束的時候不一定存在\0。所以使用strcpy函數肯定是行不通的。那怎么辦呢?
此時我們就可以使用memcpy函數-- - 內存拷貝函數,用來拷貝任意類型數據。
void *memcpy ( void * destination, const void * source, size_t num ); //void* - 通用類型的指針-無類型指針 //dest destination 表示內存拷貝的目的位置 //src source 表示內存拷貝的起始位置 //size_t num 表示內存拷貝的字節數
函數memcpy從source的位置開始向后復制num個字節的數據到destination的內存位置
這個函數在遇到 '\0' 的時候并不會停下來
如果source和destination有任何的重疊,復制的結果都是未定義的。
例:
int main() { int arr1[] = { 1,2,3,4,5 }; int arr2[5] = { 0 }; memcpy(arr2, arr1, sizeof(arr1)); return 0; }
調試結果:
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* - 通用類型的指針-無類型指針 //dest destination 表表示內存移動的目的位置 //src source 表示內存移動的起始位置 //size_t num 表示移動內存的字節數
和memcpy的差別就是memmove函數處理的源內存塊和目標內存塊是可以重疊的
如果源空間和目標空間出現重疊,就得使用 比特科技 memmove函數處理
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.(將緩沖區設置為指定的字符)
以字節為內存設置單位
例:
#include<stdio.h> #include<string.h> int main() { char arr[] = "abcdefg"; memset(arr, '*', 4); printf("%s", arr); return 0; }
執行結果:
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
比較從ptr1和ptr2指針開始的num個字節
返回值如下
例:
#include<stdio.h> #include<string.h> int 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; }
執行結果:
關于“C語言中字符串和內存函數的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。