咱們在上節博客中介紹了 C 語言中字符串相關的概念,那麼咱們今天就來看看在字符串這塊的典型問題。面試
A、咱們先來看看下面的示例代碼會輸出什麼,代碼以下數組
#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; }
咱們先來講說 snprintf 函數,它自己是可變參數的函數,原型是這樣的:int snprintf(char* buf, int buf_size, const char* fomart, ...)。當函數只有3個參數時,若是第三個參數沒有包含格式化信息,函數調用沒有問題;相反,若是第三個參數包含了格式化信息,但缺乏後續對應參數,則程序行爲不穩定。上面的程序中第8行調用了 snprintf 函數,可是在第6行定義的 src 字符數組中包含了 %s,則它的行爲是不肯定的。咱們來看看編譯結果ide
咱們看到編譯其實已經提示了,打印的結果果真是不肯定的。那麼咱們在 snprintf 函數中再加上第四個參數字符串「world」試試(或者直接把第6行後面的 %s 變成 world 也是一樣的效果)。編譯結果以下函數
那麼咱們看到編譯沒有警告,程序也完美運行。學習
B、咱們再來看看下面這份示例代碼優化
#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; }
咱們先來分析下這個程序,第6行定義了一個宏,可是它裏面有兩個 \0,其實是3個,由於編譯器還會爲字符串自動去分配個 \0。在程序的第11行進行 src 到 buf 的內容複製。咱們在上屆說過字符數組是以 \0 結尾的,所以第13行打印的長度爲7。但第14行打印的是它整個宏定義的長度,因此爲15。第16行打印的也即是 7 了,第17行打印的指針的長度,即是4。第19行打印的 buf 中內容的長度一樣也是 7,第20行打印的 數組 buf 的長度即是 255。第22和23行分別打印 src 和 buf 中的內容,即是 hello 了。咱們來看看編譯結果spa
結果和咱們分析的一致,字符串字面量的本質爲數組。指針
C、再來看第三個示例程序,代碼以下blog
#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; }
咱們先來分析下,咱們在第6和7行分別定義了兩個宏字符串(可是它們的內容是相同的)。接下來咱們直接將 s1 和 s2 進行判斷是否相等。那麼在這塊咱們判斷的應當是他兩的地址,它們在這塊就是數組,兩個數組怎麼可能進行相等比較呢。若是是判斷地址,第一個 if 語句應當打印出不相等的。下面的 if 語句是用 strcmp 函數進行判斷的餓,那麼這個固然是相等的啦,由於這個函數判斷的是他兩的內容。因此經咱們分析,第一個 if 語句打印出 Non Equal,第二個 if 語句打印出 Equal。咱們來看看編譯器就是是怎麼處理的圖片
咱們看到第一個和咱們分析的不同,那麼咱們再來看看 BCC 編譯器
那麼 BCC 編譯器的結果和咱們分析的是一致的。在 gcc 編譯器中它作了優化,當咱們定義 s1 以後,進行 s2 的定義時。編譯器發現他倆內容是同樣的,便將 s2 也指向了 s1 的地址,由於它以爲你是在浪費內存。咱們在程序中加上打印 s1 和 s2 的地址的語句,gcc 打印結果以下
gcc 編譯器果真是將他倆放在一個地址上了。可是咱們看看 BCC 呢
咱們看到 BCC 是這樣的,因此咱們在之後不能寫出依賴於某種編譯器的代碼,這樣的話,代碼的可移植性就下降了。因此咱們在進行字符串之間的相等比較時須要用 strcmp 完成,不可直接用 == 進行字符串直接進行比較。徹底相同的媳婦吃字面量的 == 比較結果爲 false。一些現代編譯器可以將相同的字符串字面量映射到同一個無名字符數組,所以 == 比較結果爲 true。
D、最後咱們再來看個關於字符串循環右移的問題,這也是一道筆試面試題。代碼以下
#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; }
咱們能夠利用求餘的的方式進行字符串的賦值。那麼咱們用一個 for 循環就完成右移,它的時間複雜度爲 O(n),這個效率無疑是最高的。
歡迎你們一塊兒來學習 C 語言,能夠加我QQ:243343083。