常見字符串面試問題

/* memcpy ——— 拷貝不重疊的內存塊 */ 
void memcpy(void* pvTo, void* pvFrom, size_t size)
{
void* pbTo = (byte*)pvTo;
void* pbFrom = (byte*)pvFrom;
ASSERT(pvTo != NULL && pvFrom != NULL); //檢查輸入指針的有效性
ASSERT(pbTo>=pbFrom+size || pbFrom>=pbTo+size);//檢查兩個指針指向的內存是否重疊
while(size–>0)
*pbTo++ == *pbFrom++;
return(pvTo);
}

原文來自:http://blog.sina.com.cn/s/blog_6d041c110100mmc3.html

看的時候發現,有的算法很有技巧性,於是自己就添加了註釋,希望我下次看的時候能有收穫!

1)寫出在母串中查找子串出現次數的代碼.

int count1(char* str,char* s)

{

    char* s1;

    char* s2;

    int count = 0;

    while(*str!=’\0′)

    {

        s1 = str;

        s2 = s;

        while(*s2 == *s1&&(*s2!=’\0′)&&(*s1!=’\0′))

        {

            s2++;

            s1++;

        }

        if(*s2 == ‘\0’)

            count++;  //經過了綠色的步驟,一定是找到了一個匹配的字符串。

        str++;

    }

    return count;

}

2)查找第一個匹配子串位置,如果返回的是s1長度len1表示沒有找到

size_t find(char* s1,char* s2)

    {

        size_t i=0;

         size_t len1 = strlen(s1);

        size_t len2 = strlen(s2);

        if(len1-len2<0) return len1;

        for(;i<len1-len2;i++)

        {

            size_t m = i;  //m是用來記錄對比中s1向前走的位置。

            for(size_t j=0;j<len2;j++)

            {

                if(s1[m]!=s2[j])  //當不是匹配字符時

                    break;

                m++;  //爲下一次匹配做準備。

            }

            if(j==len2) //要使得j == len2,則上面的for應該完成,所以此時已經找到第一個匹配的位置,所以要跳出。

                break;

        }

        return i<len1-len2?i:len1;

    }

 

strstr的實現:

        const char * _strstr(const char *src, const char *needle)
        {
                 const char *p1, *p2;
    
                 p1 = src;
                 p2 = needle;
                 while (*src != ‘\0’ && *needle != ‘\0’) 
                 {
                         if (*src++ != *needle++){    //這次判斷,非常重要,如果不成立,src和needle都子增加了,如果成立,那麼needle要從頭開始,但是被搜搜索的字符

                                                                          //要從下一個字符開始!!
                               needle = p2;   //要從頭開始
                               src = ++p1; //從下一個字符開始搜索needle       
                        }
                 }
                 if (*needle == ‘\0’)
                        return p1;

                 return NULL;
         }

 

3)實現strcpy函數

char *my_strcpy(char *destination, const char *source)

{
 
    assert(destination!=NULL&&source!=NULL);
 
    char* target = destination;
 
    while((*destination++ = *source++) != ‘\0’);
 
    return target ;
 
}

此函數原型爲 char *strcat(char *dest, const char *src).
功能爲連接兩個字符串,把src連接到dest後面;返回dest地址
實現如下

區別於strcat

char * strcat(char *dest,const char *src)
{
char* addr=dest;
while(*dest)//找到’\0′
{
dest++;
};
while(*dest++=*src++)
{};
return addr;
}

出現次數相當頻繁

4)實現strcmp函數

int strcmp11(char* l,char* r)

{

    assert(l!=0&&r!=0);

    while(*l == *r &&*l != ‘\0’) l++,r++;

    if(*l > *r)  //此時*l和*r不相等!!!

        return 1;

    else if(*l == *r)

        return 0;

    return -1;

}

5) 實現字符串翻轉

void my_reserve(char* str)

{
 
    //assert(str != NULL);
 
    char * p1 = str;  //第一個字符
 
    char * p2 = str-1;
 
    while(*++p2);         //一般要求不能使用strlen
 
    p2 -= 1;  //p2指向最後一個字符
 
    while(p1<p2)
  
    {
  
        char c = *p1;  //保留前部分
  
        *p1++ = *p2;
  
        *p2– = c;
  
 }
 
}

6)、用指針的方法,將字符串“ABCD1234efgh”前後對調顯示

//不要用strlen求字符串長度,這樣就沒分了

代碼如下:

    char str123[] = “ABCD1234efgh”;

    char * p1 = str123;

    char * p2 = str123-1;

    while(*++p2);

    p2 -= 1;

    while(p1<p2)

    {

        char c = *p1;

        *p1++ = *p2;

        *p2– = c;

    }

7) 給定字符串A和B,輸出A和B中的最大公共子串。比如A=”aocdfe” B=”pmcdfa” 則輸出”cdf”

#i nclude<stdio.h>

#i nclude<stdlib.h>

#i nclude<string.h>

char *commanstring(char shortstring[], char longstring[])   //傳入是可以隨便,然後再計算大小,大的賦值給long,小的賦值給short

{

    int i, j;

    char *substring=malloc(256);

    if(strstr(longstring, shortstring)!=NULL)              //如果……,那麼返回shortstring

        return shortstring;

    for(i=strlen(shortstring)-1;i>0; i–)                 //否則,開始循環計算

    {

        for(j=0; j<=strlen(shortstring)-i; j++)

        {

            memcpy(substring, &shortstring[j], i);  //先從最大子串開始搜索,然後再逐漸使字串變短!!

            substring[i]=’\0′;

            if(strstr(longstring, substring)!=NULL)

            return substring;

        }

    }

    return NULL;

}

main()

{

    char *str1=malloc(256);

    char *str2=malloc(256);

    char *comman=NULL;

    gets(str1);

    gets(str2);

    if(strlen(str1)>strlen(str2))                         //將短的字符串放前面

        comman=commanstring(str2, str1);

    else

        comman=commanstring(str1, str2);

    printf(“the longest comman string is: %s\n”, comman);

}

8) 判斷一個字符串是不是迴文

int IsReverseStr(char *str)

{

    int i,j;

    int found=1;

    if(str==NULL)

        return -1;

    char* p = str-1;

    while(*++p!= ‘\0’);

    –p;

    while(*str==*p&&str<p) str++,p–;

    if(str < p)

        found = 0;

    return found;

}

9)寫函數完成內存的拷貝

void* memcpy( void *dst, const void *src, unsigned int len )

{

    register char *d;

    register char *s;

    if (len == 0)

        return dst;

    if ( dst > src )   //考慮覆蓋情況

    {

        d = (char *)dst + len – 1;

        s = (char *)src + len – 1;

        while ( len >= 4 )   //循環展開,提高執行效率

        {

            *d– = *s–;

            *d– = *s–;

            *d– = *s–;

            *d– = *s–;

            len -= 4;

        }

        while ( len– )

        {

            *d– = *s–;

        }

    }

    else if ( dst < src )

    {

        d = (char *)dst;

        s = (char *)src;

        while ( len >= 4 )

        {

            *d++ = *s++;

            *d++ = *s++;

            *d++ = *s++;

            *d++ = *s++;

            len -= 4;

        }

        while ( len– )

        {

            *d++ = *s++;

        }

    }

    return dst;

}

10)寫一個函數,它的原形是int continumax(char *outputstr,char *intputstr)

功能:

在字符串中找出連續最長的數字串,並把這個串的長度返回,並把這個最長數字串付給其中一個函數參數outputstr所指內存。例如:”abcd12345ed125ss123456789″的首地址傳給intputstr後,函數將返回

9,outputstr所指的值爲123456789

int continumax(char *outputstr, char *inputstr)

{

    char *in = inputstr, *out = outputstr, *temp, *final;

    int count = 0, maxlen = 0;

    while( *in != ‘\0’ )

    {

        if( *in > 47 && *in < 58 )

        {

            for(temp = in; *in > 47 && *in < 58 ; in++ )

            count++;

        }

    else

    in++;

    if( maxlen < count )

    {

        maxlen = count;

        count = 0;

        final = temp;

    }

    }

    for(int i = 0; i < maxlen; i++)

    {

        *out = *final;

        out++;

        final++;

    }

    *out = ‘\0’;

    return maxlen;

}

11) 編寫一個 C 函數,該函數在一個字符串中找到可能的最長的子字符串,且該字符串是由同一字符組成的。

 

主要思想就是:定義兩個臨時變量,iTemp來存儲每次找到的子字符串的大小, cpTemp來存儲從什麼位置開始搜索!!

char * search(char *cpSource, char ch)

{

         char *cpTemp=NULL, *cpDest=NULL;

         int iTemp, iCount=0;

         while(*cpSource)

         {

                 if(*cpSource == ch)

                 {

                          iTemp = 0;

                          cpTemp = cpSource;

                          while(*cpSource == ch)   //找到了可能是最長的一次匹配

                                 ++iTemp, ++cpSource;

                          if(iTemp > iCount)

                                iCount = iTemp, cpDest = cpTemp;

                      if(!*cpSource)  // 當!0爲真是退出,即*(cpSource)到了尾部

                            break;

                 }

                 ++cpSource;

     }

     return cpDest;

}

点赞