文章目錄
- 一、字符分類函數
- 二、字符轉換函數
- 三、strlen函數:計算字符串長度
- 功能說明
- 使用示例
- 模擬實現
- 四、strcpy函數:字符串拷貝
- 功能說明
- 模擬實現
- 五、strcat函數:字符串追加
- 功能說明
- 模擬實現
- 六、strcmp函數:字符串比較
- 比較規則
- 模擬實現
- 七、strncpy函數:指定長度的字符串拷貝
- 功能說明
- 八、strncat函數:指定長度的字符串追加
- 功能說明
- 九、strncmp函數:指定長度的字符串比較
- 功能說明
- 十、strstr函數:查找子字符串
- 功能說明
- 模擬實現
- 十一、strtok函數:字符串分割
- 功能說明
- 十二、strerror函數:獲取錯誤信息
- 功能說明
- 相關函數:perror
在C語言編程中,字符和字符串的處理是非常基礎且重要的操作。C語言標準庫提供了一系列專門用于處理字符和字符串的庫函數,掌握這些函數能極大地提高編程效率。本文將詳細介紹這些函數的使用方法和模擬實現,幫助大家深入理解并靈活運用。
一、字符分類函數
字符分類函數用于判斷一個字符屬于哪種類型,它們都包含在ctype.h
頭文件中。這些函數的參數為 int
類型 , 返回值為 非0(真)或0(假)。
以下是常用的字符分類函數及其功能:
iscntrl
:判斷是否為控制字符isspace
:判斷是否為空白字符(空格' '
、換頁'\f'
、換行'\n'
、回車'\r'
、制表符'\t'
、垂直制表符'\v'
)isdigit
:判斷是否為十進制數字(0~9)isxdigit
:判斷是否為十六進制數字(0~9、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
:判斷是否為任何可打印字符(包括圖形字符和空白字符)
示例:使用islower
函數
islower
函數用于判斷參數是否為小寫字母,是則返回非0整數,否則返回0。
下面的代碼將字符串中的小寫字母轉換為大寫,其他字符不變:
#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 (islower(c)) c -= 32;putchar(c);i++;}return 0;
}
二、字符轉換函數
C語言提供了兩個常用的字符轉換函數,同樣包含在ctype.h
頭文件中:
int tolower(int c)
:將大寫字母轉換為小寫int toupper(int c)
:將小寫字母轉換為大寫
示例:使用toupper
函數
將上面的小寫轉大寫代碼用toupper
函數改寫:
#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 (islower(c)) c = toupper(c);putchar(c);i++;}return 0;
}
三、strlen函數:計算字符串長度
strlen
函數用于計算字符串的長度,其原型為:
size_t strlen(const char *str);
功能說明
- 字符串以’\0’作為結束標志,
strlen
返回的是’\0’前面的字符個數(不包含’\0’) - 參數指向的字符串必須以’\0’結束
- 返回值為
size_t
(無符號整數),這一點在使用時容易出錯
使用示例
#include <stdio.h>
#include <string.h>
int main()
{const char* str1 = "abcdef";const char* str2 = "bbb";if(strlen(str2) - strlen(str1) > 0)printf("str2>str1\n");elseprintf("str1>str2\n");return 0;
}
注意:由于
strlen
返回值是無符號數,上面代碼中strlen(str2)-strlen(str1)
的結果是無符號數,可能會出現與預期不符的情況。
模擬實現
strlen
有多種模擬實現方式:
- 計數器方式
int my_strlen(const char *str)
{int count = 0;assert(str); // 確保指針非空while(*str){count++;str++;}return count;
}
- 遞歸方式(不創建臨時變量)
int my_strlen(const char *str)
{assert(str);if(*str == '\0')return 0;elsereturn 1 + my_strlen(str + 1);
}
- 指針-指針方式
int my_strlen(char *s)
{assert(s);char *p = s;while(*p != '\0')p++;return p - s;
}
四、strcpy函數:字符串拷貝
strcpy
函數用于將源字符串拷貝到目標空間,原型為:
char* strcpy(char *destination, const char *source);
功能說明
- 源字符串必須以’\0’結束
- 會將源字符串中的’\0’拷貝到目標空間
- 目標空間必須足夠大,以容納源字符串
- 目標空間必須可修改
模擬實現
char *my_strcpy(char *dest, const char*src)
{char *ret = dest;assert(dest != NULL);assert(src != NULL);while((*dest++ = *src++)){;}return ret;
}
實現說明:循環中先將
*src
賦值給*dest
,然后兩者都自增,直到拷貝到’\0’時,循環條件為假,結束循環。
五、strcat函數:字符串追加
strcat
函數用于將源字符串追加到目標字符串末尾,原型為:
char *strcat(char *destination, const char *source);
功能說明
- 源字符串必須以’\0’結束
- 目標字符串也必須以’\0’結束,否則無法確定追加的起始位置
- 目標空間必須足夠大,能容納源字符串的內容
- 目標空間必須可修改
- 字符串不能自己給自己追加,會導致錯誤
模擬實現
char *my_strcat(char *dest, const char*src)
{char *ret = dest;assert(dest != NULL);assert(src != NULL);// 找到目標字符串的結束標志'\0'while(*dest){dest++;}// 追加源字符串while((*dest++ = *src++)){;}return ret;
}
六、strcmp函數:字符串比較
strcmp
函數用于比較兩個字符串的大小,原型為:
int strcmp(const char *str1, const char *str2);
比較規則
- 從第一個字符開始比較,若相等則繼續比較下一對字符,直到字符不同或遇到’\0’
- 標準規定:
- 第一個字符串大于第二個字符串,返回大于0的數字
- 兩個字符串相等,返回0
- 第一個字符串小于第二個字符串,返回小于0的數字
- 比較的是對應位置字符的ASCII碼值
模擬實現
int my_strcmp(const char *str1, const char *str2)
{assert(str1 != NULL);assert(str2 != NULL);while(*str1 == *str2){if(*str1 == '\0')return 0;str1++;str2++;}return *str1 - *str2;
}
七、strncpy函數:指定長度的字符串拷貝
strncpy
函數可以指定拷貝的字符個數,原型為:
char *strncpy(char *destination, const char *source, size_t num);
功能說明
- 拷貝
num
個字符從源字符串到目標空間 - 如果源字符串的長度小于
num
,則拷貝完源字符串后,在目標空間后追加0,直到達到num
個字符
八、strncat函數:指定長度的字符串追加
strncat
函數用于將源字符串的前num
個字符追加到目標字符串,原型為:
char *strncat(char *destination, const char *source, size_t num);
功能說明
- 將源字符串的前
num
個字符追加到目標字符串末尾,并追加一個’\0’ - 如果源字符串的長度小于
num
,則只追加到源字符串的’\0’為止
使用示例
#include <stdio.h>
#include <string.h>
int main ()
{char str1[20];char str2[20];strcpy(str1,"To be ");strcpy(str2,"or not to be");strncat(str1, str2, 6);printf("%s\n", str1); // 輸出 "To be or not"return 0;
}
九、strncmp函數:指定長度的字符串比較
strncmp
函數用于比較兩個字符串的前num
個字符,原型為:
int strncmp(const char *str1, const char *str2, size_t num);
功能說明
- 比較兩個字符串的前
num
個字符 - 如果相等則繼續比較,最多比較
num
個字符 - 如果提前發現不同,則提前結束比較
- 返回值規則與
strcmp
相同
返回值 | 說明 |
---|---|
<0 | 第一個不匹配的字符在str1中的值小于在str2中的值 |
0 | 兩個字符串的前num個字符相等 |
>0 | 第一個不匹配的字符在str1中的值大于在str2中的值 |
十、strstr函數:查找子字符串
strstr
函數用于查找一個字符串在另一個字符串中第一次出現的位置,原型為:
char *strstr(const char *str1, const char *str2);
功能說明
- 返回字符串
str2
在字符串str1
中第一次出現的位置的指針 - 如果
str2
不是str1
的一部分,則返回空指針 - 匹配過程不包含’\0’,以’\0’作為結束標志
使用示例
#include <stdio.h>
#include <string.h>
int main ()
{char str[] = "This is a simple string";char *pch;pch = strstr(str, "simple");strncpy(pch, "sample", 6);printf("%s\n", str); // 輸出 "This is a sample string"return 0;
}
模擬實現
char *strstr(const char *str1, const char *str2)
{char *cp = (char *)str1;char *s1, *s2;if (!*str2)return (char *)str1;while (*cp){s1 = cp;s2 = (char *)str2;while (*s1 && *s2 && !(*s1 - *s2)){s1++;s2++;}if (!*s2)return cp;cp++;}return NULL;
}
十一、strtok函數:字符串分割
strtok
函數用于分割字符串,原型為:
char *strtok(char *str, const char *sep);
功能說明
sep
參數是一個字符串,定義了用作分隔符的字符集合- 第一個參數為
str
時,函數找到str
中的第一個標記,并用’\0’結尾,返回指向該標記的指針,同時保存該位置 - 第一個參數為
NULL
時,函數從上次保存的位置繼續查找下一個標記 - 如果沒有更多標記,返回
NULL
strtok
會修改被操作的字符串,所以通常對字符串的臨時拷貝進行操作
使用示例
#include <stdio.h>
#include <string.h>
int main()
{char arr[] = "192.168.6.111";char* sep = ".";char* str = NULL;for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep)){printf("%s\n", str);}return 0;
}
// 輸出:
// 192
// 168
// 6
// 111
十二、strerror函數:獲取錯誤信息
strerror
函數用于獲取錯誤碼對應的錯誤信息,原型為:
char *strerror(int errnum);
功能說明
- 參數
errnum
為錯誤碼,函數返回該錯誤碼對應的錯誤信息字符串的地址 - 錯誤碼通常定義在
errno.h
頭文件中 - 程序啟動時,
errno
(記錄當前錯誤碼的變量)為0,表示沒有錯誤 - 當標準庫函數發生錯誤時,會將對應的錯誤碼存入
errno
使用示例
- 打印0~10的錯誤碼對應的信息
#include <errno.h>
#include <string.h>
#include <stdio.h>
int main()
{int i = 0;for (i = 0; i <= 10; i++) {printf("%s\n", strerror(i));}return 0;
}
在Windows11+VS2022環境下的輸出如下:
No error
Operation not permitted
No such file or directory
No such process
Interrupted function call
Input/output error
No such device or address
Arg list too long
Exec format error
Bad file descriptor
No child processes
- 在文件操作中使用
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{FILE *pFile;pFile = fopen("unexist.ent", "r");if (pFile == NULL)printf("Error opening file unexist.ent: %s\n", strerror(errno));return 0;
}
// 輸出:Error opening file unexist.ent: No such file or directory
相關函數:perror
perror
函數可以直接打印錯誤信息,它會先打印參數中的字符串,再打印一個冒號和空格,最后打印錯誤信息。
#include <stdio.h>
#include <errno.h>
int main ()
{FILE *pFile;pFile = fopen("unexist.ent", "r");if (pFile == NULL)perror("Error opening file unexist.ent");return 0;
}
// 輸出:Error opening file unexist.ent: No such file or directory
本文詳細介紹了C語言中常用的字符函數和字符串函數,包括它們的功能、使用方法和模擬實現。這些函數在日常編程中非常實用,掌握它們能幫助我們更高效地處理字符和字符串操作。在使用過程中,要注意各個函數的參數要求和返回值特點,避免出現不必要的錯誤。