一个栈数据越界的小例子

来源:互联网 发布:mac微博客户端是什么 编辑:程序博客网 时间:2024/05/21 10:02

前段时间,有个学妹跑过来找我,学长,我的程序出了bug,找不出来,你帮我看看吧。去了之后看到她的代码是这样写的(我只写出主要出问题的代码):

struct stu{    char name[10];    char passwd[10];};//定义了一个结构体,成员变量为两个char数组;//她在某个函数方法内是这样写的int i;struct stu st;for(i=0;i<10;i++)    st.name[i]=getc();for(i=0;i<10;i++)    st.passwd[i]=getc();//然后把结构体的内容写入某个文件中;fprintf(fd,"%s ",st.name);fprintf(fd,"%s\n",st.passwd);

这个学妹比较实在,她每次输入的名字都是10个字节,密码也是,于是乎就有了下面的问题;
她在后面的程序中把数据存文件中读出来,然后输入当时写的数据进行验证,结果是错的,验证总是失败的,百思不得姐,然后来找我了。
我在大概扫了代码后第一眼觉得好像没什么错啊,但是验证总是失败。很无奈,但是作为学长总不能说不会吧,多丢人。于是我再次仔细的审查了一下代码,终于发现了一点问题

for(i=0;i<10;i++)    st.name[i]=getc();for(i=0;i<10;i++)    st.passwd[i]=getc();

上述代码扫一眼看似没什么问题,但是 问题就是出在这的,还有就是她每次都会输入10个字符;这段代码的问题在于在每次输入后没有给数组结尾加‘\0’,问题找到了我得验证一下是不是这个原因,结果打开文件,里面的数据我正如我想的,第一列数据是20个字节,第二列数据是10个字节。为什么会出现这样的问题呢;在解释之前先看一个小程序:

#include<stdio.h>int main(int argc, char **argv){  int i;  int a[5];  for(i=0;i<6;i++)    a[i]=0;  printf("hello word");  return 0;}

在windows上这段代码是没有输出的,但是下面这段代码却会输出伟大的“hello word”

#include<stdio.h>int main(int argc, char **argv){  int a[5];  int i;  for(i=0;i<6;i++)    a[i]=0;  printf("hello word");  return 0;}

两段代码唯一的不同点就是两个变量的声明顺序不同造成了两种完全不同的结果,为什么呢?看一下程序的内存分配图;
这里写图片描述
在上述代码中的i和数组a由于是函数的私有空间,隐藏他们都在栈内存中,而栈的特点是向下生长的,首先定义的i在数组a的上方,a的数据从一号元素到最后一个的排列方式是从下往上的,如下图:
这里写图片描述
如上图数组的起始下标是0,而上述代码的数组下标结束时5,a[5]在代码中找不到,但是在内存中可以啊,a[5]低地址就是i的地址于是数组越界把i的值给覆盖了,i就从5变成0,然后for循环重新开始。如果把放在a[0]后面则也会越界,但是对i没有影响,但是数组越界所造成的伤害是不可预知的,所以不要相互伤害。
现在回到刚开始的问题,字符串的结束标志是’\0’,但是字符数组的最后一个元素一般都是用来放置’\0’的,然而当输入的字符和数组大小相同时,’\0’就会被覆盖,然而后面紧跟的确实下一个字符串,在读取的时候回找’\0’,然而很遗憾,在第一船数据后面没找到,于是就越界吧继续向下寻找,然而比较幸运,在第二串后面找到了(虽然第二串也没标记,但是编译器比较好,在最后加了一个),于是就把所遍历的数据全写入了,于是就形成了开始所讲述的问题。

0 0
原创粉丝点击