天天看點

C語言字元串函數及如何實作這些函數

C語言字元串函數及如何實作這些函數

近期在複習C語言字元串相關的知識,在觀看了 翁恺 老師的 C語言程式設計 課程後,打算對C語言标準庫以及 string.h 内的函數進行整理,并寫出自己的實作方式(部分函數涉及系統底層和複雜操作,隻給出簡單的C語言表示形式,數組同樣可以做出相應的函數,但本文以指針角度進行闡釋)。有不足之處還請大神指正。

1.putchar函數(屬于stdio.h庫函數)

函數原型: int putchar( int c )

函數作用:向标準輸出輸出一個字元

函數的傳回值:

  • 1:輸出成功
  • n( n為整數 ) :輸出了多個字元
  • EOF (-1) :輸出失敗
#include <stdio.h>
#undef

int myputchar(int c) {
    return fputc(c,stdout);    
    //fputc函數功能:将字元c寫到檔案指針fp所指向的檔案的目前寫指針的位置,
    //fputc函數原型:int fputc (int c, FILE *fp)
}      

2.getchar函數(屬于stdio.h庫函數)

函數原型: int putchar( void )

函數作用:向标準輸出讀入一個字元

函數的傳回值:

  • 以整數形式傳回讀入的字元
  • EOF (-1) :讀入失敗

這裡推薦一篇優質文章,主要講解getchar工作原理

3.strlen函數(屬于string.h庫函數)

函數原型: *size_t strlen( const char s )

函數作用:傳回s的字元串長度

函數的傳回值:整數,表示s的字元串長度,字元串結尾的‘\0’不計入長度。

函數的自實作

int mystrlen(const char *s){
    int len = 0;
    while( *s != '\0' ){
        len++;
        s++;
    }
    return len;
}    //使用指針實作      

4.strcmp函數(屬于string.h庫函數)

函數原型: **int strcmp( const char s1, const char s2 )

函數作用:比較兩個字元串,并傳回值

函數的傳回值:

  • 0 : s1 == s2
  • n : s1 > s2 , 且s1與s2內插補點為n(n為正整數)
  • -n : s1 < s2 , 且s1與s2的內插補點為-n(n為正整數)

函數的自實作

int mystrcmp(const char *s1, const char *s2){
    while(*s1 == *s2 && s1 != '\0'){
        s1++;
        s2++;
    }
    return *s1 - *s2;
}    //使用指針實作      

5.strcpy函數(屬于string.h庫函數)

函數原型: **char *strcpy(char restrict dst, const restrict src)

函數作用:将src的字元串拷貝到dst(注: 關鍵字restrict表示src和dst不重疊(在記憶體中的儲存位置不重疊)(c99))并傳回dst

函數的傳回值:dst (傳回值是為了使該函數能夠參與到其他運算中去)

//使用示例:複制一個字元串
char *dst = (char*)malloc(strlen(src)+1);  
//strlen不包含結尾’/0‘的長度,需要在傳回值上+1機關長度
strcpy(dst,src);      

函數的自實作

char *mystrcpy(char *dst, const char *src){
    while(*src != '\0'){
        *dst = *src;
        dst++;
        src++;
    }
    *dst = '\0';
    return dst;
}    //使用指針實作      
//在 翁恺 老師的課程中提及此函數有更簡潔的表達方式(不影響編譯和實際效率)
char *mystrcpy(char *dst, const char *src){
    while(*dst++ = *src++);
    *dst = '\0';
    return dst;
}      

6.strcat函數(屬于string.h庫函數)

函數原型: **char *strcpy(char restrict s1, const restrict s2)

函數作用:将s2拷貝到s1的後面,将二者拼接為一個長的字元串并傳回s1

函數的傳回值:s1 (必須保證s1具有足夠的空間)

函數的自實作

char *mystrcat(char *s1, const char *s2){
    while(*s1 != '\0') s1++;
    while(*s1++ = *s2++);    //這裡采用更為簡略的寫法
    *s1 = '\0';
    return s1;
}    //使用指針實作      

7.strchr函數和strrchr(屬于string.h庫函數)

函數原型: **char strchr(const char s, int c)

函數作用:從左向右搜尋指定字元

函數原型:**char strrchr(const char s, int c)

函數的傳回值:從左/右向右/左搜尋指定字元

  • 若字元串中存在該字元,則傳回第一次周遊到的該字元的指針
  • 若字元串中不存在該字元,則傳回NULL

函數的自實作

char *mystrchr(const char *s, int c){
    while(*s != c && *s != '\0') s++;
    return (char*)s;
}    //使用指針實作
//(PS:如有更優解決方案請指出,我在嘗試将s++寫進while判斷條件裡的時候遇到了一些問題:)
//  while(*s++ != c && *s++ != '\0');
//此語句在執行過程中遇到一些奇怪的問題,比如一些字元(如'e')無法搜尋到,而其他字元能夠正常搜尋到,暫未深究...
//mystrrchr省略,原理大緻相同      

8.strstr函數和strcasestr(屬于string.h庫函數)

函數原型: **char *strstr(const char s1, const char s2)

函數作用:搜尋指定字元串(在s1中搜尋s2)

函數原型: **char *strcasestr(const char s1, const char s2)

函數作用:忽略大小寫搜尋指定字元串(在s1中搜尋s2)

函數的傳回值:

  • 若str2是str1的子串,則傳回str2在str1的首次出現的位址
  • 如果str2不是str1的子串,則傳回NULL
char *strstr(const char *s1,const char *s2)
{
    char *p = s1;
    const len = strlen(s2);
    while((p=strchr(p,*s2))){
        if(strncmp(p,s2,len)==0) return (char*)p;
        p++;
    }
    return NULL;
}    //使用指針實作,由于展開再寫一遍搜尋函數無意義,先使用string.h裡的部分函數(具體實作方法見前文)      

①strncpy

函數原型: **char *strncpy(char restrict dst, char restrict src, size_t n)

②strncat

函數原型: **char *strncat(char restrict s1, char restrict s2, size_t n)

③strncmp

函數原型: **int strncpy(char restrict s1, char restrict s2, size_t n)

繼續閱讀