日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

几个重要库函数的实现

發布時間:2024/8/23 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 几个重要库函数的实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

面試官很喜歡讓求職者寫一些常用庫函數的實現,有很多是和字符串相關的,有一些是關于內存拷貝的。一般,常會讓寫的函數有以下幾個:

strcpy , strncpy, memcpy。

memset一般不會讓去寫,但這個函數也很有特點,有很多容易用錯的地方。一并總結吧。

1. strcpy

strcpy函數的原型是:

char * strcpy(char* dest, const char* src)

strcpy的實現經常要注意的細節是:

(1)判斷地址是否為空,個人感覺可以使用斷言

(2)參數只有兩個地址,沒有拷貝的長度。拷貝到'\0‘時就會終止,要保證最終dest末尾是'\0'。

(3)要保證目標字串的長度足夠,能夠容納原串的長度。

(4)因為拷貝是dest會移動,而最終要返回的是拷貝后字符串的起始地址,因此要先保存dest的地址,便于最終返回。

在實現這一點時,有兩種方法。 char* temp=dest; 拷貝時移動dest返回temp,或者拷貝時移動temp返回dest,不知道哪個是對的。感覺兩個都是沒有問題的

其中一種實現方式:

[cpp]?view plaincopy
  • char*?mystrcpy(char*?dest,const?char*?src)??
  • ??
  • {??
  • ??
  • ????????????assert(dest!=NULL?&&?src!=NULL);??
  • ??
  • ????????????char*?temp=dest;??
  • ??
  • ????????????while((*temp++?=?*src++?)!='\0')??
  • ??
  • ????????????{}??
  • ??
  • ????????????return?dest;??
  • ??
  • }??


  • 2. strncpy

    strncpy的功能和strcpy相似,只是它復制時多了一個終止條件。即是未遇到原串的'\0’,如果已經復制了n個字符(n為提供的參數長度),復制同樣會終止。

    strcpy的實現要注意的細節也基本適用于strncpy的實現。

    實現方式:

    [cpp]?view plaincopy
  • char*?mystrncpy(char*?dest,?const?char*?src,?int?len)??
  • ??
  • {??
  • ??
  • ????????????assert(dest!=NULL?&&?src!=NULL);??
  • ??
  • ????????????char*?temp=dest;??
  • ??
  • ????????????int?i=0;??
  • ??
  • ????????????while(i++?<?len??&&?(*temp++?=?*src++)!='\0')??
  • ??
  • ????????????{}??
  • ??
  • ????????????if(*(temp)!='\0')??
  • ??
  • ???????????????????????*temp='\0';??
  • ??
  • ????????????return?dest;??
  • ??
  • }??
  • 3. memcpy

    memcpy和strncpy有些類似,但也有本質的不同。

    (1)strncpy只能復制字符串,但memcpy對類型沒有要求。

    (2)strncpy有兩個終止條件,memcpy只有一個終止條件,那就是復制n個字節。(n是memcpy的第三個參數)

    (3)要特別注意目的地址和源地址重合的問題,拷貝前要加以判斷。

    (4)實現這個函數時一般要把原來的指針類型轉換成char*,這樣每次移動都是一個字節。

    實現方式:(考慮了兩個地址空間是否會有重疊)

    [cpp]?view plaincopy
  • void*?mymemcpy(void*?dest,?void*?src,?int?len)??
  • ??
  • {??
  • ??
  • ????????????int?i=0;??
  • ??
  • ????????????char*?tempdest=(char*)dest;??
  • ??
  • ????????????char*?tempsrc=(char*)src;??
  • ??
  • ????????????if(tempdest<tempsrc?||?tempdest>(tempsrc+len-1))??
  • ??
  • ????????????{??
  • ??
  • ???????????????????????while(i<len)??
  • ??
  • ???????????????????????{??
  • ??
  • ???????????????????????????????????*tempdest++?=?*tempsrc++;??
  • ??
  • ???????????????????????????????????i++;??
  • ??
  • ???????????????????????}??
  • ??
  • ????????????}??
  • ??
  • ????????????else??
  • ??
  • ????????????{??
  • ??
  • ???????????????????????tempdest+=len;??
  • ??
  • ???????????????????????tempsrc+=len;??
  • ??
  • ???????????????????????i=len;??
  • ??
  • ???????????????????????while(i>0)??
  • ??
  • ???????????????????????{??
  • ??
  • ???????????????????????????????????*tempdest--?=?*tempsrc--;??
  • ??
  • ???????????????????????????????????i--;??
  • ??
  • ???????????????????????}??
  • ??
  • ????????????}??
  • ??
  • ????????????return?dest;??
  • ??
  • }??

  • ?
    注意,memcpy是對內存的拷貝,對其他安全性不做考慮。用戶在使用這個函數時要小心,比如用它來拷貝字符串(當然如果是字符串拷貝肯定是用strncpy)就要注意末尾的\0字符之類的。



    4. memset

    memset函數的原型是:

    void *memset(void *s, int ch,size_t?n)

    作用是把s所指向的地址開始的n個字節的內容全部置位ch所指定的ASCII值。

    一般經常用memset對某段內存空間置零。

    經常會出現的一個問題:在C++中,為什么不提倡在構造函數中使用:memset(this,0,sizeof(*this))

    原因:?C++中,如果類中都是基本類型的數據成員并且沒有虛函數和虛繼承的話,使用memset這樣用到沒有太多影響。

    如果有虛函數,memset會把虛表指針等全部置零,對類會產生破壞。


    三個函數的原型如下:

    [cpp]?view plaincopy
  • void*?memset(void?*des,?int?val,?size_t?size)???
  • void?*?memcpy(void?*des,?const?void*?src,?size_t?size)??
  • void?*?memmove(void?*des,?const?void?*src,?size_t?size)??

  • 實現如下:

    [cpp]?view plaincopy
  • void*?memset(void?*des,?int?val,?size_t?size)?{??
  • ????void?*start?=?des;??
  • ????while?(size--)?{??
  • ????????*(char*)?des?=?(char)?val;??
  • ????????des?=?(char?*)?des?+?1;??
  • //??????(char*)?des++;??
  • ????????//??????des?=?(char*?)des?+?1;??
  • ????}??
  • ????return?start;??
  • }??
  • void?*?memcpy(void?*des,?const?void*?src,?size_t?size)?{??
  • ????void?*ret?=?des;??
  • ????while?(size--)?{??
  • ????????*(char?*)?des?=?*(char?*)?src;??
  • ????????des?=?(char?*)des?+?1;??
  • ????????src?=?(char?*)src?+?1;??
  • //??????(char?*)?des++;??
  • //??????(char?*)?src++;??
  • ????}??
  • ????return?ret;??
  • }??
  • void?*?memmove(void?*des,?const?void?*src,?size_t?size)?{??
  • ????void?*ret?=?des;??
  • ????if?(des?<?src?||?(char?*)?des?>?(char?*)?src?+?size?-?1)?{??
  • ????????while?(size--)?{??
  • ????????????????*(char?*)?des?=?*(char?*)?src;??
  • ????????????????des?=?(char?*)?des?+?1;??
  • ????????????????src?=?(char?*)src?+?1;??
  • //??????????????(char?*)?src++;??
  • //??????????????(chr?*)?des?++;??
  • ????}??
  • ????}else{??
  • ????????des?=?(char?*)des?+?size?-?1;??
  • ????????src?=?(char?*)src?+?size?-?1;??
  • ????????while?(size?--?>?0){??
  • ????????????*(char?*)?des?=?*(char?*)?src;??
  • //??????????(char?*)?des--;??
  • //??????????(char?*)?src--;??
  • ????????????des?=?(char?*)des?-?1;??
  • ????????????src?=?(char?*)src?-?1;??
  • ????????}??
  • ????}??
  • ????return?ret;??
  • }??

  • 不采用//中的寫法是因為包報出警告:warning: value computed is not used

    看起來不爽。

    注意事項:

    (1)使用memset的時候,要把最后一位或者最后一位的下一位置為‘\0’;

    [cpp]?view plaincopy
  • char?buffer[20]?=?"hello";??
  • memset(buffer,?'1',?sizeof(char)*20);??
  • printf("%s\n",buffer);??
  • 運行結果:111111111111111111110@??
  • ??
  • char?buffer[20]?=?"hello";??
  • memset(buffer,?'1',?sizeof(char)*20);??
  • buffer[20]?=?'\0';??
  • printf("%s\n",buffer);??
  • 運行結果:11111111111111111111??

  • 因為在prinf一個字符串的時候,printf函數是遇見‘\0就停止。想第一個例子中的,buffer[20]都是‘1’,結束沒有‘\0’,所以打印出來的結果就不確定。當然,也有可能是對的,那只是運氣好而已。

    (2)memcpy和strcpy的區別:

    實際上區別只有一個,strcpy的操作對象只能是char *,而memcpy操作的對象是void *。(什么類型的都可以)。實際上,在memcpy的實現上,都是將(void *)裝換成為了(char *)來做的,其實跟strcpy一樣。

    (3)memmove和memcpy的區別:

    區別就是memmove要考慮內存區間重疊的情況,而memcpy不會。

    關于這個問題,可以用下面的圖片來解釋:

    內存區間重疊的情況如下和不會出現內存區間重疊的情況:


    假設des為src + 2,如果按照memcpy處理,從頭開始拷貝,就要出現下面的悲劇:


    src的內存都被污染了,而且如果這時候打印*des開頭的內存,仍然會出現未定義的情況:因為'\0'被覆蓋了。

    [cpp]?view plaincopy
  • char?buffer5[10]?=?"1234";??
  • ????memcpy(buffer5?+?2,?buffer5,?sizeof(buffer5));??
  • ????printf("%s\n",?buffer5);??
  • ????char?buffer6[10]?=?"1234";??
  • ????memmove(buffer6?+?2,?buffer6,?sizeof(buffer6));??
  • ????printf("%s\n",buffer6?+?2);??
  • 運行結果:
    121212121212????"
    1234





    總結

    以上是生活随笔為你收集整理的几个重要库函数的实现的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。