读书人

2012华为软件机考题 浅析 -C/C++ 西

发布时间: 2012-09-21 15:47:26 作者: rapoo

2012华为软件机试题 浅析 --------------------C/C++ 西安交大考点

热火朝天准备了两天的华为机试,终于考了。考前很虚,很多东西没看。好在华为的机试不考死记硬背的东西,考的编程的规范、思维。今年的考题只有一道,时间20分钟。所有人都是C/C++,没有java。真正编代码的时间也就五六分钟,题很简单。但我觉的,还是很有水平的题。

题目:将字符串中的每一个字符,变成他的下一个字符。大小写不变,如果是z就改成a。(其他的没说,如果是Z改成A)。比如,输入为abcf,输出应为bcdg。

函数原型给定了:void change_letter(char *pInStr, char *pOutStr)

下面是我的作答,仅供参考:

#include<stdio.h>void change_letter(char *pInStr, char *pOutStr){if(pInStr == NULL || pOutStr == NULL)return;while(*pInStr){if(*pInStr == 'z')*pOutStr = 'a';else if(*pInStr == 'Z')*pOutStr = 'A';else*pOutStr = *pInStr + 1;pInStr++;pOutStr++;}*pOutStr = '\0';}void main(){char *test = "guozhaoyanguoqi";char *out = (char *)malloc(strlen(test));*out = '\0';//char out[100];change_letter(test, out);printf("%s\n", out);}

这里,有几个值得注意的地方,这些细节也正是考官的加分点或扣分点。

1,函数的开头要判断是否申请了内存:if(pInStr == NULL || pOutStr == NULL),因为他们要求不准自己加头文件。默认的就是#include<stdio.h>,所以没用assert。扯淡的是,考场上由于紧张,我只判断了pInStr,忘了判断输出了!它大爷的2012华为软件机考题 浅析 -C/C++    西安交大考点

2,while循环里可以写while(*pInStr != '\0'),也可以像我上面写的那样while(*pInStr),本着简单的原则我采用后者。

3,while循环出来之后,输出字符串一定要加字符串结束符'\0'.while循环出来之后,指针pOutStr指向的是最后一个字符的下一个字节,所以这里直接赋值‘\0’就可以了。从程序健壮性考虑一定要赋,但也有意想不到的隐情,请看4

4,主函数里要给out申请内存。有两种方式,一种是char out[100];直接申请100个。如果while循环里不加'\0',将会看到如下错误结果:

2012华为软件机考题 浅析 -C/C++    西安交大考点

如果加上‘\0’的话,一切会正常。但我想工程上不会让这么浪费内存吧,因此采用第二种方式是必须的。

第二种方式,char *out = (char *)malloc(strlen(test));即用多少申请多少。这时,while循环出来之后,从程序结果上来看加不加'\0'都是一样的,但真的么?我将程序修改如下:

#include<stdio.h>#include<stdlib.h>void change_letter(char *pInStr, char *pOutStr){if(pInStr == NULL || pOutStr == NULL)return;while(*pInStr){if(*pInStr == 'z')*pOutStr = 'a';else if(*pInStr == 'Z')*pOutStr = 'A';else*pOutStr = *pInStr + 1;pInStr++;pOutStr++;}//*pOutStr = '\0';}void main(){char *test = "guozhaoyanguoqi";// *out = NULL;//printf("strlen(test) = %d", strlen(test));char*out = (char*)malloc(strlen(test));//*out = '\0';//char out[100];change_letter(test, out);printf("%s\n", out);printf("strlen(out) = %d\n", strlen(out));}
运行结果:

2012华为软件机考题 浅析 -C/C++    西安交大考点虽然字符串的结果是对的,但打印出来strlen(out)=19,而源字符串的长度是15. 这里就出错了,如果此时对out没有察觉,用out作其他处理时会引发致命错误!这些大公司考字符串不是没有意义的。

对了对比明确,我将主程序修改如下:

void main(){char *test = "guozhaoyanguoqi";printf("strlen(test) = %d", strlen(test));char*out = (char*)malloc(strlen(test));//*out = '\0';//char out[100];change_letter(test, out);printf("%s\n", out);printf("strlen(out) = %d\n", strlen(out));}
仅仅是在申明char *out前加了一句话,竟然编译不通过:

错误信息是:

C:\Documents and Settings\Administrator\桌面\快捷方式\huawei.c(25) : warning C4013: 'strlen' undefined; assuming extern returning intC:\Documents and Settings\Administrator\桌面\快捷方式\huawei.c(26) : error C2143: syntax error : missing ';' before 'type'C:\Documents and Settings\Administrator\桌面\快捷方式\huawei.c(29) : error C2065: 'out' : undeclared identifierC:\Documents and Settings\Administrator\桌面\快捷方式\huawei.c(29) : warning C4047: 'function' : 'char *' differs in levels of indirection from 'int 'C:\Documents and Settings\Administrator\桌面\快捷方式\huawei.c(29) : warning C4024: 'change_letter' : different types for formal and actual parameter 2Error executing cl.exe.
将主程序改为:

void main(){char *test = "guozhaoyanguoqi";char *out = NULL;printf("strlen(test) = %d\n", strlen(test));out = (char*)malloc(strlen(test));//*out = '\0';//char out[100];change_letter(test, out);printf("%s\n", out);printf("strlen(out) = %d\n", strlen(out));}
就能正常编译运行了!乖乖,多亏了写这个博客!看来c语言里,变量的申明和c++还是有所不同的,c++是即申明即用,但c略微不同,有时还不易察觉。像这里,如果没有printf("strlen(test) = %d\n", strlen(test));这句话,采用char*out = (char*)malloc(。。。)这种方式没有啥问题。但就多了一句printf这句话,这样申明就不中了。看来还是要规规矩矩的来!先申明char *out = NULL;然后再out=(char*)(。。。)。程序运行结果如下

2012华为软件机考题 浅析 -C/C++    西安交大考点
仅仅是对输入字符串的值做了改变,输出和输入的两个字符串的长度竟然不一样,这都是while循环里字符串结尾没有加‘\0’惹的祸!如果您不查看strlen,这个祸还有可能发现不了!

将while里的加‘\0’带上,如上的主程序,运行结果一切正常,如下:

2012华为软件机考题 浅析 -C/C++    西安交大考点

引发的三个未解决的疑问:

1,out的申明长度问题,是该out = (char*)malloc(strlen(test));还是该申明strlen(test)+1个长度?我用前者,也没有报错!按理说,应该申明strlen(test)+1更严密!否则的话最后while出来之后的*pOutStr的赋值占用的是非法内存,是未申明的内存。是不是有什么后患???

2,在out = (char*)malloc(strlen(test)+1)申明内存之后,是不是要用*out = '\0';对这块内存进行初始化一下? 我以前没有这个意识,最近看书籍,有的书上讲到这么初始化一下,不写这句也没发现啥问题。作何解释???

3,我连着申明两个字符串内存空间,如

char *test = "guozhaoyanguoqi";

char *out = = (char*)malloc(strlen(test)+1);

没有啥问题。当第一个语句后随便加一个语句,再申明out的时候怎么就乱报错???必须采用

char *out = NULL;

out = (char*)malloc(。。。。)

这种方式才能够申明通过。这两种申明方式本质上有什么区别吗?? 这就是传说中的字节对齐2012华为软件机考题 浅析 -C/C++    西安交大考点

ps:走出考场,我觉的写的程序能得90分最起码,吃饭时想到忘了判断pOutStr为NULL,得85分吧!文章写到一半,发现申明out的长度应该是strlen(pInStr)+1,得分80. 半路杀出个程咬金,无意发现申明字符串时的正确方式,应该是char*out = NULL;然后out = (char*)malloc(。。。),这样才严密!我靠,80分不到了。。。。。2012华为软件机考题 浅析 -C/C++    西安交大考点

欢迎大牛前来指点后生的三个疑问。


5楼yleek21分钟前
1 申请strlen(test)+1个长度是必须的,while最后加'\0'也是必须的n2 如果是char out[100],定义的时候用char out[100] = {0}初始化,如果是用malloc,可以用memset函数或者是bzero函数处理;另外如果是用malloc,好的习惯是要马上检查是否分配成功的,不要在作为实参使用的时候再检查n3 跟c的编译器有关哦,如果是老的编译器,c程序{}里用到的变量一定得前置声明或定义,函数就更是了,新的gcc应该不用哦,你试试n最后跟你说几个好的习惯:时刻谨记cstring是'\0'结尾的字符数组,不要存在侥幸心理;对于那些调用可能成功或者不成功的函数,调用完应该马上检查返回值;函数应该首先检查实参是否符合要求
4楼helinlin0071小时前
刚查看了一下strlen函数的原型,它是第一个"\0"就结束的,因此,它返回的是有效字符串的长度!
3楼ANDY20091小时前
关于最后一个问题:nn出错原因是VC支持的是C89标准,变量的声明必须出现在语句块{...}的首部,中间不允许插入其它非声明语句。按C99标准编译,就不会出现这种问题。
2楼chgaowei3小时前
文章写的挺详细,不错。n1楼三个问题回答的都对。nn从编程规范的角度考虑,你的函数还有几个问题:n1、分支条件后面即使有一句,也要加花括号。n2、if(pInStr == NULL || pOutStr == NULL) :最好是:nif((pInStr == NULL) || (pOutStr == NULL)) ,用括号明确的表明你的意图,而不是使用优先级。减少读者的思维量。n3、if和while后面都加空格,程序看起来更美观。n4、申请的内存要判断是否成功,成功要初始化,而且最后还要释放。虽然main退出后系统会自动回收,但是释放申请的内存是一个非常重要的习惯。这里面试官可能会非常在意。n5、最后,你可以现场鄙视一下华为设计的原型,像这个函数我绝对不允许我的员工使用,有安全隐患:nvoid change_letter(char *pInStr, char *pOutStr)n两个问题:参数pInStr在函数中式不允许改变的,可以加const修饰;npOutStr是输出字符串,可以把它的长度最为入参传进来。参考strncpy和snprintf。nn网上有流程的华为的编程规范,一个不错的教材。
1楼helinlin007昨天 23:44
师兄的这篇文章把华为机试的里面隐藏的问题找出来了,我之前都没有注意一些细节。n不过对于第二个问题,一般推荐都要加上“\0”进行初始化,如果不加“\0”,当要求输出第strlen(test)+1个数据的时候,可能会有系统报错,或者后面跟上一堆乱码。加了“\0”,则要求输出第strlen(test)+1个元素,就不会出现问题。

读书人网 >C++

热点推荐