成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【PHP源碼學(xué)習(xí)】2019-03-13 PHP字符串筆記

blair / 456人閱讀

摘要:釋放字符串內(nèi)存空間的時候,需要先釋放指針?biāo)赶虻膬?nèi)存空間,再釋放結(jié)構(gòu)體本身的內(nèi)存空間,效率同樣低下,而且這兩個操作順序不能顛倒。如果存了長度,就不會管你是否有,從頭開始讀字符串,一直讀長度為止即可。有些編譯器不支持?jǐn)?shù)組,可將其改成或均可。

baiyan

全部視頻:https://segmentfault.com/a/11...

源視頻地址:http://replay.xesv5.com/ll/24...

字符串的設(shè)計過程

在C99的柔性數(shù)組標(biāo)準(zhǔn)未發(fā)布之前,我們?nèi)绻朐O(shè)計一個數(shù)據(jù)結(jié)構(gòu),存儲一個字符串,可以很容易地想出如下代碼:

    struct string{
        ...
        int len;   //存長度(至于為什么存長度下文會講到)
        char* val; //存真正的字符串值
    };

那么我們發(fā)現(xiàn),這樣做有如下缺點:

訪問字符串值的時候,需要先訪問結(jié)構(gòu)體,在訪問指針?biāo)赶虻膬?nèi)存空間,需要2次內(nèi)存訪問,效率低下。

釋放字符串內(nèi)存空間的時候,需要先釋放char *val指針?biāo)赶虻膬?nèi)存空間,再釋放結(jié)構(gòu)體本身的內(nèi)存空間,效率同樣低下,而且這兩個操作順序不能顛倒。

那么如何改進(jìn)呢?很容易想到,我們將字符串值和結(jié)構(gòu)體存儲在一片連續(xù)的內(nèi)存空間就可以了。這樣的話,訪問字符串與釋放字符串的內(nèi)存空間,均僅需1次內(nèi)存訪問,在C99柔性數(shù)組標(biāo)準(zhǔn)發(fā)布之前,改進(jìn)代碼的方式如下:

int main() {

    struct string{
        int len;
    };

    typedef struct string str;

    char *s = "he";
    str *p = (str*)(malloc(sizeof(str) + strlen(s) + 1)); //分配足夠存下一個字符串的結(jié)構(gòu)體
    p->len = strlen(s);
    memcpy(p + 1, s, strlen(s)); //將字符串拷貝到緊鄰結(jié)構(gòu)體的內(nèi)存處

}

小插曲:這個代碼的第一版,我還出現(xiàn)了一個指針加法的錯誤,見:關(guān)于memcpy一個字符串到緊鄰結(jié)構(gòu)體內(nèi)存空間處的疑問

我們利用gdb調(diào)試一下這段代碼:

首先我們應(yīng)該給這個結(jié)構(gòu)體分配4 + 2 + 1 = 7字節(jié)的內(nèi)存空間,但是由于內(nèi)存對齊的原因,最終分配了8字節(jié)大小的空間。

結(jié)構(gòu)體本身和len字段的地址均是0x602010,len字段的長度為4B,指針加上4B的len字段長度之后,就應(yīng)該是字符串he的起始地址,即0x602014,將其強轉(zhuǎn)為char *,發(fā)現(xiàn)正好就是我們存的字符串值"he"。注意不是p+4,而是p+1。因為p+4 = p+4*sizeof(指針p的類型)

由于這樣編寫代碼過于繁瑣,所以C99干脆制定一個標(biāo)準(zhǔn),使用柔性數(shù)組代替上述寫法。其實使用的計算方法和上面一段代碼是一樣的,只不過換了一種簡化的寫法而已,這段代碼最終內(nèi)存中的存儲情況如下:

PHP7中字符串的實現(xiàn)

借助上文講到的字符串?dāng)?shù)據(jù)結(jié)構(gòu)設(shè)計思想,PHP中是這樣設(shè)計字符串的,它的結(jié)構(gòu)體叫做zend_string:

struct _zend_string {
    zend_refcounted_h gc;         /*引用計數(shù),與垃圾回收相關(guān),暫不展開*/
    zend_ulong        h;          /* 冗余的hash值,計算數(shù)組key的哈希值時避免重復(fù)計算*/
    size_t            len;        /* 長度 */
    char              val[1];     /* 柔性數(shù)組,真正存放字符串值 */
};

第一個問題:為什么要存長度len?不存長度,直接和C語言一樣通過字符串的"