1. 程式人生 > >C語言字串函式歸納。

C語言字串函式歸納。

首先需要知道在c語言中本身並沒有字串型別,字串通常放在常量字串中或者字元陣列中

1.實現strlen

首先strlen函式的作用是求字串長度的。'\0’是它的結束標誌,strlen函式返回的是在字串中‘\0’前面出現的字元個數,strlen函式的返回值為size_t,是無符號的,它的實現有三種方式。

第一種用指標和計數器的方式。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int my_strlen(char* str)
{
  int count=0;
  while(*str)
  {
    str++;
    count++;
  }
  return count;
}
int main()
{
  char str[]="asdvssdvsdv";
  printf("%d\n",my_strlen(str));
  return 0;
}

這是最簡單也是很容易理解的一種方式。

第二種遞迴的方式。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int my_strlen(char* str)
{
  if(*str=='\0')
    return 0;
  else
    return 1+my_strlen(str+1);
}
int main()
{
  char str[]="asdvssdvsdv";
  printf("%d\n",my_strlen(str));
  return 0;
}

第三種是採用指標和指標的方式。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int my_strlen(char* str)
{
  char* p=str;
  while(*p!='\0')
      p++;
  return p-str;
}
int main()
{
  char str[]="asdvssdvsdv";
  printf("%d\n",my_strlen(str));
  return 0;
}

2實現strcpy

首先應該知道它的作用是複製,char* strcpy(char* destination,const char* source)目標空間應該足夠大,以確保能存放源字串,源字串必須以‘\0’結束,會將源字串的‘\0’拷貝到目標空間。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<assert.h>
#include<algorithm>
using namespace std;
char* my_strcpy(char* dest,char* src)
{
  char* ret=dest;
  assert(dest!=NULL);
  assert(src!=NULL);
  while((*dest++==*src++)!='\0')
  {;}
  return ret;
}
int main()
{
  char str1[]="hello";
  char str2[]="world";
  printf("%s\n",my_strcpy(str1,str2));
  return 0;
}

assert是判斷指標有效性的函式。是把dest複製到原函式上面。迴圈寫成while(*dest++=*src++)明顯是錯誤的,不知什麼時候結束。迴圈寫成while(*src!='\0'){*dest++=*src++;}也是錯誤的,迴圈體結束後,dst末尾並沒有加上‘\0’.
2.實現strcat

該函式的作用是拼接函式,stract(str1,strr2),str2是源,str1是目標函式,是把源拼接在目標函式上,目標函式必須足夠大,能容納下源字串的內容。

#include<iostream>
#include<algorithm>
#include<assert.h>
#include<cstdio>
using namespace std;
char *my_strcat(char* dest,char *src)
{
  char* ret=dest;
  assert(dest!=NULL);
  assert(src!=NULL);
  while(*dest!='\0')
  {
    dest++;
  }
  while((*dest++=*src++))
  {
    ;
  }
  return ret;
}
int main()
{
  char str1[]="hello";
  char str2[]="world";
  my_strcat(str1,str2);
  printf("%s\n",my_strcat(str1,str2));
  return 0;
}


3.實現strcmp

該函式的作用是比較另個字串是否完全相同。此處用返回相關數值表示。返回0表示完全相同,返回1表示不相同。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<assert.h>
using namespace std;
int my_strcmp(char* src,char* dst)
 {
  assert(src!=NULL);
  assert(dst!=NULL);
   while(*src==*dst)
   {
       if(*src=='\0')
        return 0;
     ++src;
     ++dst;
   }
   if(*src>*dst)
      return 1;
   else
     return -1;
 }
int main()
{
  char str1[]="hello";
  char str2[]="hellv";
  my_strcmp(str1,str2);
  cout<<my_strcmp(str1,str2)<<endl;
  return 0;
}


4.實現strchr

strchr 原型為extern char *strchr(const char *s,char c),可以查詢字串s中首次出現字元c的位置。此函式並不常用。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<assert.h>
using namespace std;
char* my_strchr(char* str,char c)
{
  assert(str!=NULL);
  while(*str!='\0')
  {
    if(*str==(char)c)
    {
      return (char*)str;
    }
    str++;
  }
return NULL;
}
int main()
{
  char str[]="abcdefg";
  char *p;
  p=my_strchr(str,'f');
  if(p==NULL)
  {
    cout<<"Not Find"<<endl;
  }
  else
  {
    cout<<"Find"<<endl;
    cout<<p<<endl;
  }
  return 0;
}


5.實現strstr

strstr函式的作用是找字串的子串

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<assert.h>
using namespace std;
char* my_strstr(char* str1,char* str2)
{
  assert(str1!=NULL);
  assert(str2!=NULL);
  char* start=(char*)str1;
  char* substart=(char*)str2;
  char* cp=(char*)str1;
  while(*cp)
  {
    start=cp;
    while(*start!='\0'&&*substart!='\0'&&*start==*substart)
    {
      start++;
      substart++;
    }
    if(*substart=='\0')
      return cp;
    substart=(char*)str2;
    cp++;
  }
  return NULL;
}
int main()
{
  char str1[]="abbbcdefg";
  char str2[]="bbcd";
  cout<<my_strstr(str1,str2)<<endl;  
  return 0;
}

首先,根據strstr函式的實現方法得知函式需要傳進去的引數是兩個字串,而且這兩個字串都是不可更改的,這樣,我們可以利用const來修飾;而且函式返回的也是一個字串,那麼返回值型別也可以確定,這樣,我們可以寫出這樣一個函式的定義:char* my_strstr(const char* dest,const char* src){}。其中,dest指向的是目標字串,也就是你需要比較的字串,src指向的是源字串,也就是用來被比較的字串。找不到就可以返回一個空指標。

實現的思路也是比較簡單的,你可以建立兩個指標,通過遍歷的方式逐個訪問字串,並對這兩個指標一一比較。

////

舉例說明:給上倆個字串:

str1:abcdefg

str2:bcd

建立兩個指標:char *start=str1; char *substart=str2;

此時,start指向字元a,而substart指向字元b,對start和substart兩個指標解引用並進行比較,判斷是否相等,即*start=*substart;若是兩個相等,則兩個指標都向後移動一位,再解引用進行判斷;若是兩個不相等,那麼start向後移動一位,substart則將會重新指向str2的起始位置,兩個再次進行比較。重複這個過程,直到兩個字串其中一個或者是兩個都遇到‘\0’,遍歷結束。那麼在這裡你就可以採用迴圈的方法來做;迴圈的判斷條件就是(start!='\0' && substart!='\0' && *start==*substart)。

////

如果到這裡你覺得這個函式就算實現成功的話,那你可就掉到坑裡去了。我再舉個例子吧:

str1:abbbcdefg

str2:bbcd

這裡你繼續採用上面的方式做,你會得到不一樣的結果。

指標判斷,當start指向str1中的第一個b時,substart指向str2中的第一個b,兩個相等,再往後面遍歷,當start指向第三個b的時候,substart指向c,兩個不相等,那麼此時substart會返回並指向str2中的第一個b。

注意,此時start指向的還是str1中的第三個b,start並沒有發生移動,再採用如上的方式比較,從str1的第三個b開始,你再也找不到與str2相同的,那麼函式會返回一個 空,可是顯然第一個字串中包含你需要的查詢的字串。這樣,我們就需要通過某種方法來解決這個問題。

解決方法其實也是比較簡單的:當兩個字串比較的結果不相等時,我們知道substart,就是指向第二個字串的指標是返回到str2這個字串的起始位置的,而start這個指標並沒有發生任何的變動。再次比較也只能從這個位置繼續向後比較,那麼中間肯定就會有一些字元是沒有辦法比較的。所以,當兩個字元比較不相等時,start這個指標也需要向前返回,不過它回到的不是起始位置了,而是起始位置的下一個位置,這樣就可以避免重複而無用的比較。所以,我們需要在建立一個指標cp用來儲存起始位置,並讓start返回到起始位置的下一個位置。(此處為從別人部落格摘抄的,感覺寫的特比妙)
6.實現memcpy

mecmpy是記憶體的拷貝函式

這個函式的原型是 void* mecmpy(void* destination,const void* source,size_t num);函式mecmpy從source 的位置開始向後複製num個位元組的資料到destination的記憶體位置。注意這個函式在遇到'\0'是不會停下來的。如果source和destination有任何的重疊,複製的結果都是未定義的。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
void* my_memcpy(void* dst,void* src,size_t count)
{
  void* ret=dst;
  while(count--)#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
void* my_memcpy(void* dst,void* src,size_t count)
{
  void* ret=dst;
  while(count--)
  {
    *(char* )dst=*(char* )src;
    dst=(char*)dst+1;
    src=(char*)src+1;
  }
  return ret;
}
int main()
{
  float arr1[]={1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0};
  float arr2[10];
  int len=sizeof(arr1)/sizeof(arr1[0]);
  my_memcpy(arr2,arr1,len);
  return 0;
}

  {
    *(char* )dst=*(char* )src;
    dst=(char*)dst+1;
    src=(char*)src+1;
  }
  return ret;
}
int main()
{
  float arr1[]={1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0};
  float arr2[10];
  int len=sizeof(arr1)/sizeof(arr1[0]);
  my_memcpy(arr2,arr1,len);
  return 0;
}

此函式和memcpy的差別就是memmove函式處理的源記憶體塊和目標記憶體塊是可以重疊的,如果源空間和目標空間出現重疊,就得使用memmove函式處理

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
void* memove(void* dst,const void* src,size_t count)
{
  void* ret=dst;
  if(dst<=src||(char*)dst>=((char*)src+count))
  {
    while(count--)
    {
      *(char *)dst=*(char *)src;
      dst=(char*)dst+1;
      src=(char*)src+1;
    }
  }
  else
  {
    dst=(char*)dst+count-1;
    src=(char*)src+count-1;
    while(count--)
    {
      *(char*)dst=*(char*)src;
      dst=(char*)dst-1;
      src=(char*)src-1;
    }
  }
  return ret;
}
int main()
{
  char str1[]="hello";
  char str2[]="world";
  int len=strlen(str1);
  memmove(str1,str2,len);
  cout<<memove(str1,str2,len)<<endl;
  return 0;
}

複製的是一個記憶體。