C++面試八股文:如何實現一個strncpy函數?

2023-07-04 06:00:35

某日二師兄參加XXX科技公司的C++工程師開發崗位第31面:

面試官:strcpy函數使用過吧?

二師兄:用過。

面試官:這個函數有什麼作用?

二師兄:主要用做字串複製,將於字元從一個位置複製到另一個位置。

面試官:strncpy函數也使用過吧,和strcpy有何不同?

二師兄:strncpy多了一個size_t的引數,用於避免緩衝區溢位。

面試官:能否實現一個strncpy函數?

二師兄:好的。

void strncpy(char *dest, char *src, size_t n)
{
    for (size_t i = 0; i < n; i++)
    {
        *(dest + i) = *(src + i);
    }
}

面試官:額。。如果strlen(src) < n會發生什麼?

二師兄:嗯。。那要做個判斷。。

void strncpy(char *dest, char *src, size_t n)
{
    size_t len = strlen(src) > n ? n : strlen(src);
    for (size_t i = 0; i < len; i++)
    {
        *(dest + i) = *(src + i);
    }
}

面試官:如果strlen(dest) < n呢?

二師兄:因為n是程式設計師傳入進來的,且無法知曉dest的長度,所以這個n要程式設計師保證它的正確性。

面試官:有沒有更簡潔的寫法?比如利用指標的自增?

二師兄:讓我想想。。

void strncpy(char *dest, char *src, size_t n)
{
    while(n-- && (*dest++ = *src++));
}

面試官:如果使用者傳入的src是字串常數,會發生什麼?

二師兄:額。。。讓我想想。。明白了,要在src前加上const修飾符:

void strncpy(char *dest, const char *src, size_t n)
{
    while(n-- && (*dest++ = *src++));
}

面試官:有一些操作需要strcpy巢狀strcpy,如果要實現這個功能,需要做哪些修改?

二師兄:你說的是strncpy(strncpy(...)...)這種操作嗎?

面試官:是的。

二師兄:那麼需要返回dest地址:

char *strncpy(char *dest, const char *src, size_t n)
{
    char *ret = dest;
    while (n-- && (*dest++ = *src++));
    return ret;
}

面試官:如果srcdest的記憶體地址有重疊,會發生什麼?

二師兄:這要分為兩種情況,第一種情況:dest < src < dest+n

二師兄:此時並不需要特殊的處理,拷貝完成後,整個字串是這樣的:

二師兄:雖然src被覆寫了,但是dest的內容是正確的。

二師兄:第二種情況,src < dest <src+n;

二師兄:如果直接拷貝,結果會變成這樣:

二師兄:此時dest的內容是錯誤的。所以我們需要對這種情況做特殊處理:

char *strncpy(char *dest, const char *src, size_t n)
{
    char *ret = dest;
    size_t len = strlen(src) > n ? n :strlen(src);
    if(src < dest && dest < src + len)  //需要從尾部開始拷貝
    {
        const char* s = src + len - 1;
        char* d = dest + len - 1;
        while(len --) *d-- = *s--;
        return ret;
    }
    while (n-- && (*dest++ = *src++));
    return ret;
}

面試官:嗯。有沒有什麼辦法對以上的程式碼做一些效能上的優化?

二師兄:可以使用SIMD(Single Instruction Multiple Data)指令對strncpy函數做一些優化。*dest++ = *src++每次只能複製一個位元組的內容,而SIMD每次可以複製超過一個位元組的內容,當資料量大的時候,效率會有明顯的提升。

面試官:寫過SIMD相關的程式碼嗎?

二師兄:只是聽說過,沒有用過。

面試官:好的,今天就到這裡,請回去等通知吧。

什麼是SIMDSIMD真的能夠提升效率嗎?

SIMD是一種常見的平行計算技術,一條指令可以同時處理多個資料,所以它可以減少指令的數量,從而提高處理速度。

X86_64架構下,SIMD的指令集主要包括MMXSSEAVX

下面程式碼演示如果使用SIMD技術加速大容量字串的拷貝:

#include <emmintrin.h>
void strncpy_simd(char *dest, const char *src, size_t n)
{
    size_t len = strlen(src) > n ? n : strlen(src);
    __m128i *d = (__m128i *)dest;
    const __m128i *s = (const __m128i *)src;
    while (len >= sizeof(__m128i))
    {
        _mm_storeu_si128(d++, _mm_loadu_si128(s++));
        len -= sizeof(__m128i);
    }
    char *dc = (char *)d;
    const char *sc = (const char *)s;

    while (len--)
    {
        *dc++ = *sc++;
    }
}

今天的面試到這裡就結束了,感謝大家的耐心~

關注我,帶你21天「精通」C++!(狗頭)