读书人

讨论华为的一道面试题,该如何处理

发布时间: 2012-02-21 16:26:23 作者: rapoo

讨论华为的一道面试题
从网上看到华为的一道面试题,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{

char * str1= "6789 ";
char * str2= "123456789 ";
strcpy(str1,str2);
printf( "str1=%s\n ",str1);
printf( "str2=%s\n ",str2);
return 0;
}

有没有问题?网上的人说华为里面的人说这段代码是对的。

个人意见:字符串常量存在代码段中,这两个字符串是不可写的。char * str1和char * str2只是获取了常量字符串的首地址,所以strcpy根本无法执行。不知大家的看法是怎样,欢迎讨论。



[解决办法]
数据段分为.data段(可读写)与.rdata段(只读)
反汇编可以证明 "6789 " "123456789 "数据均放于.rdata段,
[
8: char * str1= "6789 ";
00401028 mov dword ptr [ebp-4],offset string "6789 " (00422040)
9: char * str2= "123456789 ";
0040102F mov dword ptr [ebp-8],offset string "123456789 " (00422034)
10: strcpy(str1,str2);
00401036 mov eax,dword ptr [ebp-8]
]
请看地址00422040与00422034的反汇编信息:
SECTION HEADER #2
.rdata name
13ED virtual size
22000 virtual address
2000 size of raw data
22000 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40000040 flags
Initialized Data
Read Only

RAW DATA #2
00422000: 00 00 00 00 E0 B5 E3 46 00 00 00 00 02 00 00 00 .......F........
00422010: 29 00 00 00 00 00 00 00 00 A0 02 00 73 74 72 32 )...........str2
00422020: 3D 25 73 0A 00 00 00 00 73 74 72 31 3D 25 73 0A =%s.....str1=%s.
00422030: 00 00 00 00 31 32 33 34 35 36 37 38 39 00 00 00 ....123456789...
00422040: 36 37 38 39 00 00 00 00 70 72 69 6E 74 66 2E 63 6789....printf.c
00422050: 00 00 00 00 66 6F 72 6D 61 74 20 21 3D 20 4E 55 ....format != NU
00422060: 4C 4C 00 00 69 33 38 36 5C 63 68 6B 65 73 70 2E LL..i386\chkesp.

这下应该弄明白了吧,其实原理就是在导入这个程序的时候,os把rdata所在的段进行tlb映射的时候,把段属性弄成了只读.因此一考贝数据,CPU就产生异常.

[解决办法]
CSYNYK() :
给这掉题目做个总结吧!(个人看法,如有谬误,请多指正,先谢谢各位了!^_^)
1、题目所给出的代码是正确的,可以编译、运行。
2、char * str1= "6789 ";和char * str2= "123456789 ";存放在静态数据存储区(没有在堆栈内)
3、可以对str1和str2进行读写操作!


你用的是什么编译器,居然可以运行?!
个人感觉str1,str2是指针而已,而且是一个指向常量的指针,给他们赋值不是在尝试修改这个常量吗?
[解决办法]
单独开辟一个readonly text section比较浪费内存空间,(虚拟内存都是按页分配的),有些编译器可能选择把字符串常量放到bss section,不管怎样,js14(印度three)的做法是值得学习的,想了解自己的编译器,就查一下编译器的汇编结果,dumpobj一下看看编译器是如何分配数据的
[解决办法]
在VC6.0上测试可以运行,输出:
123456789
9

猜测原因:存在内存对其问题
char * str1= "6789 ";
char * str2= "123456789 ";
str1为0x00416000,str2为0x00416008,str2-str1=8;

字符串 "6789 "一共占5个字节,但是后面被补齐,加了3个字节,使得字符串 "123456789 "从0x00416008位置开始。所以str2输出来是9就很好理解了。
[解决办法]
其实当你了解了C++语言的内存模型的时候
那你就可以认为你对语言的了解有了一个质的飞跃!

此题如果你了解各种数据的内存模型的话
简单的一眼就可以看出来
char * str1= "6789 ";
char * str2= "123456789 ";
str1和str2显然是一个存储在静态数据区的字符串常量,


只具赋值后只具有读取的权限,没有写入权限,怎么可以执行strcpy操作呢?

楼主是否在定一个变量的时候,是否考虑它存在哪里呢,比如所栈,堆,静态数据区
当你有这样考虑的时候,那你可以处理很多你想不通的问题,万变不离其宗!
[解决办法]
不愧是华为的试题
1。“str2拷贝到str1中的同时把str2的前12345覆盖了!结果str2就只剩下6789了!看来很多东西都书上都只讲到了表面阿!(turbo c实用大全中指出“如果str1和str2重叠,strcpy()的行为是非法的”)”主要考查这个
2。char *p = "AAA "; p的位置在堆栈,指向的空间位置是数据段(《程序员面试宝典》)
3。数组传给函数做参数,就退化为指针 void fun(char *p)等同void fun(char p[])
这是数组可以做参数且不必指定空间长度的原因
美国某著名软件公司面试题:
#include <iostream.h>
#include <stdio.h>
int main(void)
{ char src[] = "123456789 ";
char dest[] = "123 ";
strcpy(dest,src);
printf( "%s,%s ",dest,src);
return 0;
}
输出结果:
123456789,56789
原因:分配内存时内存地址是连续的,原来是1234\0123456789\0 ,
strcpy后变成了123456789\06789\0 ,空间分配不足
把 char src[] = "123456789 ";
char dest[] = "123 ";
这两行调换下可以正确输出结果123456789,123456789,但产生一个运行期错误,目标字符串越过了实际空间,访问到了不可预知的地址。

[解决办法]
各个编译器似乎不一样

不过一句
char * str1= "6789 ";
char * str2= "123456789 ";
str1和str2显然是一个存储在静态数据区的字符串常量,

尽量不要使用 strcpy(str1,**) 或strcpy(str2,**)
C++Prime plus 4rd version对这问题提及一下。
知道就行了,自己别用。

[解决办法]
用TC 编译和运行都没有错误, 结果为:
str1=123456789
str2=6789

另外gcc编译也同样。
程序本身没有错误吧。
P.S:个人认为 用char * str1和char * str2来拷贝比用字符数组更好一些(节省内存)。
[解决办法]
用TC 编译和运行这种结果:
str1=123456789
str2=6789

其原因是:str2的6789其实是str1的后半段。
内存初始为 (6) 7 8 9 \0 (1) 2 3 4 5 6 7 8 9 \0
strcpy(str1,str2)后:(1) 2 3 4 5 (6) 7 8 9 \0 6 7 8 9 \0
str1最初指向(6),str2指向(1),strcpy()后,指针位置不变,str1指向(1),str2指向(6)
所以输出结果为:
str1=123456789
str2=6789

[解决办法]
用TC 编译和运行这种结果:
str1=123456789
str2=6789

其原因是:str2的6789其实是str1的后半段。
内存初始为 (6) 7 8 9 \0 (1) 2 3 4 5 6 7 8 9 \0
strcpy(str1,str2)后:(1) 2 3 4 5 (6) 7 8 9 \0 6 7 8 9 \0
str1最初指向(6),str2指向(1),strcpy()后,指针位置不变,str1指向(1),str2指向(6)
所以输出结果为:
str1=123456789
str2=6789
str2的6789其实就是str1的后半段。

读书人网 >C语言

热点推荐