新浪博客

gets()与puts()函数及字符串的处理

2014-10-26 10:54阅读:
1、gets()函数从终端输入一个字符串到数组,直到按回车键为止,并把回车键保存为'\0‘,因此gets()函数输入字符串没有长度限制,与定义的数组的长度没有直接关系,因为这个特点,在利用本函数写程序时,很容易发生意想不到的错误。 2、puts()函数与gets()函数类似,它从数组向终端输出字符串,直到遇到'\0'为止,并把它以回车换行的形式输出,同样也是一个容易产生程序漏洞的函数。
3.下面是编写的一个字符串连接函数
#include
int main()
{
char str1[5],str2[6],str[6];
int i,k;
gets(str1);
gets(str2);
for(i=0;i<5;i++)
str[i]=str1[i];
k=i;
for(i=k;i<10;i++)
str[i]=str2[i-k];
printf('%o',str1);
printf('%o',str2);
printf('%o',str);
puts(str1);
puts(str2);
puts(str);
return 0;
}
它的作用是把两个字符串str1和str2首位连接并保存在str中输出到终端,程序运行情况如图:
gets()与puts()函数及字符串的处理

代码中printf('%o',str1)这三条语句是为了用8进制把3个数组的起始地址显示出来,根据运行结果可知内存分配了3段相连接的部分给了3个数组,按从上到下的顺序依次为str,str1,str2,每段的长度都为6(这个地方我有一个疑问,为什么给str分配的内存长度为6?)。观察程序的运行结果可知,它与期望的结果并不相符。
究其原因,无非就是内存的分配以及gets()函数和puts()函数引起的错误。
下图为3个数组的内存分配图:
gets()与puts()函数及字符串的处理
其中str1先被赋值,str1='12b4t5r'并带有一个回车,其长度与str1定义的长度6无关;之后str2被赋值,恰好在str1起始地址105773之前停止(可以预见,如果运行时对str2多输入几个字符使得地址超过str1的首地址,那么之前str1中与str2地址相同处的字符将会被str2的字符覆盖)。然后便是循环语句对strd的赋值,第一次从首地址10577407开始,赋5个值到10577423结束,接着便是将str2的值向str赋值,此时由于str2与str有重复的内存地址,使得str的值在与str2相同地址处将str2的字符替换,因此最后str2='uty66'然后换行,根据遇到'\0'gets()才结束输出的原则,str='12b4teuty66'然后换行。
由此可见,由于内存的分配及puts()和gets()函数的性质,在内存重叠部分以及'\0'之前的剩余部分都使得运行的结果超出预期。
下面是另一种输出结果:
gets()与puts()函数及字符串的处理
分析可知,与预想的相同地址处发生字符的替换是相符合的。
尝试用printf函数和scanf函数改写,如图: gets()与puts()函数及字符串的处理
可见用printf和scanf函数时内存分配方式仍与前面相同,还需要改进。 为了解决内存地址的重叠问题,考虑到str内存位置在最前面,例如str1和str2都是长度为5的字符串,那么定义的时候将其长度定义为6,这是为了给'\0'保留一个位置,于是str应该是长度为10的字符串,为了保证str与str2的内存地址不重叠,应该定义str的长度至少为11,若定义为11,则str[11]='\0',且str[11]后面的内存地址恰好为str2的首地址,如图:
gets()与puts()函数及字符串的处理
此时程序运行得到了预期的结果。
总结:字符串的处理中,定义数组长度为字符串长度+1(为\0保留的位置),每个字符串都这样处理的话,就不会发生内存的重叠,也能在正确的位置遇到\0结束输出。

我的更多文章

下载客户端阅读体验更佳

APP专享