?文章來源:http://www.zghlxwxcb.cn/news/detail-661080.html
目錄
1.求字符串長度strlen
2.長度不受限制的字符串函數(shù)
字符串拷貝strcpy
字符串追加strcat
字符串比較strcmp
3.長度受限制的字符串函數(shù)介紹strncpy
strncat
?編輯strncmp
4.字符串查找strstr
5.字符串分割strtok
6.錯(cuò)誤信息報(bào)告
strerror
perror
7.字符分類函數(shù)
8.字符轉(zhuǎn)換函數(shù)
?9.內(nèi)存操作函數(shù)
memcpy
memmove
?memset
?memcmp?編輯
1.求字符串長度strlen
函數(shù)介紹
- 字符串已經(jīng) '\0' 作為結(jié)束標(biāo)志,strlen函數(shù)返回的是在字符串中 '\0' 前面出現(xiàn)的字符個(gè)數(shù)(不包含 '\0' )。
- 參數(shù)指向的字符串必須要以 '\0' 結(jié)束。
- 注意函數(shù)的返回值為size_t,是無符號(hào)的( 易錯(cuò) )?
使用示例
int main()
{
size_t sz = strlen("abcd");
printf("%u", sz);
return 0;
}
因?yàn)楹瘮?shù)的返回值為無符號(hào)類型,所以對(duì)于下面這種代碼,我們很容易就看錯(cuò):
#include<stdio.h>
#include<string.h>
int main()
{
if (strlen("abc") - strlen("abcdef") > 0)
{
printf("大于\n");
}
else
{
printf("小于\n");
}
return 0;
}
輸出結(jié)果:
?正確的比較方法:
if (strlen("abc") > strlen("abcdef"))
strlen的模擬實(shí)現(xiàn)
size_t my_strlen(const char* str)
{
int count = 0;
while (*str!='\0')
{
count++;
str++;
}
return count;
}
2.長度不受限制的字符串函數(shù)
字符串拷貝strcpy
- Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
- 源字符串必須以 '\0' 結(jié)束。
- 會(huì)將源字符串中的 '\0' 拷貝到目標(biāo)空間。
- 目標(biāo)空間必須足夠大,以確保能存放源字符串。
- 目標(biāo)空間必須可變
使用示例
int main()
{
char arr1[20] = { 0 };
char arr2[] = "hello world";
strcpy(arr1, arr2);
printf("%s", arr1);
return 0;
}
輸出結(jié)果:?
strcpy的模擬實(shí)現(xiàn)
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
while (*dest++ = *src++)
{
}
return ret;
}
字符串追加strcat
- ?Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.
- 源字符串必須以 '\0' 結(jié)束。
- 目標(biāo)空間必須有足夠的大,能容納下源字符串的內(nèi)容。
- 目標(biāo)空間必須可修改。
- 字符串自己給自己追加,如何?
?使用示例
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
strcat(arr1, arr2);
printf("%s", arr1);
return 0;
}
輸出結(jié)果:?
?strcat的模擬實(shí)現(xiàn)
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
while (*dest != '\0')//找到目標(biāo)空間的\0
{
dest++;
}
while (*dest++ = *src++)
{
}
return ret;
}
注意:字符串不能自己給自己追加?
當(dāng)字符串自己給自己追加時(shí),字符串中的'\0'將會(huì)被覆蓋,導(dǎo)致程序陷入死循環(huán)。
字符串比較strcmp
- ?This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ or until a terminating null-character is reached.
- 標(biāo)準(zhǔn)規(guī)定:
- 第一個(gè)字符串大于第二個(gè)字符串,則返回大于0的數(shù)字
- 第一個(gè)字符串等于第二個(gè)字符串,則返回0
- 第一個(gè)字符串小于第二個(gè)字符串,則返回小于0的數(shù)字
使用示例
int main()
{
int ret1 = strcmp("abcdef", "abq");
int ret2 = strcmp("abc", "abc");
printf("%d\n", ret1);
printf("%d\n", ret2);
return 0;
}
?輸出結(jié)果:?
strcmp的模擬實(shí)現(xiàn)
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1++ == *str2++)
{
if (*str1 == '\0')
{
return 0;
}
}
return *str1 - *str2;
}
3.長度受限制的字符串函數(shù)介紹 strncpy
- Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
- 拷貝num個(gè)字符從源字符串到目標(biāo)空間。
- 如果源字符串的長度小于num,則拷貝完源字符串之后,在目標(biāo)的后邊追加0,直到num個(gè)。
使用示例
int main()
{
char arr1[20] = "abcdef";
char arr2[20] = "xxxxxxxxxxxxxx";
strncpy(arr1, arr2, 3);
printf("%s\n", arr1);
return 0;
}
輸出結(jié)果:?
strncat
- Appends the first num characters of source to destination, plus a terminating null-character.
- If the length of the C string in source is less than num, only the content up to the terminating null-character is copied.
使用示例
int main()
{
char arr1[20] = "hello ";
char arr2[20] = "worldxxx";
strncat(arr1, arr2, 5);
printf("%s\n", arr1);
return 0;
}
輸出結(jié)果:?
strncmp
?比較到出現(xiàn)另個(gè)字符不一樣或者一個(gè)字符串結(jié)束或者num個(gè)字符全部比較完。
?使用示例
int main()
{
char arr1[20] = "abc";
char arr2[20] = "abcdef";
char arr3[20] = "aba";
printf("%d\n", strncmp(arr1, arr2, 3));
printf("%d\n", strncmp(arr1, arr2, 4));
printf("%d\n", strncmp(arr1, arr3, 5));
return 0;
}
輸出結(jié)果:?
4.字符串查找strstr
strstr函數(shù)是在字符串str1中查找是否含有字符串str2,如果存在,返回str2在str1中第一次出現(xiàn)的地址;否則返回NULL。
使用示例
int main()
{
char arr1[] = "abcdefabcdef";
char arr2[] = "def";
char* ret = strstr(arr1, arr2);
if(ret!=NULL)
{
printf("%s\n", ret);
}
return 0;
}
輸出結(jié)果:?
?strstr的模擬實(shí)現(xiàn)
這里使用的是BF算法來實(shí)現(xiàn):
char* my_strstr(char* str1, char* str2)
{
char* cp = str1;
char* s1 = cp;
char* s2 = str2;
while (*cp)
{
s1 = cp;
s2 = str2;
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return cp;
cp++;
}
return NULL;
}
5.字符串分割strtok
- 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è)字符串中被保存的位置開始,查找下一個(gè)標(biāo)記。
- 如果字符串中不存在更多的標(biāo)記,則返回 NULL 指針。
使用示例1
int main()
{
char arr[] = "123@qq.com";
char sep[] = "@.";
char copy[20];
strcpy(copy, arr);
char* pc = strtok(copy, sep);
while (pc)
{
puts(pc);
pc = strtok(NULL, sep);
}
return 0;
}
使用示例2
int main()
{
char arr[] = "123@qq.com";
char sep[] = "@.";
char copy[20];
strcpy(copy, arr);
char* ret = NULL;
for (ret = strtok(copy, sep); ret != NULL; ret = strtok(NULL, sep))
{
printf("%s\n", ret);
}
return 0;
}
輸出結(jié)果:?
6.錯(cuò)誤信息報(bào)告
strerror
?返回錯(cuò)誤碼,所對(duì)應(yīng)的錯(cuò)誤信息。
庫函數(shù)在執(zhí)行的時(shí)候,發(fā)生了錯(cuò)誤會(huì)將錯(cuò)誤碼存放在errno這個(gè)全局變量中。errno是C語言提供的一個(gè)全局變量。
下面代碼是將錯(cuò)誤碼0~9所對(duì)應(yīng)的錯(cuò)誤信息給打印出來:
int main()
{
int i = 0;
for (int i = 0; i < 10; i++)
{
printf("%d:%s\n", i, strerror(i));
}
return 0;
}
?當(dāng)然,這里展示的僅僅是一小部分。
下面演示一下當(dāng)我們進(jìn)行文件操作是,打開文件失敗后查找打開失敗的原因:
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
}
return 0;
}
程序輸出了“ No such file or directory ”的錯(cuò)誤提示,意思是沒有要打開的文件。
perror
perror(str) 用來將上一個(gè)函數(shù)發(fā)生錯(cuò)誤的原因輸出到標(biāo)準(zhǔn)設(shè)備(stderr)。參數(shù) str 所指的字符串會(huì)先打印出,后面再加上錯(cuò)誤原因字符串。此錯(cuò)誤原因依照全局變量errno的值來決定要輸出的字符串。
使用示例
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
perror("fopen");
}
return 0;
}
?輸出結(jié)果:
7.字符分類函數(shù)
8.字符轉(zhuǎn)換函數(shù)
?下面代碼的功能是輸入一串字符,將字符串中的小寫字母轉(zhuǎn)成大寫,大寫字母轉(zhuǎn)成小寫
int main()
{
char arr[30] = { 0 };
gets(arr);
char* p = arr;
while (*p)
{
if (isupper(*p))
{
*p = tolower(*p);
}
else if (islower(*p))
{
*p = toupper(*p);
}
*p++;
}
puts(arr);
}
? 9.內(nèi)存操作函數(shù)
memcpy
- 函數(shù)memcpy從source的位置開始向后復(fù)制num個(gè)字節(jié)的數(shù)據(jù)到destination的內(nèi)存位置。
- 這個(gè)函數(shù)在遇到 '\0' 的時(shí)候并不會(huì)停下來。
- 如果source和destination有任何的重疊,復(fù)制的結(jié)果都是未定義的。
可以拷貝任意類型的數(shù)據(jù):字符串,整形數(shù)組,結(jié)構(gòu)體數(shù)據(jù)類型……
使用示例
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
//將arr1的內(nèi)容拷貝到arr2中
memcpy(arr2, arr1, 40);
for (int i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
?輸出結(jié)果:
?memcpy的模擬實(shí)現(xiàn)
void* my_memcpy(void* dest, void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
注意下面這種寫法編譯器會(huì)報(bào)錯(cuò):
在代碼中,使用了(char*)dest++
和(char*)src++
來更新指針的位置。然而,這種寫法是不正確的,因?yàn)楹缶Y遞增操作符++
的優(yōu)先級(jí)高于類型轉(zhuǎn)換操作符(char*)
,所以實(shí)際上你只是在轉(zhuǎn)換指針類型后遞增了一個(gè)臨時(shí)變量,而沒有更新指針本身的值。
注意:mencpy 函數(shù)是用來處理不會(huì)重疊的內(nèi)存拷貝,當(dāng)我們拷貝兩個(gè)相同的字符串是,可以結(jié)果與預(yù)期的會(huì)不相同:
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memcpy(arr1+2, arr1, 32);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
printf("\n");
return 0;
}
對(duì)于上面的代碼,我們的預(yù)期結(jié)果是這樣的:
?實(shí)際輸出的結(jié)果卻是如下:
?如果要拷貝重疊的內(nèi)存,我們就要使用下面這個(gè)函數(shù)了
memmove
- 和memcpy的差別就是memmove函數(shù)處理的源內(nèi)存塊和目標(biāo)內(nèi)存塊是可以重疊的。
- 如果源空間和目標(biāo)空間出現(xiàn)重疊,就得使用memmove函數(shù)處理。
使用示例
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1+2, arr1, 32);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
printf("\n");
return 0;
}
?輸出結(jié)果:
?memmove的模擬實(shí)現(xiàn)
不同于memcpy,mommove的拷貝需要分情況:
void* my_memmove(void* dest, const void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
if (dest < src)
{
//從前向后拷貝
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
printf("從后向前拷貝\n");
//從后向前拷貝
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
? memset
?memset是一個(gè)初始化函數(shù),作用是將某一塊內(nèi)存中的全部設(shè)置為指定的值。
- prr 指向要填充的內(nèi)存塊。
- value 是要被設(shè)置的值。
- num 是要被設(shè)置該值的字符數(shù)。
- 返回類型是一個(gè)指向存儲(chǔ)區(qū)s的指針。
使用示例1
int main()
{
char arr[] = "hello world";
memset(arr + 1, 'x', 4);
printf("%s\n", arr);
return 0;
}
上面代碼的作用是將的arr數(shù)組的第2個(gè)元素到第5個(gè)元素的值設(shè)置成‘x',輸出結(jié)果:
使用示例2
int main()
{
int arr[10] = { 0 };
memset(arr, 1, 10);
return 0;
}
? memcmp
比較從ptr1和ptr2指針開始的num個(gè)字節(jié)
返回值如下:
?使用示例
int main()
{
int arr1[] = { 1,2,1,4,5,6 };
int arr2[] = { 1,2,257 };
int ret = memcmp(arr1, arr2, 9);
printf("%d\n", ret);
return 0;
}
對(duì)于上面的代碼,可以借助編譯器的調(diào)試來查看 arr1 和 arr2 的內(nèi)存:
可以看出,arr1和arr2的前9個(gè)字節(jié)是相同的,而我們比較的是前9個(gè)字節(jié),因此輸出結(jié)果應(yīng)該是0。?
?
文章來源地址http://www.zghlxwxcb.cn/news/detail-661080.html
到了這里,關(guān)于【C語言】字符函數(shù)和字符串函數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!