咱们在上节博客中介绍了 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。