📄 c.txt
字号:
9 strcpy(string, str1);
10 }
题(3)
1 void test3(char* str1)
2 {
3 char string[10];
4 if(strlen(str1) <= 10)
5 {
6 strcpy(string, str1);
7 }
8 }
解析
这3道题都有数组越界的问题。
q 题(1)中,string是一个含有10个元素的字符数组,str1指向的字符串长度为10,在进行strcpy调用时,会将str1的结束符也复制到string数组里,即复制的字符个数为11,这样会导致string出现数组越界。程序不一定会因此而崩溃,但这是一个潜在的危险。解决办法是将string的元素个数定义为11。
q 题(2)中,str1和string都是含有10个元素的字符数组,并且str1的元素全部被赋为字符“a”,然后再调用strcpy。这里会出现以下两个问题:一个问题是str1表示的字符数组没有以'\0'结束,在随后调用strcpy时无法判断什么时候复制结束;另一个问题是string的数组长度不够,出现数组越界的现象。解决办法是将string和str1的元素个数都定义为11个,并在调用strcpy之前加入一条语句把str1[10]赋为'\0'。
q 题(3)中,if语句使用小于等于“<=”进行比较,如果str1的长度等于10,也会出现数组越界的情况。解决办法是把“<=”换成“<”。
答案
3道题都有数组越界的问题。改正后的程序如下所示。
题(1)
1 void test1()
2 {
3 char string[11]; //字符数组长度为11,多分配一个
4 char* str1 = "0123456789";
5 strcpy(string, str1);
6 }
题(2)
1 void test2()
2 {
3 char string[11], str1[11]; //字符数组长度都为11,均多分配一个
4 int i;
5 for(i=0; i<10; i++)
6 {
7 str1[i] = 'a';
8 }
9 str1[10] = '\0'; //初始化str1为空字符串
10 strcpy(string, str1);
11 }
题(3)
1 void test3(char*str1)
2 {
3 char string[10];
4 if(strlen(str1) < 10) //不能用<=
5 {
6 strcpy(string, str1);
7 }
8 }
面试例题9:分析程序——数组越界。
考点:不当的循环操作导致数组越界。
出现频率:★★★
下面这个程序执行后会出现什么错误?
1 #define MAX 255
2 int main()
3 {
4 unsigned char A[MAX], i;
5
6 for (i = 0; i <= MAX; i++)
7 A[i] = i;
8 }
解析
代码第6行的for循环中用的是“<=”,当i=MAX时数组越界。值得注意:这个程序很容易使人误认为只有数组越界的问题,但只要细心些就能发现,i是无符号的char类型,它的范围是0~255,所以“i<=MAX”一直都是真,这样会导致无限循环。可以把“i<=MAX”改为“i<MAX”,这样既避免了无限循环又避免了数组越界。
答案
i<=MAX导致数组越界以及无限循环,应改为i<MAX。
面试例题10:分析程序——打印操作可能产生数组越界。
考点:打印操作时可能产生的数组越界问题。
出现频率:★★★
下面这个程序的打印结果是什么?
1 #include <stdio.h>
2
3 int main()
4 {
5 int a[5]={0, 1, 2, 3, 4}, *p;
6 p = a;
7 printf("%d\n",*(p + 4*sizeof(int)));
8
9 return 0;
10 }
答案
这个程序存在着越界的问题。
代码第6行,p指向a的第1个元素,所以p+4指向a的最后一个元素即4,p + 4 * sizeof(int)即p+16,此时指向的是数组a的第17个元素,显然已经越界了,因此打印结果是个随机数。
6.2.3 其他编程问题
由于字符串非常灵活,因此面试中非常注重字符串操作的考察。本节列出了一些经常出现的字符串考题,例如有关字符串长度检测,查找子串,单向翻转,判断是否回文等的题目。
面试例题11:编程实现字符串的长度检测。
考点:strcpy库函数的实现细节。
出现频率:★★★★★
解析
这个题目非常简单,字符串是以'\0'作为结束符,所以只需要做一次遍历就可以了。但是需要注意的是要尽量把程序写得简单高效。看下面的示例代码:
1 #include <stdio.h>
2 #include <assert.h>
3
4 int strlen1(const char* src)
5 {
6 assert( NULL != src); //src必须有效
7 int len = 0; //保存src的长度
8 while(*src++ != '\0') //遇到结束符'\0'退出循环
9 len++; //每循环一次len加1
10 return len;
11 }
12
13 int strlen2(const char* src)
14 {
15 assert( NULL != src); //src必须有效
16 const char *temp = src; //保存src首地址
17 while(*src++ != '\0'); //遇到结束符'\0'退出循环
18 return (src-temp-1); //返回尾部指针与头部指针之差即长度
19 }
20
21 int main()
22 {
23 char p[] = "Hello World!";
24 printf("strlen1 len: %d\n", strlen1(p)); //打印方法1得到的结果
25 printf("strlen2 len: %d\n", strlen2(p)); //打印方法2得到的结果
26
27 return 0;
28 }
strlen1和strlen2这两个函数用来计算字符串长度。它们的区别如下所示。
q strlen1用局部变量len在遍历的时候做自增,然后返回len。因此每当while循环一次,就需要执行两次自增操作。
q strlen2用局部变量temp记录src遍历前的位置。while循环一次只需要一次自增操作,最后返回指针之间的位置差。
当字符串较长的时候strlen2比strlen1的效率更高。下面是程序的输出结果:
strlen1 len: 12
strlen2 len: 12
面试例题12:编程实现字符串中子串的查找。
考点:strstr库函数的实现细节。
出现频率:★★★★★
编写实现strstr即一个函数,即从一个字符串中,查找另一个字符串的位置,如strstr("12345", "34")返回值为2,即在2号位置找到字符串34。
解析
程序如下所示:
1 #include <stdio.h>
2 #include <assert.h>
3
4 const char *strstr(const char* src, const char* sub)
5 {
6 const char *bp;
7 const char *sp;
8
9 if (src == NULL || NULL == sub) //判断src与sub的有效性
10 {
11 return src;
12 }
13 while (*src) //遍历src字符串
14 {
15 bp = src; //用于src的遍历
16 sp = sub; //用于sub的遍历
17 do
18 { //遍历sub字符串
19 if (!*sp) //如果到了sub字符串结束符位置
20 return src; //表示找到了sub字符串,退出
21 } while (*bp++ == *sp++);
22 src += 1;
23 }
24
25 return NULL;
26 }
27 int main()
28 {
29 char p[] = "12345";
30 char q[] = "34";
31
32 char *r = strstr(p, q);
33 printf("r: %s\n", r);
34
35 return 0;
36 }
main函数中的测试结果为:
r: 345
代码第32行调用strstr结束之后,r指向了数组p的第3个元素。这里strstr函数的方法是循环取src的子串与sub比较。以本题中的“12345”和“34”为例,比较步骤如下所示。
q “12345”和“34”比较,不满足匹配。
q “2345”和“34”比较,不满足匹配。
q “345”和“34”比较,满足匹配。
面试例题13:编程实现字符串中各单词的翻转。
考点:字符串相关的综合编程能力。
出现频率:★★★
编写函数,将“I am from Shanghai”倒置为“Shanghai from am I”,即将句子中的单词位置倒置,而不改变单词内部的结构。
解析
第1种方法代码如下:
1 #include <iostream>
2 using namespace std;
3
4 void RevStr(char *src)
5 {
6 char *start = src, *end = src, *ptr = src;
7
8 while(*ptr++ != '\0') //遍历字符串
9 {
10 if(*ptr == ' ' || *ptr == '\0') //找到一个单词
11 {
12 end = ptr - 1; //end指向单词末尾
13 while(start < end)
14 swap(*start++, *end--); //把单词的字母逆置
15
16 start = end = ptr+1; //指向下一个单词开头
17 }
18 }
19 start = src, end = ptr-2; //start指向字符串开头,end指向字符串末尾
20 while(start < end)
21 {
22 swap(*start++, *end--); //把整个字符串逆置
23 }
24 }
25
26 int main()
27 {
28 char src[] = "I am from Shanghai";
29 cout << src << "\n";
30 RevStr(src);
31 cout << src << "\n";
32
33 return 0;
34 }
程序输出结果:
1 I am from Shanghai
2 Shanghai From am I
RevStr函数有两个转换步骤:代码第8~18行将src中所有的单词进行翻转,其结果是src的内容变为“I ma morf iahgnahS”,然后代码第20~23行再进行全局翻转。
第2种方法代码如下:
1 #include <iostream>
2 using namespace std;
3
4 void RevStr(char *src)
5 {
6 char *start = src, *end = src, *ptr = src;
7
8 while(*ptr++ != '\0');
9 end = ptr-2; //找到字符串末尾
10 while(start < end)
11 {
12 swap(*start++, *end--); //逆置整个字符串
13 }
14
15 start = src, end = ptr-2;
16 ptr = start;
17 while(*ptr++ != '\0')
18 {
19 if(*ptr == ' ' || *ptr == '\0') //找到单词
20 {
21 end = ptr - 1; //end指向单词末尾
22 while(start < end)
23 swap(*start++, *end--); //逆置单词
24
25 start = end = ptr+1; //指向下一个单词开头
26 }
27 }
28 }
29
30 int main()
31 {
32 char src[] = "I am from Shanghai";
33 cout << src << "\n";
34 RevStr(src);
35 cout << src << "\n";
36
37 return 0;
38 }
程序输出结果:
I am from Shan ghai
Shanghai from am I
RevStr函数转换步骤与第1种方法相反,即代码第10~11行将src进行全局翻转, src的内容变为“iahgnahS morf ma I”,然后代码第17~第27行再把所有的单词进行翻转。
从上面的代码分析可以看出,两种方法都是采用了两个步骤,即字符串全局翻转和各个单词局部翻转,只是步骤的顺序不同,但是得到的结果都是一致的。
面试例题14:编程判断字符串是否为回文。
考点:字符串相关的综合编程能力。
出现频率:★★★★
判断一个字符串是不是回文。
解析
根据题目要求,我们可以从一个字符串的两端进行遍历比较。例如对于“level”字符串,我们可以进行如下操作。
q 计算需要比较的次数。由于“level”字符串长度为5,是奇数,因此比较2次。
q 第1次比较:看“level”的第1个字符与最后1个字符是否相等,如果相等进行第2次比较。
q 第2次比较:看“level”的第2个字符与倒数第2个字符是否相等,如果相等则是回文。
只要在上面的比较过程中有一个不相等,则字符串不是回文。根据以上思路,程序代码如下所示:
1 #include <iostream>
2 using namespace std;
3
4 int IsRevStr(char *str)
5 {
6 int i, len;
7 int found = 1; //1表示是回文字符串,0表示不是
8
9 if(str == NULL) //判断str的有效性
10 {
11 return -1;
12 }
13 len = strlen(str); //获得字符串长度
14 for(i=0; i<len/2; i++)
15 {
16 if(*(str+i) != *(str+len-i-1)) //遍历中如果发现相应头尾字符不等
17 { //则字符串不是回文
18 found=0;
19 break;
20 }
21 }
22 return found;
23 }
24
25 int main()
26 {
27 char str1[10] = "1234321"; //回文字符串
28 char str2[10] = "1234221"; //非回文字符串
29
30 int test1 = IsRevStr(str1); //测试str1是不是回文
31 int test2 = IsRevStr(str2); //测试str2是不是回文
32
33 cout << "str1 is " << (test1 == 1 ? "": "not ")
34 << "reverse string." << endl;
35 cout << "str2 is " << (test2 == 1 ? "": "not ")
36 << "reverse string." << endl;
37
38 return 0;
39 }
这个程序中的IsRevStr()函数用于判断字符串是否是回文字符串,如果是则返回1,否则返回0。输出结果:
str1 is reverse string.
str2 is not reverse string.
面试例题15:编程实现stcmp库函数。
考点:库函数strcmp的实现细节。
出现频率:★★★★★
解析
此题实际上就是实现C/C++库函数中的strcmp函数。对于两个字符串str1和str2,若相等则返回0,若str1大于str2则返回1,若str1小于str2返回-1。
程序代码如下所示:
1 #include <iostream>
2 using namespace std;
3
4 int mystrcmp(const char *src, const char *dst)
5 {
6 int ret = 0 ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -