一、求字符串長度函數(shù)(strlen)
包含在<string.h>頭文件里
功能:返回字符串中有效字符的個(gè)數(shù),遇到‘\0’結(jié)束,不包括結(jié)束符‘\0’.
- 函數(shù)的參數(shù)為------const char* str:字符指針
- 返回值的類型------size_t:無符號(hào)整數(shù)(即:unsigned int)
模擬實(shí)現(xiàn)strlen:
方法一:計(jì)數(shù)器的方法
#include <stdio.h>
int my_strlen(char* p)
{
int n= 0;
while (*p++ != '\0')
{
n++;
}
return n;
}
int main()
{
char arr[10] = "abcdefghi";
int num = my_strlen(arr);//統(tǒng)計(jì)字符串的個(gè)數(shù)
printf("%d\n", num);
return 0;
}
方法二:不能創(chuàng)建臨時(shí)變量的計(jì)數(shù)器
#include <stdio.h>
int my_strlen(char* p)
{
if (*p == '\0')
return 0;
return 1 + my_strlen(++p);//p的地址加1,然后傳遞過去
}
int main()
{
char arr[10] = "abcdefghi";
int num = my_strlen(arr);
printf("%d\n", num);
return 0;
}
方法三:用指針-指針的方法
#include <stdio.h>
int my_strlen(char* p)
{
char* p1 = p;
while (*p1 != '\0')
p1++;
return p1 - p;//指向同個(gè)數(shù)組的兩個(gè)指針相減,得到的數(shù)為 指針之間的元素個(gè)數(shù)
}
int main()
{
char arr[10] = "abcdefghi";
int num = my_strlen(arr);
printf("%d\n", num);
return 0;
}
二、長度不受限制的字符串函數(shù)
包含在<string.h>頭文件里
2.1字符串拷貝函數(shù)(strcpy)
功能:
源字符串必須以‘\0’結(jié)束。
會(huì)將源字符串里的‘\0’拷貝到目標(biāo)空間。
目標(biāo)空間足夠大,以確保存放源字符串。
目標(biāo)空間必須可變
- 函數(shù)的參數(shù):
char* destination---------目標(biāo)字符串的首地址
const char* source------源地址:被復(fù)制的字符串的首地址,用const
飾,避免修改掉被拷貝的字符串 - 函數(shù)的返回值類型:char*:返回的是目標(biāo)字符串的首地址
模擬實(shí)現(xiàn)strcpy:
#include <stdio.h>
char* my_strcpy(char* p, char* p1)//char*類型為了實(shí)現(xiàn)鏈?zhǔn)皆L問
{
char* dest = p;
while (*p1 != '\0')
{
*p = *p1;
p++;
p1++;
}
*p=*p1;
return dest;
}
int main()
{
char arr1[20] = { '1','2','3','4','5','6','7','8','9','a','b','c','d'};
char arr2[] = "hello math";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
2.2字符串連接函數(shù)(strcat)
功能:
連接兩個(gè)字符數(shù)組中的字符串,將源字符串的內(nèi)容連接到目標(biāo)空間中字符串后面,結(jié)果放到目標(biāo)空間中。(源字符串和目標(biāo)空間中要有‘\0’)
不能自己給自己追加
模擬實(shí)現(xiàn)strcat:
#include <stdio.h>
char* my_strcat(char* dest, const char* sour)//為了實(shí)現(xiàn)鏈?zhǔn)皆L問
{
char* ret = dest;//ret指向目標(biāo)空間首地址
while (*dest != '\0')//找到目標(biāo)空間的’\0‘
{
dest++;
}
while (*sour != '\0')//源字符串不等于’\0‘就一直循環(huán)
{
*dest = *sour;//把源字符串的內(nèi)容連接到目標(biāo)空間
dest++;
sour++;
}
*dest = *sour;
return ret;
}
int main()
{
char arr1[20] = "1234567";
char arr2[] = "hello math";
my_strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
2.3字符串比較函數(shù)(strcmp)
功能:
比較str1和str2.
- str1大于str2,函數(shù)返回值為1
- str小于str2,函數(shù)返回值為-1
- str等于str2,函數(shù)返回值為0
模擬實(shí)現(xiàn)strcmp:
#include <stdio.h>
int my_strcmp(const char* str1, const char* str2)//返回1個(gè)整型
{
while (*str1 == *str2)//字符串1和字符串2相等就循環(huán)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
if (*str1 > *str2)
return 1;
else
return -1;
}
int main()
{
char arr1[20] = "hello pan";
char arr2[] = "hello math";
int n=my_strcmp(arr1, arr2);
printf("%d\n", n);
return 0;
}
三、長度受限制的字符串函數(shù)
3.1strncpy
源字符串的num個(gè)字符拷貝到目標(biāo)空間
功能:把src所指由NULL結(jié)束的字符串的前n個(gè)字節(jié)復(fù)制到dest所指的數(shù)組中。
說明:如果src的前n個(gè)字節(jié)不含NULL字符,則結(jié)果不會(huì)以NULL字符結(jié)束。
如果src的長度小于n個(gè)字節(jié),則以NULL填充dest直到復(fù)制完n個(gè)字節(jié)。
src和dest所指內(nèi)存區(qū)域不可以重疊且dest必須有足夠的空間來容納src的字符串。
返回指向dest的指針 。
#include <stdio.h>
#include <assert.h>
char* strncpy_(char* p1, char* p2, int x)
{
assert(p1);//斷言目標(biāo)空間不能為空
assert(p2);
char* dest = p1;
while (x--&&*p2)//p2拷貝到'\0'或拷貝結(jié)束
{
*dest=*p2;
dest++;
p2++;
}
if (!*p2)//p2拷貝完了為真
{
while (x--)//對(duì)多的數(shù)進(jìn)行拷貝
{
*dest = '\0';
dest++;
}
}
return p1;
}
void text_1()
{
char arr1[] = "abcdef";
char arr2[10] = { 1,2,3,4,5,6,7,8,9,0 };
strncpy_(arr2, arr1, 9);
printf("%s", arr2);
}
int main()
{
text_1();//模擬實(shí)現(xiàn)strncpy
return 0;
}
注意:不用關(guān)注‘\0’,源字符串拷貝到目標(biāo)空間,多的部分就是‘\0’;
3.2strncat
源字符串的num個(gè)字符連接到目標(biāo)空間
功能:
拷貝的字符數(shù)量大于源字符串長度時(shí),不管多幾個(gè)字符,都只添加1個(gè)‘\0’.
當(dāng)要拷貝的字符數(shù)量小于源字符串長度時(shí),自動(dòng)添加’\0‘。
當(dāng)要拷貝的字符數(shù)量小于源字符串長度時(shí),自動(dòng)添加’\0‘。
#include <stdio.h>
#include <assert.h>
char* my_strncat(char* dest,char* sur, int n)
{
assert(dest);//斷言目標(biāo)空間不能為空
assert(sur);
char* cur = dest;
while (*cur)//找到‘\0’跳出
{
cur++;
}
while (n--)//給目標(biāo)空間賦值,賦了n次
{
*cur = *sur;
cur++;
sur++;
}
return dest;
}
void text_2()
{
char arr1[20] = "123456";
char arr2[20] = "567890";
my_strncat(arr1,arr2,8);
printf("%s\n", arr1);
}
int main()
{
text_2();//模擬實(shí)現(xiàn)strncat
return 0;
}
3.3strncmp
源字符串的num個(gè)字符與目標(biāo)空間進(jìn)行比較
功能:
字符串大小的比較是以ASCII 碼表上的順序來決定,此順序?yàn)樽址闹怠trncmp()首先將dest 第一個(gè)字符值減去sur 第一個(gè)字符值,若差值為0 則再繼續(xù)比較下個(gè)字符,直到字符結(jié)束標(biāo)志’\0’,若差值不為0,則將差值返回。例如字符串"Ac"和"ba"比較則會(huì)返回差值(-33)
#include <stdio.h>
#include <assert.h>
int my_strncmp(char* dest, char* sur, int x)
{
assert(dest);
assert(sur);
assert(x);
while (--x && *dest == *sur && *dest && *sur)//兩個(gè)字符不相等或者任意一個(gè)字符為空就跳出循環(huán)或比較完n個(gè)字符
{
dest++;
sur++;
}
return (*dest - *sur);
}
void text_3()
{
char arr1[20] = "abcdef";
char arr2[20] = "abCdeF";
printf("%d\n", my_strncmp(arr1, arr2, 2));
}
int main()
{
text_3();//模擬實(shí)現(xiàn)strncmp
return 0;
}
四、字符串查找函數(shù)
4.1strstr
在字符串中找子字符串找不到返回NULL(空指針)
功能:strstr()是一個(gè),參數(shù)為兩個(gè)字符指針類型,返回值是char類型的函數(shù),它用于找到子串(str2)在一個(gè)字符串(str1)中第一次出現(xiàn)的位置。這里因?yàn)閭鬟M(jìn)來的地址指向的內(nèi)容不會(huì)在發(fā)生改變,所以我們?cè)趦蓚€(gè)形參(char)前加上const.
#include <stdio.h>
#include <assert.h>
const char* my_strstr(const char * str1, const char* str2)//模擬實(shí)現(xiàn)strstr
{
char* s1=NULL, * s2=NULL, * cur = str1;
if (str2 == '\0')
return str1;
while (*cur)
{
//指針回退
s1 = cur;//把cur地址先存起來
s2 = str2;//s2指向需要查找的子字符串首地址
while (*s1 && *s2 && (*s1 == *s2))//*s1或者*s2或者兩者不等的時(shí)候跳出循環(huán)
{
s1++;
s2++;
}
if (*s2 == '\0')//找到了那個(gè)子字符串
{
return cur;
}
if (*s1 == '\0')//沒有找到字符串
{
return NULL;
}
cur++; //當(dāng)前cur指向的并不是子串第一次出現(xiàn)的首元素地址,指向的地址要往后跳一個(gè)字節(jié)
}
return NULL;//經(jīng)過以上的循環(huán)比較,沒有找到子字符串,返回空指針NULL
}
void text_4()
{
char arr1[20] = "Acdef";
char arr2[20] = "";
char* ret=my_strstr(arr1, arr2);//在字符串a(chǎn)rr1中找到子字符串2,返回第一次找到字符串2的位置
if (ret == NULL)
printf("沒找到\n");
else
printf("找到了\n%s\n",ret);
}
int main()
{
text_4();//模擬實(shí)現(xiàn)strstr
return 0;
}
4.2strtok
把str字符串中由符號(hào)隔開的字段拿出來
功能
第一個(gè)參數(shù)是要分割的字符串,第二個(gè)參數(shù)是分割字符串的分隔符。
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指針。
#include <stdio.h>
#include <string.h>
void test_1()
{
char str1[] = "yi_ge_xiao.nao@dai";
char str[] = "_.@";
char str2[25];//我們?cè)谑褂胹trtok函數(shù)時(shí)會(huì)改變函數(shù)的第一個(gè)參數(shù),所以我們?cè)趧?chuàng)建一個(gè)數(shù)組,不要用原字符串做參數(shù)
strcpy(str2, str1);
char* ret = strtok(str2, str);//第一個(gè)參數(shù)不為NULL,找到第一個(gè)字段,在字段后面吧分隔符換成‘\0’,strtok函數(shù)保存這個(gè)位置,返回字段的初始位置
for (ret; ret != NULL;)//循環(huán),把每個(gè)字段找出來
{
printf("%s ", ret);
ret = strtok(NULL, str);//如果第一個(gè)參數(shù)為NULL,函數(shù)將在同一個(gè)字符串中被保存的位置開始,查找下一個(gè)標(biāo)記。
}
}
int main()
{
test_1();//strtok的使用
return 0;
}
打印結(jié)果:
五、錯(cuò)誤信息報(bào)告(strerror)
功能:
把錯(cuò)誤碼翻譯成錯(cuò)誤信息
返回值:把錯(cuò)誤碼對(duì)應(yīng)錯(cuò)誤信息的字符串的首地址返回來。
庫函數(shù)在執(zhí)行的時(shí)候發(fā)生拉錯(cuò)位,會(huì)將錯(cuò)誤碼存放在errno這個(gè)變量中,errno是C語言提供的一個(gè)全局變量
如:
404->訪問的頁面不存在
例子:
#include <stdio.h>
#include <string.h>
void test_2()
{
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d->%s\n", i, strerror(i));
}
}
int main()
{
test_2();//strerror的使用
return 0;
}
打印結(jié)果:
表達(dá)的意思:
0->沒有錯(cuò)誤
1->操作被拒絕
2->沒有這個(gè)文件或文件夾
3->沒有這個(gè)進(jìn)程
4->函數(shù)調(diào)用被中斷
5->輸入輸出錯(cuò)誤
6->沒有這個(gè)設(shè)備和地址
7->參數(shù)列表太長
等……
如:
#include <stdio.h>
#include <string.h>
int main()
{
//c語言中可以操作文件
//操作文件的步驟
//打開文件
//讀或者寫
//關(guān)閉文件
//打印失敗
FILE* pf = fopen("data.txt","r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));//只打印錯(cuò)誤信息
//perror(“fopen”)//打印自定義信息(如fopen)然后加一個(gè)冒號(hào)和空格,在打印錯(cuò)誤信息。
return 1;
}
//讀文件
//關(guān)閉文件
fclose(pf);
return 0;
}
沒有這個(gè)文件:
如果有多個(gè)錯(cuò)誤:
用strerror(還可以用perror)只能一次翻譯一個(gè)錯(cuò)誤,如果一個(gè)問題有多個(gè)錯(cuò)誤,先翻譯第一個(gè)出現(xiàn)的錯(cuò)誤,我們解決這個(gè)錯(cuò)誤后,它會(huì)繼續(xù)報(bào)另外的錯(cuò)誤,所以我們遇到問題要及時(shí)更新。
六、字符操作函數(shù)
6.1字符分類函數(shù)
符合條件就打印非0值,不符合條件就打印0。
6.2字符轉(zhuǎn)換函數(shù)
大寫字母轉(zhuǎn)換為小寫字母函數(shù)(tolower)
小寫字母轉(zhuǎn)換為大寫字母函數(shù)(toupper)
#include <stdio.h>
#include <string.h>
int main()
{
printf("%c\n", tolower('A'));
printf("%c\n", toupper('a'));
return 0;
}
七、字符串大寫和小寫轉(zhuǎn)換函數(shù)
字符串大寫字母轉(zhuǎn)換成小寫字母函數(shù)(strlwr)
字符串小寫字母轉(zhuǎn)換成大寫字母函數(shù)(strupr)
#include <stdio.h>
#include <string.h>
int main()
{
char str1[] = "abcdEFGH1234";
printf("%s\n", _strlwr(str1));
printf("%s\n", _strupr(str1));
return 0;
}
八、內(nèi)存操作函數(shù)
8.1memcpy
用來處理不重疊的內(nèi)存拷貝
有三個(gè)參數(shù):
destination:一個(gè)指向目標(biāo)數(shù)組的指針,它的內(nèi)容將會(huì)被覆蓋。
source:一個(gè)指向了被拷貝數(shù)據(jù)的那個(gè)指針。
num:拷貝幾個(gè)字節(jié)(size_t就是unsigned int)
功能:函數(shù)memcpy從source位置開始向后復(fù)制num個(gè)字節(jié)的數(shù)據(jù)destination目標(biāo)空間里,然后返回目標(biāo)空間的初始地址。
這個(gè)函數(shù)遇到‘\0’的時(shí)候不會(huì)停下來。
如果source和destination有任何重疊的部分,復(fù)制的結(jié)果將未定義(結(jié)果于預(yù)料的值可能不一樣)
memcpy函數(shù)的模擬實(shí)現(xiàn)
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* dest, void* sur, size_t num)
{
assert(dest);
assert(sur);
void* ret = dest;
while (num--)
{
*(char*)dest = *(char*)sur;//每個(gè)字節(jié)進(jìn)行轉(zhuǎn)換
(char*)dest = (char*)dest + 1;//每個(gè)字節(jié)向后移一步
(char*)sur = (char*)sur + 1;
}
return ret;
}
void test_3()
{
int str1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int str2[20] = {0};
my_memcpy(str2, str1, 16);
int i = 0;
for (i = 0; i < 20; i++)
{
printf("%d ", str2[i]);
}
}
int main()
{
test_3();//mencpy的模擬實(shí)現(xiàn)
return 0;
}
如果我們稍微改一下
結(jié)果變成了1 2 1 2 1 2 7 8 9 10
說明memcpy不能重疊內(nèi)存拷貝
8.2memmove
可以處理重疊的內(nèi)存拷貝
和memcpy的差別就是memmove函數(shù)處理的源內(nèi)存塊和目標(biāo)內(nèi)存塊是可以重疊得。
如果源空間和目標(biāo)空間出現(xiàn)重疊,就使用memmove函數(shù)處理
memmove函數(shù)的模擬實(shí)現(xiàn)
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memmove(void* dest, void* sur, size_t num)
{
void* ret = dest;
assert(dest);
assert(sur);
if (dest <= sur || ((char*)sur + num) <= (char*)dest)
{
while (num--)
{
*(char*)dest = *(char*)sur;//每個(gè)字節(jié)進(jìn)行轉(zhuǎn)換
dest = (char*)dest + 1;//每個(gè)字節(jié)向后移一步
sur = (char*)sur + 1;
}
}
else
{
while (num--)//20
{
*((char*)dest+num) = *((char*)sur+num);//每個(gè)字節(jié)進(jìn)行轉(zhuǎn)換
}
}
return ret;
}
void test_4()
{
int str1[10] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(str1 + 2, str1, 16);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", str1[i]);
}
}
int main()
{
test_4();//memmove函數(shù)的模擬實(shí)現(xiàn)
return 0;
}
打?。?br>
在數(shù)組中,地址是由低到高得,如果dest的地址小于等于sur的地址,可以從前往后進(jìn)行遍歷拷貝;sur跳過num個(gè)的地址如果大于等于dest的地址可以從前往后遍歷拷貝,也可以從后往前遍歷拷貝。
8.3memset
內(nèi)存設(shè)置
功能:填充內(nèi)存塊
ptr所指向的前num個(gè)字節(jié)的內(nèi)容,設(shè)置成我們想要的value值(把所有字節(jié)都設(shè)置成一個(gè)值)
#include <stdio.h>
#include <string.h>
int main()//內(nèi)存設(shè)置
{
char arr[] = "panlongjun";
memset(arr + 1, 'L', 2);
printf("%s\n", arr);
return 0;
}
8.4memcmp
內(nèi)存比較函數(shù)(一個(gè)字節(jié)一個(gè)字節(jié)往后比較)
功能:
- ptr1大于ptr2,函數(shù)返回值為1
- ptr1小于ptr2,函數(shù)返回值為-1
- ptr1r等于ptr2,函數(shù)返回值為0
#include <stdio.h>
#include <string.h>
int main()//內(nèi)存比較
{
int arr1[] = { 1,2,1,4,5,6 };
int arr2[] = { 1,2,257,12,34 };
int ret = memcmp(arr1, arr2, 9);
printf("%d\n", ret);
return 0;
}
打印:
memcmp是內(nèi)存比較函數(shù),在內(nèi)存空間里一個(gè)一個(gè)字節(jié)進(jìn)行比較(比較9個(gè)字節(jié),結(jié)果為0)文章來源:http://www.zghlxwxcb.cn/news/detail-635012.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-635012.html
到了這里,關(guān)于c語言——字符串函數(shù)和內(nèi)存操作函數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!