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是專門為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',回車‘\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ù)字或者字母的圖形字符(可打印) |
| 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-03
Cocos2d-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-09
QT編寫(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

