溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C之典型字符串(二十八)

發(fā)布時(shí)間:2020-08-28 14:21:35 來(lái)源:網(wǎng)絡(luò) 閱讀:431 作者:上帝之子521 欄目:編程語(yǔ)言

        我們?cè)谏瞎?jié)博客中介紹了 C 語(yǔ)言中字符串相關(guān)的概念,那么我們今天就來(lái)看看在字符串這塊的典型問(wèn)題。

        A、我們先來(lái)看看下面的示例代碼會(huì)輸出什么,代碼如下

#include <stdio.h>

int main()
{
    char buf[15] = {0};
    char src[] = "hello %s";
    
    snprintf(buf, sizeof(buf), src);
    
    printf("buf = %s\n", buf);
    
    return 0;
}

        我們先來(lái)說(shuō)說(shuō) snprintf 函數(shù),它本身是可變參數(shù)的函數(shù),原型是這樣的:int snprintf(char* buf, int buf_size, const char* fomart, ...)。當(dāng)函數(shù)只有3個(gè)參數(shù)時(shí),如果第三個(gè)參數(shù)沒(méi)有包含格式化信息,函數(shù)調(diào)用沒(méi)有問(wèn)題;相反,如果第三個(gè)參數(shù)包含了格式化信息,但缺少后續(xù)對(duì)應(yīng)參數(shù),則程序行為不穩(wěn)定。上面的程序中第8行調(diào)用了 snprintf 函數(shù),但是在第6行定義的 src 字符數(shù)組中包含了 %s,則它的行為是不確定的。我們來(lái)看看編譯結(jié)果C之典型字符串(二十八)

        我們看到編譯其實(shí)已經(jīng)提示了,打印的結(jié)果果然是不確定的。那么我們?cè)?snprintf 函數(shù)中再加上第四個(gè)參數(shù)字符串“world”試試(或者直接把第6行后面的 %s 變成 world 也是同樣的效果)。編譯結(jié)果如下

C之典型字符串(二十八)

        那么我們看到編譯沒(méi)有警告,程序也完美運(yùn)行。

        B、我們?cè)賮?lái)看看下面這份示例代碼

#include <stdio.h>
#include <string.h>

int main()
{
    #define STR "Hello, \0World\0"
    
    char* src = STR;
    char buf[255] = {0};
    
    snprintf(buf, sizeof(buf), src);
    
    printf("strlen(STR) = %d\n", strlen(STR));
    printf("sizeof(STR) = %d\n", sizeof(STR));
    
    printf("strlen(src) = %d\n", strlen(src));
    printf("sizeof(src) = %d\n", sizeof(src));
    
    printf("strlen(buf) = %d\n", strlen(buf));
    printf("sizeof(buf) = %d\n", sizeof(buf));
    
    printf("src = %s\n", src);
    printf("buf = %s\n", buf);
    
    return 0;
}

        我們先來(lái)分析下這個(gè)程序,第6行定義了一個(gè)宏,但是它里面有兩個(gè) \0,實(shí)際上是3個(gè),因?yàn)榫幾g器還會(huì)為字符串自動(dòng)去分配個(gè) \0。在程序的第11行進(jìn)行 src 到 buf 的內(nèi)容復(fù)制。我們?cè)谏蠈谜f(shuō)過(guò)字符數(shù)組是以 \0 結(jié)尾的,因此第13行打印的長(zhǎng)度為7。但第14行打印的是它整個(gè)宏定義的長(zhǎng)度,所以為15。第16行打印的也便是 7 了,第17行打印的指針的長(zhǎng)度,便是4。第19行打印的 buf 中內(nèi)容的長(zhǎng)度同樣也是 7,第20行打印的 數(shù)組 buf 的長(zhǎng)度便是 255。第22和23行分別打印 src 和 buf 中的內(nèi)容,便是 hello 了。我們來(lái)看看編譯結(jié)果C之典型字符串(二十八)

        結(jié)果和我們分析的一致,字符串字面量的本質(zhì)為數(shù)組。

        C、再來(lái)看第三個(gè)示例程序,代碼如下

#include <stdio.h>
#include <string.h>

int main()
{
    #define s1 "hello world"
    #define s2 "hello world"
    
    if( s1 == s2 )
    {
        printf("Equal\n");
    }
    else
    {
        printf("Non Equal\n");
    }
    
    if( strcmp(s1, s2) == 0)
    {
        printf("Equal\n");
    }
    else
    {
        printf("Non Equal\n");
    }
    
    return 0;
}

        我們先來(lái)分析下,我們?cè)诘?和7行分別定義了兩個(gè)宏字符串(但是它們的內(nèi)容是相同的)。接下來(lái)我們直接將 s1 和 s2 進(jìn)行判斷是否相等。那么在這塊我們判斷的應(yīng)當(dāng)是他兩的地址,它們?cè)谶@塊就是數(shù)組,兩個(gè)數(shù)組怎么可能進(jìn)行相等比較呢。如果是判斷地址,第一個(gè) if 語(yǔ)句應(yīng)當(dāng)打印出不相等的。下面的 if 語(yǔ)句是用 strcmp 函數(shù)進(jìn)行判斷的餓,那么這個(gè)當(dāng)然是相等的啦,因?yàn)檫@個(gè)函數(shù)判斷的是他兩的內(nèi)容。所以經(jīng)我們分析,第一個(gè) if 語(yǔ)句打印出 Non Equal,第二個(gè) if 語(yǔ)句打印出 Equal。我們來(lái)看看編譯器就是是怎么處理的

C之典型字符串(二十八)

        我們看到第一個(gè)和我們分析的不一樣,那么我們?cè)賮?lái)看看 BCC 編譯器

C之典型字符串(二十八)

        那么 BCC 編譯器的結(jié)果和我們分析的是一致的。在 gcc 編譯器中它做了優(yōu)化,當(dāng)我們定義 s1 之后,進(jìn)行 s2 的定義時(shí)。編譯器發(fā)現(xiàn)他倆內(nèi)容是一樣的,便將 s2 也指向了 s1 的地址,因?yàn)樗X(jué)得你是在浪費(fèi)內(nèi)存。我們?cè)诔绦蛑屑由洗蛴?s1 和 s2 的地址的語(yǔ)句,gcc 打印結(jié)果如下

C之典型字符串(二十八)

        gcc 編譯器果然是將他倆放在一個(gè)地址上了。但是我們看看 BCC 呢

C之典型字符串(二十八)

        我們看到 BCC 是這樣的,所以我們?cè)谝院蟛荒軐懗鲆蕾囉谀撤N編譯器的代碼,這樣的話,代碼的可移植性就降低了。所以我們?cè)谶M(jìn)行字符串之間的相等比較時(shí)需要用 strcmp 完成,不可直接用 == 進(jìn)行字符串直接進(jìn)行比較。完全相同的媳婦吃字面量的 == 比較結(jié)果為 false。一些現(xiàn)代編譯器能夠?qū)⑾嗤淖址置媪坑成涞酵粋€(gè)無(wú)名字符數(shù)組,因此 == 比較結(jié)果為 true。

        D、最后我們?cè)賮?lái)看個(gè)關(guān)于字符串循環(huán)右移的問(wèn)題,這也是一道筆試面試題。代碼如下

#include <stdio.h>
#include <string.h>

void right_shift_r(const char* src, char* result, unsigned int n)
{
    const unsigned int len = strlen(src);
    int i = 0;
    
    for(i=0; i<len; i++)
    {
        result[(i+n) % len] = src[i];
    }
    
    result[len] = '\0';
}

int main()
{
    char result[255] = {0};
    
    right_shift_r("abcde", result, 2);
    
    printf("%s\n", result);
    
    right_shift_r("abcde", result, 5);
    
    printf("%s\n", result);
    
    right_shift_r("abcde", result, 8);
    
    printf("%s\n", result);
    
    return 0;
}

        我們可以利用求余的的方式進(jìn)行字符串的賦值。那么我們用一個(gè) for 循環(huán)就完成右移,它的時(shí)間復(fù)雜度為 O(n),這個(gè)效率無(wú)疑是最高的。


        歡迎大家一起來(lái)學(xué)習(xí) C 語(yǔ)言,可以加我QQ:243343083

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI