C語言詳解如何應(yīng)用模擬字符串和內(nèi)存函數(shù)
1.strlen 求字符串長度
size_t strlen ( const char * str ); //返回值是unsigned int類型
使用案例:
#include <stdio.h>
int main()
{
char arr[] = { "abcde" };
printf("%d\n",strlen(arr));
return 0;
}
我們知道在arr數(shù)組里,最后一個字符'e'后,默認是'\0',而strlen遇到'\0'則會結(jié)束運行,且返回的是在字符串中 '\0' 前面出現(xiàn)的字符個數(shù)(不包 含 '\0' )。
我們可以根據(jù)這個來對strlen進行模擬實現(xiàn):
1.計數(shù)法
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
assert(str);
int count = 0; //計數(shù)
while (*str) //解引用判斷元素是否為'\0'
{
count++;
str++; //地址++
}
return count; //返回計數(shù)
}
int main()
{
int len = my_strlen("abcdef");
printf("%d\n", len);
return 0;
}
2.不創(chuàng)建臨時變量計數(shù)器-遞歸
#include <stdio.h>
#include <assert.h>
int my_strlen(const char * str)
{
assert(str);
if (*str == '\0')
return 0;
else
return 1 + my_strlen(str + 1);
}
int main()
{
char arr[] = {"abcdef"};
int ret = my_strlen(arr);
printf("%d\n", ret);
return 0;
}
3.指針-指針的方式
#include <stdio.h>
#include <assert.h>
int my_strlen(char *s)
{
char *p = s;
while (*p != '\0')
p++;
return p - s; //指針相減是長度
}
int main()
{
char arr[] = {"abcdef"};
int ret = my_strlen(arr);
printf("%d\n", ret);
return 0;
}
2.長度不受限制的字符串函數(shù)
1.strcpy
char* strcpy(char * destination, const char * source );
源字符串必須以 '\0' 結(jié)束。
會將源字符串中的 '\0' 拷貝到目標空間。
目標空間必須足夠大,以確保能存放源字符串。
目標空間必須可變。
使用案例:
#include <stdio.h>
#include <assert.h>
int main()
{
char arr1[] = {'a', 'b', 'c', 'd', 'e', 'f', '\0'};
char arr2[20] = "xxxxxxxxxxxx";
strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
}

模擬實現(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++) //這里不打印'\0'之后的
{
;
}
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);
return 0;
}
2.strcat
char * strcat ( char * destination, const char * source );
源字符串必須以 '\0' 結(jié)束。
目標空間必須有足夠的大,能容納下源字符串的內(nèi)容。
目標空間必須可修改。
使用案例:
#include <stdio.h>
#include <assert.h>
int main()
{
char arr1[30] = "hello";//注意初始化方式,必須要包含'\0'
char arr2[] = "world";
strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}


模擬實現(xiàn):
#include <stdio.h>
#include <assert.h>
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
//保留起始地址,方便找回打印
assert(dest && src);
//1. 找目標空間中的\0,打印的起點
while (*dest)
{
dest++;
}
//2. 追加內(nèi)容到目標空間
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[30] = "hello";//注意初始化方式,必須要包含'\0'
char arr2[] = "world";
printf("%s\n", my_strcat(arr1, arr2));
return 0;
}
3.strcmp-比較字符串首字母的大小
int strcmp ( const char * str1, const char * str2 );
第一個字符串大于第二個字符串,則返回大于0的數(shù)字
第一個字符串等于第二個字符串,則返回0
第一個字符串小于第二個字符串,則返回小于0的數(shù)字
使用案例:
#include <stdio.h>
#include <assert.h>
int main()
{
char arr1[] = "degh";
char arr2[] = "bcdefx";
int ret = strcmp(arr1, arr2);
if (ret<0)
{
printf("arr1<arr2");
}
else if (ret >0)
{
printf("arr1>arr2");
}
else
{
printf("arr1==arr2");
}
return 0;
}

就是根據(jù)返回的值來判斷兩個字符串大小
模擬實現(xiàn):
//模擬實現(xiàn)strcmp-比較對應(yīng)位置字符串大小
//相同的話地址各向后加一繼續(xù)比較
//注意strcmp返回的是大于等于或小于0的整型
#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;
//若相等,各向后+1繼續(xù)比較
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
char arr1[] = "degh";
char arr2[] = "bcdefx";
int ret = my_strcmp(arr1, arr2);
if (ret<0)
{
printf("arr1<arr2");
}
else if (ret >0)
{
printf("arr1>arr2");
}
else
{
printf("arr1==arr2");
}
return 0;
}

3.長度受限制的字符串函數(shù)?
1.strncpy
char * strncpy ( char * destination, const char * source, size_t num );
相較于strcpy,strncpy函數(shù)有了對字符長度的限制,更加的靈活
使用案例:
#include <stdio.h>
#include <assert.h>
int main()
{
char arr1[] = {'a', 'b', 'c', 'd', 'e', 'f', '\0'};
char arr2[20] = "xxxxxxxxxxxx";
strncpy(arr2, arr1,4);
printf("%s\n", arr2);
return 0;
}

2.strncat?
char * strncat ( char * destination, const char * source, size_t num );
使用案例:
#include <stdio.h>
#include <assert.h>
int main()
{
char arr1[30] = "hello";
char arr2[] = "world";
strncat(arr1, arr2,3);
printf("%s\n", arr1);
return 0;
}

若給的數(shù)字超過了arr2的長度,如:
strncat(arr1, arr2,7);
則

只會追加到arr2元素中的'\0'結(jié)束。
3.strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
使用案例:
#include <stdio.h>
#include <assert.h>
int main()
{
char arr1[] = "degh";
char arr2[] = "bcdefx";
int ret = strncmp(arr1, arr2,3);
if (ret<0)
{
printf("arr1<arr2");
}
else if (ret >0)
{
printf("arr1>arr2");
}
else
{
printf("arr1==arr2");
}
return 0;
}

這里的數(shù)字3表明比較的是前3個?字符串的大小。
4.strstr-找子串?
char * strstr ( const char *str2, const char * str1);
在字符串里找子串,返回找到子串的起始地址
找不到則返回空指針
使用案例:
#include <stdio.h>
int main()
{
char arr1[] = "abbbcdef";
char arr2[] = "bbcq";
char* ret = strstr(arr1, arr2); //因為返回的是地址,要用指針接收
if (NULL == ret)
printf("沒找到\n");
else
printf("%s\n", ret);
return 0;
}

模擬實現(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) //如果*cur為'\0',則找不到,返回空指針
{
s1 = cur;
s2 = substr;
while (*s1 && *s2 && *s1 == *s2) //*s1 *s2不為'\0'
{
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("沒找到\n");
else
printf("%s\n", ret);
return 0;
}

5.strtok
應(yīng)用:將字符串里面除了分隔符外的其他內(nèi)容提出來
char * strtok ( char * str, const char * sep );
第一個參數(shù)指定一個字符串,包含了字符串和分隔符
sep參數(shù)是個字符串,定義了用作分隔符的字符集合
例如:
const char* p = "*.-"; char arr[] = "sukabulie*wula.wushi-baga";
sep=p? ? ? ?str=arr
注:strtok會改變第一個字符串里的內(nèi)容(將分隔符改為\0),因此不能直接將源字符串傳過去,可以臨時拷貝一份
char buf[50] = { 0 };
strcpy(buf,arr);
那么接下來要傳參時第一個參數(shù)用buf就好。
注:strtok函數(shù)的第一個參數(shù)不為空指針?,函數(shù)將找到str中第一個標記,strtok函數(shù)將保存它在字符串中的位置。
strtok函數(shù)的第一個參數(shù)為空指針 ,函數(shù)將在同一個字符串中被保存的位置開始,查找下一個標記。
如果字符串中不存在更多的標記,則返回空指針。
用法:
char* str = strtok(buf, p);//sukabulie
printf("%s\n", str);
str = strtok(NULL, p);//wula
printf("%s\n", str);
str = strtok(NULL, p);//wushi
printf("%s\n", str);
str = strtok(NULL, p);//baga
printf("%s\n", str);
打印效果:


我們發(fā)現(xiàn)這樣的寫法很笨,當我們不知道一個字符串它有多少分段時就很麻煩,我們可以用for循環(huán)來解決這個問題。
改進:
#include <stdio.h>
#include <string.h>
int main()
{
const char* p = "*.-";
char arr[] = "sukabulie*wula.wushi-baga";
char buf[50] = { 0 };
strcpy(buf, arr);
for (char* str = strtok(buf, p); str != NULL; str = strtok(NULL, p))
{
printf("%s\n",str);
}
return 0;
}

6.strerror
返回錯誤碼所對應(yīng)的錯誤信息
C語言中規(guī)定了一些錯誤碼及它所對應(yīng)的意思(錯誤信息)
char * strerror ( int errnum );
int errnum 是錯誤碼? ? ? ? ?函數(shù)返回的是錯誤信息的起始地址
展示:
#include <stdio.h>
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%s\n", strerror(i));
}
return 0;
}

使用方式:
當我們運行一個程序遇到錯誤,跑不過去時,可以在他執(zhí)行錯誤代碼段的下一行用
printf("%s\n",strerror(errno));
//注意要引用頭文件
#include <errno.h>
errno是c語言提供的一個全局變量,可直接使用,當程序發(fā)生錯誤時,他會改變?yōu)橄鄬?yīng)的錯誤碼,我們就可以用strerror函數(shù)得到相對應(yīng)的錯誤信息。
7.memcpy-不重復(fù)內(nèi)存拷貝
void * memcpy ( void * destination, const void * source, size_t num );
將source里的元素通過字節(jié)數(shù)來拷貝到destination中
使用案例:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int arr2[5] = { 0 };
memcpy(arr2,arr1,5*sizeof(arr2[0]));
int i = 0;
for (i=0;i<5;i++)
{
printf("%d\n",arr2[i]);
}
return 0;
}

模擬實現(xiàn):
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* dest, const void*src, size_t num)
{
void* ret = dest; //保留要返回的起始地址
assert(dest&&src);
while (num--) //先使用后--,一個字節(jié)一個字節(jié)的覆蓋
{
*(char*)dest = *(char*)src;//強制類型轉(zhuǎn)換是臨時的
dest = (char*)dest+1; //因此改變地址時也要強制類型轉(zhuǎn)換
src = (char*)src+1;
}
return ret;
}
int main()
{
int arr1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int arr2[5] = { 0 };
my_memcpy(arr2, arr1, 5 * sizeof(arr2[0]));
int i = 0;
for (i = 0; i<5; i++)
{
printf("%d\n", arr2[i]);
}
return 0;
}

注意:c語言中要求memcpy只要可以拷貝沒有重復(fù)的內(nèi)存就可以了,但是在vs下memcpy也可以處理重復(fù)的內(nèi)存。
若按我們寫的來舉例,我們的memcpy是不支持重復(fù)內(nèi)存的處理:
int main()
{
int arr1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int arr2[5] = { 0 };
my_memcpy(arr1+2, arr1, 5 * sizeof(arr1[0]));
int i = 0;
for (i = 0; i<9; i++)
{
printf("%d\n", arr1[i]);
}
return 0;
}
如若是這樣拷貝,那么我們想的打印出來的應(yīng)該是1 2?1 2 3 4 5 8 9
實際上是:1 2 1 2 1 2 1 8 9

用memcpy來實現(xiàn):
int main()
{
int arr1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int arr2[5] = { 0 };
memcpy(arr1+2, arr1, 5 * sizeof(arr1[0]));
int i = 0;
for (i = 0; i<9; i++)
{
printf("%d\n", arr1[i]);
}
return 0;
}

在vs下庫函數(shù)memcpy功能更加強大,可處理重復(fù)內(nèi)存,c語言只要求它能處理不重復(fù)的內(nèi)存即可,處理重復(fù)內(nèi)存時用庫函數(shù)memmove,因此我們模擬的memcpy正確。
8.memmove-可處理重復(fù)內(nèi)存拷貝
void * memcpy ( void * destination, const void * source, size_t num );
類型與memcpy相同
使用案例:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int arr2[5] = { 0 };
memmove(arr1 + 2, arr1, 5 * sizeof(arr1[0]));
int i = 0;
for (i = 0; i<9; i++)
{
printf("%d\n", arr1[i]);
}
return 0;
}

模擬實現(xiàn):
分析:

#include <stdio.h>
#include <string.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); // //根據(jù)圖來分析
}
}
}
int main()
{
int arr1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int arr2[5] = { 0 };
my_memmove(arr1 + 2, arr1, 5 * sizeof(arr1[0]));
int i = 0;
for (i = 0; i<9; i++)
{
printf("%d\n", arr1[i]);
}
return 0;
}
9.memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
比較字節(jié)中數(shù)的大小
返回的是大于等于或小于0的無符號整型
使用方式與strncmp相似,但是比較的類型不局限于字符串,更加廣泛
案例:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,7,4,5 };
int arr2[] = { 1,2,3,4,5 };
int ret = memcmp(arr1, arr2, 9); //比較arr1和arr2前九個字節(jié)中數(shù)的大小
printf("%d\n", ret);
return 0;
}

10.memset
void* memset(void* dest,int c,size_t count)
第一個參數(shù)是目標地址,第二個參數(shù)是要被設(shè)置的內(nèi)容,第三個參數(shù)是個數(shù)
以字節(jié)為單位修改
應(yīng)用方式:
#include <stdio.h>
#include <string.h>
int main()
{
char arr[20] = { 0 };
memset(arr, 'x', 10);
return 0;
}

到此這篇關(guān)于C語言詳解如何應(yīng)用模擬字符串和內(nèi)存函數(shù)的文章就介紹到這了,更多相關(guān)C語言 字符串 內(nèi)存函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C語言的字符串函數(shù),內(nèi)存函數(shù)筆記詳解
- c語言重要的字符串與內(nèi)存函數(shù)
- C語言內(nèi)存函數(shù)的使用及其模擬實現(xiàn)
- C語言超詳細講解字符串函數(shù)和內(nèi)存函數(shù)
- C語言深入詳解四大內(nèi)存函數(shù)的使用
- C語言字符串函數(shù),字符函數(shù),內(nèi)存函數(shù)使用及模擬實現(xiàn)
- 深入了解C語言中的字符串和內(nèi)存函數(shù)
- 深度解析三個常見的C語言內(nèi)存函數(shù)
- C語言內(nèi)存函數(shù)的實現(xiàn)示例
- C語言內(nèi)存函數(shù)的具體使用
- C語言實現(xiàn)內(nèi)存函數(shù)的示例代碼
相關(guān)文章
C語言中g(shù)etopt()函數(shù)和select()函數(shù)的使用方法
這篇文章主要介紹了C語言中g(shù)etopt()函數(shù)和select()函數(shù)的使用方法,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-09-09
Qt QWidget實現(xiàn)圖片旋轉(zhuǎn)動畫
這篇文章主要為大家詳細介紹了如何使用了Qt和QWidget實現(xiàn)圖片旋轉(zhuǎn)動畫效果,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-12-12

