C/C++面試常見的幾個庫函數詳解(strcpy,memcpy,memset,atoi...)

轉載http://blog.csdn.net/jiange_zh
在面試中,常常會被問到幾個庫函數的實現,雖然代碼很短,涉及的細節卻特別多,因此特別受面試官青睞,所以要把他們熟記於心,方能應對自如。

strcpy()

原型聲明:char strcpy(char dest, const char *src); 
功能:把從src地址開始且含有NULL結束符的字符串複製到以dest開始的地址空間 
說明:src和dest所指內存區域不可以重疊且dest必須有足夠的空間來容納src的字符串。 
返回指向dest的指針。

#include <assert.h>
char *strcpy(char* dest, const char *src) //point1: 源字符串不改變,需要加const保證
{
    assert(NULL != dest && NULL != src); //point2:保證指針有效
    char * temp = dest; //point3:下面涉及到指針的移動,而我們需要返回dest的頭指針,所以dest保留,而使用temp來移動
    while ((*temp++ = *src++) != '\0'); 
    /* point4:末尾的'\0'也要複製過來
     * 上面先執行 *temp++ = *src++ ,再判斷 *src 是否等於'\0'
     * 所以保證了'\0'先複製後判斷
     */
     return dest; //point5:返回dest頭指針,支持鏈式表達式
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

鏈式的例子:

int length = strlen(strcpy(strA, strB));
  • 1
  • 1

strncpy()

strcpy()是一個高危函數,因爲沒有指定複製的大小,當dest的空間比src小時,就會出錯,而我們沒法進行控制。於是有了比較安全的strncpy():

//把src所指向的字符串中以src地址開始的前n個字節複製到dest所指的數組中,並返回dest。
#include <assert.h>
char *strncpy(char* dest, const char *src, unsigned int n)
{
    assert(NULL != dest && NULL != src);
    char * temp = dest;
    while (n-- > 0 && (*temp++ = *src++) != '\0'); 
    /* 上面語句兩種終止情況:
     * 1. n = 0,此時下面的語句也不執行,如果未達到src末尾
     * 不會自動在dest末尾添加'\0'的,所以需要使用者自己添加
     * 2. n > 0 但是src已經到達末尾,那麼執行下面語句,將
     * dest填充'\0'達到長度n(ANSI C規定)
     */ 
    while (n-- > 0) *temp++ = '\0';
    return dest;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

strcmp()

比較兩個字符串 
設這兩個字符串爲str1,str2, 
若str1==str2,則返回零; 
若str1>str2,則返回正數; 
若str1

#include <assert.h>
int strcmp(const char *str1, const char *str2)
{
    assert(NULL != str1 && NULL != str2);
    /*不可用while(*str1++==*str2++)來比較,當不相等時仍會執行一次++,
    return返回的比較值實際上是下一個字符。應將++放到循環體中進行。*/
    while(*str1 && *str2 && *str1 == *str2)
    {
        str1++;
        str2++;
    }
    return *str1 - *str2;
    /* 若相等,則*str1 - *str2 = '\0' - '\0' = 0;
     * 否則,*str1 - *str2 != 0;
     * 因爲前面的位都相等,所以只需要比較當前位來確定返回值
     */
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

strcat()

把src所指字符串添加到dest結尾處(覆蓋dest結尾處的’\0’)。

char *strcat(char *dest,const char *src)
{
    assert(NULL != dest && NULL != src);
    char *temp = dest;
    while ('\0' != *temp) //自增放在循環裏,纔可以覆蓋'\0'
        ++temp;
    while ((*temp++ = *src++) != '\0');
    return dest;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

strlen()

功能:計算給定字符串的(unsigned int型)長度,不包括’\0’在內 
說明:返回s的長度,不包括結束符NULL。

unsigned int strlen(const char *s)
{
    assert(NULL != s);
    unsigned int len = 0;
    while (*s++ != '\0')
        ++len;
    return len;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

memset()

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

函數解釋:將s中前n個字節 (typedef unsigned int size_t )用 ch 替換並返回 s 。 
memset:作用是在一段內存塊中填充某個給定的值,它是對較大的結構體或數組進行清零操作的一種最快方法。

注意,memset是以【字節】爲單位進行賦值的,因此下面用法將導致錯誤:

int arr[5];
memset(array,1,sizeof(arr));
  • 1
  • 2
  • 1
  • 2

arr指向5個字節的空間,每個都用ASCII爲1的字符去填充,轉爲二進制後,1就是00000001,佔一個字節。一個INT元素是4字節,合一起就是00000001000000010000000100000001,就等於16843009,就完成了對一個INT元素的賦值了。所以上面結果不是1而是16843009!

void *memset(void *s,int c,unsigned int n) //point1:s指針類型未知,另外,n爲字節數!
{
    assert(NULL != s);
    void *temp = s;
    while (n--)
    {
        *(char *temp) = (char)c; //point2:轉化爲字符(1字節)
        temp = (char *)temp + 1; //point3:不能自增,因爲不知道指針類型
    }
    return s;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

memcpy()

內存拷貝函數,memcpy函數的功能是從源src所指的內存地址的起始位置開始拷貝n個字節到目標dest所指的內存地址的起始位置中。

void *memcpy(void *dest, const void *src, size_t n)
{
    assert(NULL != dest && NULL != src);
    int i = 0;
    void *temp = dest;
    while (i < n)
    {
        *((char *)temp + i) = *((char *)src + i); //未知類型,不能自增
        ++i;
    }
    return dest;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

atoi()

這個函數就比較經典了,面試常常出現,因爲可以考察各種特殊情況:空指針、空串、正負號、非法字符、溢出等等。

最大的int:0x7FFF FFFF; 
最小的int:0x8000 0000;

enum = {Invalid = 0, Valid};
bool errno = Invalid;
int atoi(const char * str)
{
    long long num = 0; //point1:可能溢出,所以用long long存
    errno = Invalid;
    if (NULL != str && *str != '\0') //point2
    {
        bool minus = false;
        if (*str == '+')
        {   
            ++str;
        }
        else if (*str == '-')
        {
            ++str;
            minus = true;
        }
        if ('\0' != *str) //只有符號,Invalid
            atoiCore(str, minus, num);
    }
    return (int)num; //已經檢查過溢出,保證了num在int範圍內    
}

void atoiCore(const char *str, bool minus, long long &num)
{
    while ('\0' != *str)
    {
        if (*str >= '0' && *str <= '9')
        {
            num = num*10 + (*str) - '0';
            ++str;
            if ((!minus && num > 0x7FFFFFFF)||(minus && (-num) < (signed int)0x80000000))
            {
                errno = Invalid;
                num = 0;
                return;
            }
        }
        else
        {
                errno = Invalid;
                num = 0;
                return;
        }
    }
    if (minus)
        num = -num;
    errno = Valid;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

最後強調一遍,面試技術崗的,這幾個函數一定要熟,一定要熟,一定要熟!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章