当前位置: 首页 > 科技观察

C语言的静态变量特性源自一道面试题

时间:2023-03-13 18:58:59 科技观察

最近部门在准备春招试题的时候,有这么一道题:用C/C++语言实现一个函数,给定一个int类型的整数,函数输出的是倒序整数对应的字符串,比如输入1234,则输出字符串“4321”,输入-1234,则输出字符串“-4321”。题目要求不使用标准库,不能分配动态内存。当时,我认为这很简单。这不是类似于字符串的反转吗?今天在这里整理一下常见的坑,巩固一下基础的东西。版本1的算法思路其实很简单:用10的余数和除法运算依次得到每一位数字,然后根据ASSIC码转换成字符,将结果存入char数组,最后返回字符串数组结果,如下:#include//versiononeconstchar*reverseInt(intn){charstr[16]={0};inttemp=n;inti=0;if(n<0){temp=-n;str[i++]='-';}//当temp被分成一位时退出while(0!=temp/10){charch=temp%10+48;temp=temp/10;str[i++]=ch;}//处理原始数据的第一位str[i++]=temp%10+48;returnstr;}intmain(intargc,char**agrv){inttest_data1=12345;inttest_data2=789;printf("[test_data1]%d--->%s\n",test_data1,reverseInt(test_data1));printf("[test_data2]%d--->%s\n",test_data2,reverseInt(test_data2));return0;}在编译时发现警告,如下:[root@epc.baidu.comctest]#gcc-g-otesttest.ctest.c:Infunction'reverseInt':test.c:24:2:warning:functionreturnsaddressoflocalvariable[-Wreturn-local-addr]returnstr;^编译器给的信息很清楚的说明了问题:返回的是一个局部变量的地址,但是我们知道函数的局部变量是存放在栈中的,当函数调用过程结束时,这个局部变量会被释放,自然就不能再用了,所以会产生这样的警告,这跟变量的生命周期有关。版本2针对版本1的问题,很自然的想到两种解决方案,***:使用malloc分配动态内存来存储结果,但是标题明明是不能分配动态内存的。所以自然排除了。第二种方案是将charresult[16]改为静态类型:staticcharresult[16];是的,这是一个很小的变化。#include//版本二constchar*reverseInt(intn){staticcharstr[16]={0};inttemp=n;inti=0;if(n<0){temp=-n;str[i++]='-';}//当temp分成一位时退出while(0!=temp/10){charch=temp%10+48;temp=temp/10;str[i++]=ch;}//处理原始数据的第一位str[i++]=temp%10+48;returnstr;}intmain(intargc,char**agrv){inttest_data1=12345;inttest_data2=789;printf("[test_data1]%d--->%s\n",test_data1,reverseInt(test_data1));printf("[test_data2]%d--->%s\n",test_data2,reverseInt(test_data2));return0;}run结果如下:[root@epc.baidu.comctest]#./test[test_data1]12345--->54321[test_data2]789--->98721从运行结果来看,第一次测试数据是正确的,但是第二次输出确实是错误的。是什么原因?先来回说一下用static修饰修饰的局部变量(也叫static局部变量)的特点,如下:1:静态局部变量在定义的时候没有赋初值,通过初始化为0默认;2:静态局部变量的作用域是一个函数或者一个代码块,其生命周期是在整个程序运行期间;注意不要混淆这两个概念;3:在一个进程的运行过程中,一个静态局部变量只会被初始化一次,也就是静态局部变量在第一次调用函数时被初始化,调用之后就不再初始化了。好了,至此,问题的原因已经很明显了:在上面的程序中,staticcharstr[16]={0}只会被初始化一次,也就是在执行reverseInt(test_data1)时,执行语句后,将结果存储在str中。此时str中的内容为54321,即str[16]={'5','4','3','2','1','\0'};当再次调用reverseInt(test_data2)转换第二个测试数时,str仍然是上一次的结果{'5','4','3','2','1','\0'},所以98721转换后。版本3那么如何解决版本2的问题,一个很简单的方法就是在reverseInt函数中每次使用for循环初始化静态变量str,如下,鉴于篇幅,main函数就不贴了:constchar*reverseInt(intn){staticcharstr[16]={0};inttemp=n;inti=0;intj=0;for(;j<16;j++){str[j]='\0';}if(n<0){temp=-n;str[i++]='-';}//当temp被分成一位时退出while(0!=temp/10){charch=temp%10+48;temp=temp/10;str[i++]=ch;}//处理原始数据的第一位str[i++]=temp%10+48;returnstr;}运行,可以得到我们期望的结果:[root@epc.baidu.comctest]#./test[test_data1]12345--->54321[test_data2]789--->987其实version3还有很多细节需要考虑,比如:当输入的整数超过intscope怎么处理等等,虽然是一个小细节,但是很重要。如果你有兴趣,你可以想一想,实践一下。

最新推荐
猜你喜欢