網站首頁 編程語言 正文
勵志環節
發光并非太陽的專利,大家都可以。
本章重點
重點介紹處理字符和字符串的庫函數的使用和注意事項
求字符串長度 strlen
長度不受限制的字符串函數 strcpy strcat strcmp
長度受限制的字符串函數介紹strncpy strncat strncmp
字符串查找 strstr strtok
錯誤信息報告 strerror
字符操作
內存操作函數 memcpy memmove memset memcmp
C語言中對字符和字符串的處理很是頻繁,但是C語言本身是沒有字符串類型的,字符串通常放在
常量字符串中或者字符數組中。
字符串常量 適用于那些對它不做修改的字符串函數.
一 函數介紹
1.1 strlen
在前面的文章中,介紹了三種方法實現strlen:(1)計數器的方法(2)遞歸的方法 (3)指針-指針的方法。
size_t strlen ( const char * str );
sizeof 是一個操作符,返回的結果為size_t (size_t專門為sizeof的返回值設計的)
size_t 相當于unsigned int
庫函數strlen返回值 是size_t,所以 strlen 不能用于加減:strlen("abc") - strlen("abcdefg") 結果會是一個size_t 類型的數,不會是-4 (解決辦法,可以強制轉換)
字符串以'\0' 作為結束標志,strlen函數返回的是在字符串中 '\0' 前面出現的字符個數(不包含 '\0' )
參數指向的字符串必須要以 '\0' 結束。
注意函數的返回值為size_t,是無符號的( 易錯 )
學會strlen函數的模擬實現
1.2 strcpy
char* strcpy(char * destination, const char * source );
源字符串必須以 '\0' 結束。
會將源字符串中的 '\0' 拷貝到目標空間。
目標空間必須足夠大,以確保能存放源字符串。(strlen不管目標空間可以可以放進去,但是我們要保證目標空間足夠大,以便能放進去)
目標空間必須可變。
學會模擬實現
1.3 strcat
追加一個字符串
char * strcat ( char * destination, const char * source );
源字符串必須以 '\0' 結束。沒有\0的話,就無法追加,打印不出來。
目標空間必須有足夠的大,能容納下源字符串的內容。
目標空間必須可修改。
字符串自己給自己追加,如何?
代碼展示:
#include <stdio.h>
int main()
{
char arr1[30] = "hello";
char arr2[] = "world";
strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
1.4 strcmp
int strcmp ( const char * str1, const char * str2 );
第一個字符串大于第二個字符串,則返回大于0的數字
第一個字符串等于第二個字符串,則返回0
第一個字符串小于第二個字符串,則返回小于0的數字strcmp(s1, s2),比較字符串的大小,兩個字符串從左向右逐個字符相比(按ASCII的值大小相比),直到某一個字符不相等或者其中一個字符串比較完畢才停止比較,字符的比較為ASCII碼的比較(若字符串1大于字符串2,返回結果大于0,若字符串1小于字符串2,返回結果小于0,若字符串1等于字符串2,返回結果等于0.)
strcmp的頭文件是<string.h>
1.5 strncpy
char * strncpy ( char * destination, const char * source, size_t num );
拷貝num個字符從源字符串到目標空間。
如果源字符串的長度小于num,則拷貝完源字符串之后,在目標的后邊追加'\0',直到num個。
1.6 strncat
char * strncat ( char * destination, const char * source, size_t num )
追加字符,追加num個字符從源字符串到目標空間。
如果源字符串的長度大于num,則追加num個源字符串之后,再在后邊一個加'\0'。如果源字符串的長度小于num,則追加完源字符串之后,再在后邊加一個'\0',別的就不管了。
1.7 strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
比較num個字符
1.8 strstr
char * strstr ( const char *str1, const char * str2);
字符串查找函數,在str1中找str2,返回在str1中第一次出現str2的地址。找不到返回空指針。
代碼展示:
#include <stdio.h>
int main()
{
char arr1[] = "abcdabcd";
char arr2[] = "cd";
char* ret = strstr(arr1, arr2);
if (ret == NULL)
printf("找不到");
else
printf("%s\n", ret);
return 0;
}
1.9 strtok
char * strtok ( char * str, const char * sep );
(1)sep參數是個字符串,定義了用作分隔符的字符集合
(2)第一個參數指定一個字符串,它包含了0個或者多個由sep字符串中一個或者多個分隔符分割的標記。
(3)strtok函數找到str中的下一個標記,并將其用 \0 結尾,返回一個指向這個標記的指針(注: strtok函數會改變被操作的字符串,所以在使用strtok函數切分的字符串一般都是臨時拷貝的內容 并且可修改。)
把標記內容改成\0,會改變字符串的內容,所以把字符串臨時拷貝。
(4)strtok函數的第一個參數不為 NULL ,函數將找到str中第一個標記,strtok函數將保存它在字符串 中的位置。
(5)strtok函數的第一個參數為 NULL ,函數將在同一個字符串中被保存的位置開始,查找下一個標 記。
(6)如果字符串中不存在更多的標記,則返回 NULL 指針。
1 strtok函數找第一個標記的時候,函數的第一個參數不是NULL
2 strtok函數找非第一個標記的時候,函數的第一個參數是NULL
代碼展示:
#include <stdio.h>
int main()
{
const char* p = "@.";
char arr[] = "abxbcbhd@nckdc.cidhc";
char buf[50] = { 0 };//因為字符串會被修改,所以要吧arr臨時拷貝到buf里
//要保證arr不被修改
strcpy(buf, arr);//臨時拷貝
char* str = strtok(buf, p);
printf("%s\n", str);
str = strtok(NULL, p);
printf("%s\n", str);
str = strtok(NULL, p);
printf("%s\n", str);
return 0;
}
代碼展示:(這個代碼更加的方便)
#include <stdio.h>
int main()
{
const char* p = "@.";
char arr[] = "abxbcbhd@nckdc.cidhc";
char buf[50] = { 0 };//因為字符串會被修改,所以要吧arr臨時拷貝到buf里
//要保證arr不被修改
strcpy(buf, arr);//臨時拷貝
char* str = NULL;
for (str = strtok(buf, p); str != NULL; str = strtok(NULL, p))
{
printf("%s\n", str);
}
return 0;
}
1.10 strerror
char * strerror ( int errnum );
返回錯誤碼,所對應的錯誤信息(把錯誤碼翻譯成錯誤信息)
C語言中規定了一些信息
錯誤碼—錯誤信息
0—No Error
1— …
2—…
當庫函數使用的時候,發生錯誤的時候會把errno這個全局的錯誤變量設置為本次執行庫函數產生的錯誤碼。
errno是C語言提供的全局變量,可以直接使用,放在errno.h 這個文件,所以要引用
#include <errno.h> strerror(errno);就會把錯誤顯示出來
代碼展示:
#include <stdio.h>
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%s\n", strerror(i));
}
return 0;
}
字符分類函數
上圖為字符分類函數,例如:isspace,如果是空白字符,就返回非0。不是空白字符就返回0。
別的和這個用法差不多。
代碼展示:
#include <stdio.h>
#include <ctype.h>
int main()
{
printf("%d\n", isspace(' '));
return 0;
}
字符轉換函數
int tolower(int c);
int toupper(int c);
#include <stdio.h>
int main()
{
char ch = 0;
ch = getchar();
if (islower(ch))
{
ch = toupper(ch);
}
else
{
ch = tolower(ch);
}
printf("%c\n", ch);
return 0;
}
大小寫轉換
1.11 memcpy
void * memcpy ( void * destination, const void * source, size_t num );
(1)函數memcpy從source的位置開始向后復制num個字節的數據到destination的內存位置。
(2)這個函數在遇到 '\0' 的時候并不會停下來。
(3)如果source和destination有任何的重疊,復制的結果都是未定義的。如果destination在source的后面,就可能會導致剛改變的destination的內容,又變成了source. 就會導致重復。這種情況建議使用memmove,就不會發生。
代碼展示:
#include <stdio.h>
int main()
{
char arr1[] = "sjhjcd";
char arr2[50] = { 0 };
strcpy(arr2, arr1);//拷貝字符串
int arr3[] = { 1, 2,3,4,5,6,7 };
int arr4[5] = { 0 };
memcpy(arr4, arr3, 20);//這個什么都可以拷貝,不確定拷貝什么
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", arr4[i]);
}
return 0;
}
C語言只要求memcpy能拷貝不重疊的的內存空間就足夠了,memmove去處理那些重疊的內存空間。但是VS 的memcpy可以處理重疊的內存拷貝,也可以處理不重疊的內存拷貝。
1.12 memmove
void * memmove ( void * destination, const void * source, size_t num );
(1)和memcpy的差別就是memmove函數處理的源內存塊和目標內存塊是可以重疊的。
(2)如果源空間和目標空間出現重疊,就得使用memmove函數處理。
memmove 也可以處理不重疊的。
1.13 memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
(1)比較從ptr1和ptr2指針開始的num個字節
(2)返回值如下:
比較的是字節,相等的話,返回0。 比較的是ASCII值。
1.14 memset
代碼展示:
#include <stdio.h>
int main()
{
char arr[20] = { 0 };
memset(arr, 'x', 10);
return 0;
}
以字節為單位改。
二 庫函數的模擬實現
2.1 模擬實現strlen
1 計數器的方法
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
assert(str);
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
int len = 0;
len = my_strlen("abcdefg");//傳遞給my _strlen的是字符'a'的地址
printf("%d", len);
return 0;
}
\0 的ASCII碼值是 0 ,一個表示字符串結束的標志,這是一個轉義字符,整體視為一個字符,在內存中的存儲為0000 0000
字符在內存中是以ASCII碼值對應的二進制的補碼存在的(8位)
2.2 模擬實現strcpy
代碼展示:
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* a, const char* b)
{
assert(a && b);
char* ret = a;
while (*a++ = *b++)//++的優先級大于*的優先級
{
;
}
return ret;
}
int main()
{
char arr1[20] = { 0 };
char arr2[] = "hello";
printf("%s\n", my_strcpy(arr1, arr2));//函數的鏈式訪問
return 0;
}
盡量不要返回局部變量的地址(調用的那個函數,里面的局部變量,使用完就可能被銷毀了,地址指向的局部變量的值,可能就變了),而不是局部變量。
2.3 模擬實現strcat
代碼展示:
#include <stdio.h>
#include <assert.h>
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
while (*dest)
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[30] = "hello";
char arr2[] = "world";
my_strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
思路:(1)找到目標空間中的\0 (2)追加字符
everyting——搜索strcat——右擊 打開路徑
2.4 模擬實現strstr
代碼展示:
#include <stdio.h>
#include <assert.h>
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
if (*str2 == '\0')
{
return (char*)str1;//(const char* 和char*還是不同的)
}
//當第一個字符出現匹配,后續字母中出現不匹配的時候,字符串的地址要回到出現匹配的第一個字符,的下一個字符的地址,
//所以盡可能不要直接用str1和str2,而是間接的使用
const char* s1 = str1;
const char* s2 = str2;
const char* s3 = str1;//遇到匹配的第一個字符前一直在+1
while (*s3)//在這個循環里,s3一直在+1,一直到s3遇到\0 ,while結束
{
s1 = s3;
s2 = str2;
while (*s1 != '\0' && *s2 != '\0' && * s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return (char*)s3;
s3++;
}
return NULL;
}
int main()
{
char arr1[] = "abcdabcd";
char arr2[] = "A";
char* ret = my_strstr(arr1, arr2);
if (ret == NULL)
printf("找不到");
else
printf("%s\n", ret);
return 0;
}
2.5 模擬實現strcmp
代碼展示:
#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++;
}
if (*str1 > *str2)
return 1;
else
return -1;
}
int main()
{
char arr1[] = "abc";
char arr2[] = "abcd";
int ret = my_strcmp(arr1, arr2);
printf("%d", ret);
return 0;
}
"abcd" 和"abc"比較,是1 因為,第一個字符串是d的ASCII,后一個字符串是'\0'的ascii,所以是1.
2.6 模擬實現memcpy
代碼展示:
#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, 20);
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", arr4[i]);
}
return 0;
}
知識點:
(1)void* 不能進行加減,所以轉換成char *進行加減。
2.7 模擬實現memmove
代碼展示:
#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;
}
#include <stdio.h>
int main()
{
int arr3[] = { 1, 2,3,4,5,6,7, 8, 9, 10 };
my_memmove(arr3+1, arr3, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr3[i]);
}
return 0;
}
原文鏈接:https://blog.csdn.net/m0_57388581/article/details/124209740
- 上一篇:輕松手寫Spring的IOC
- 下一篇:用C語言實現掃雷
相關推薦
- 2023-01-01 React路由動畫切換實現過程詳解_React
- 2022-03-23 深入淺析OpenCV?copyTo()函數_C 語言
- 2022-08-13 Redis - 數據結構和持久化機制
- 2024-02-28 CSS,文本溢出顯示省略號
- 2022-08-02 c#?Task.Wait()與awaiat?Task異常處理的區別說明_C#教程
- 2022-07-30 注冊中心eureka的介紹及源碼探索
- 2022-04-14 error: failed to push some refs to ‘http://git.tex
- 2022-06-19 教你cmd?bat文件中調用另一個bat文件的方法_DOS/BAT
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支