|
|
|
|
移动端

1.4 字符串(3)

《程序员面试笔试真题与解析》本书针对当前各大 IT企业面试笔试中特性与侧重点,精心挑选了 3年以来近百家典型 IT企业的面试笔试真题,这些企业涉及业务包括系统软件、搜索引擎、电子商务、手机 APP、安全关键软件等,面试笔试真题非常具有代表性与参考性。本节为大家介绍字符串。

作者:猿媛之家来源:机械工业出版社|2017-12-06 13:36

年前最后一场技术盛宴 | 1月27日与京东、日志易技术大咖畅聊智能化运维发展趋势!


1.4 字符串(3)

【真题 35】有如下代码:

  1. char str1[] = "abc";  
  2. char str2[] = "abc";  
  3. const char str3[] = "abc";  
  4. const char str4[] = "abc";  
  5. const char *str5 = "abc";  
  6. const char *str6 = "abc";  
  7. char *str7 = "abc";  
  8. char *str8 = "abc";  
  9. cout << (str1 == str2) << endl;  
  10. cout << (str3 == str4) << endl;  
  11. cout << (str5 == str6) << endl;  
  12. cout << (str7 == str8) << endl

程序的输出结果为()。

答案:0,0,1,1。

str1、str2、str3、str4是数组变量,它们有各自的内存空间;而 str5、str6、str7、str8是指针,它们

指向相同的常量区域。

【真题 36】有如下代码:

  1. #include <stdio.h> 
  2. typedef struct object object;  
  3. struct object  
  4. {  
  5. char data[3];  
  6. };  
  7. int main(void)  
  8. {  
  9. object obj_array[3] = { { 'a', 'b', 'c' }, { 'd', 'e', 'f' }, { 'g', 'h', 'i' } };  
  10. object* cur = obj_array;  
  11. printf("%c %c\n", *(char*)((char *)(cur)+2), *(char*)(cur + 2));  
  12. return 0;  

以上程序打印的两个字符分别是()。

A.c g  B.b d  C.g g  D.g c

答案:A。

本题中,cur是一个指向数组的指针,其中存储的是字符 ‘a’的地址,当 cur是 object指针时,cur+1

表示的是数组下一个元素的首地址,即字符‘ d’的地址。当 cur是 char指针时, cur+1是字符‘a’的下一个字符的地址,即‘ b’的地址。所以, *(char*)((char *)(cur)+2)表示的是字符‘ c’,*(char*)(cur+2)表示的是字符‘ g’。所以,选项 A正确。

【真题 37】不能把字符串“ HELLO!”赋给数组 b的语句是()。

A.char b[10]={'H','E','L','L','O','!','\0'}; B.char b[10];b="HELLO!";

C.char b[10];strcpy(b,"HELLO!"); D.char b[10]="HELLO!";答案:B。 b是数组的首地址,对于选项 B,b="HELLO!";改变了指针的指向,是错误的。所以,选项 B错误。

【真题 38】有如下代码:

  1. char *ptr;  
  2. char myString[] = "abcdefg";  
  3. ptr = myString;  
  4. ptr += 5; 

代码执行之后 ptr指向的内容是()。

A.Compiler error B.fg C.efg D.defg答案:B。本题中,当执行完语句 ptr = myString;后,ptr指向字符串“abcdefg”的起始位置,当执行完语句

ptr += 5;后,ptr向前移动 5个位置,指向字符 f,所以,选项 B正确。

【真题 39】在审计某一开源项目的代码时,假设有下面一个 foo()子函数的实现。从安全的角度看,会存在安全漏洞吗?有的话,请①描述漏洞细节;②说明可以利用的方法;③还有该怎么修补漏洞。没有的话,也请说明为什么。

  1. int foo( (void*funcp)( ) ){  
  2. char * ptr = pointer_to_an_array;  
  3. char buf[128];  
  4. gets(buf);  
  5. strncpy(ptr, buf, 8);  
  6. (*funcp)();  

提示:函数指针的缺陷、 gets函数的缺陷、 foo函数传参的问题等。

答案:1)没有判断 *funcp()指针是否为空。

2)调用 get(buf)的时候,没有判断 buf数组是否越界。因为 ptr定义在 buf之前,在栈上开辟内存空间,后定义的地址在低位,所以, ptr紧跟在 buf之后,如果 buf越界会覆盖 ptr指向的内容。

例如:如果 gets(buf)读取的字符串的长度超过了 128字节,那么第 129~132字节的内容会覆盖 ptr的值,那么在 strncpy(ptr,buf,8)的时候,就会改变第 129~132字节指定地址开始的 8字节的值(假设这 8字节是一段可执行的代码),然后第 133~136字节的值又会覆盖 funcp的值(假设覆盖后的值正好是之前第 129~132字节指定地址),那么当执行 (*funcp)()的时候,程序就会跳过去执行 129~132字节中注入的代码了,会有意想不到的结果,也有非常大的安全隐患。

【真题 40】有如下代码:

  1. char s[]="\\123456\123456\t";  
  2. printf("%d\n",strlen(s)); 

程序的输出结果是( )。

A.12  B.13  C.16  D.以上都不对

答案:A。

strlen是一个计数器,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符‘ \0’为止,然后返回计数器值 (长度不包含‘ \0’)。本题中,由于字符 \为转义字符, \\表示字符 \,\123表示字符 S,\t表示制表符。所以,选项 A正确。

【真题 41】从程序健壮性进行分析,下面的 FillUserInfo函数和 main函数分别存在什么问题 ?

  1. #include<iostream> 
  2. #include<string> 
  3. #define MAX_NAME_LEN 20  
  4. struct USERINFO  
  5. {  
  6. int nAge;  
  7. char szName[MAX_NAME_LEN];  
  8. };  
  9. void FillUserInfo(USERINFO* parUserInfo)  
  10. {  
  11. stu::cout <<"请输入用户的个数:";  
  12. int nCount = 0;  
  13. std::cin >> nCount;  
  14. for (int i = 0; i<nCount; i++)  
  15. {  
  16. std::cout <<"请输入年龄:";  
  17. std::cin >> parUserInfo[i]->nAge;  
  18. std::string strName;  
  19. std::cout <<"请输入姓名:";  
  20. std::cin >> strName;  
  21. strcpy(parUserInfo[i].szName, strName.c_str());  
  22. }  
  23. }  
  24. int main(int argc, char* argv[])  
  25. {  
  26. USERINFO arUserInfos[100] = { 0 };  
  27. FillUserInfo(arUserInfos);  
  28. printf("The first name is : ");  
  29. printf(arUserInfos[0].szName);  
  30. printf("\n");  
  31. return 0;  

答案:

1)在函数

FillUserInfo中没有验证 parUserInfo是否为空就直接使用了。

2)结构体中

szName的长度为 20,如果名字的长度超过 20,数组就会越界会引起段错误。

3)arUserInfos数组的大小为 100,如果在输入的用户个数超过 100,数组会越界,也会引发段错误。如果输入用户的个数小于 100就会造成空间浪费。

4)如果输入用户的个数为 0,那么在 main函数中输出的第一个用户名将会得到不确定的值。

5)没有判断输入的年龄是否是一个合法的值(比如负数)。

6)使用

strcpy可能会导致 szName数组越界,建议使用 strncpy。

7)初始化结构体数组使用的代码为: USERINFO arUserInfos[100]={0}; 一般不建议采用这种方式来初始化结构体,比较安全的方法为:ZeroMemory(arUserInfos,sizeof(arUserInfos));或者采用结构体的构造函数来初始化。

喜欢的朋友可以添加我们的微信账号:

51CTO读书频道二维码


51CTO读书频道活动讨论群:365934973

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

Wicked Cool Java中文版

本书主要介绍由Sun微系统公司创建的Java编程语言。 除了核心内容外,Java还有许多免费的财富,即开放源代码的库。本书就是为了介绍这些库...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊