工大后院

 找回密码
 加入后院

扫一扫,访问微社区

QQ登录

只需一步,快速开始

搜索
查看: 2900|回复: 25

问题多多请别见怪,还是关于内存的

[复制链接]
发表于 2006-12-26 10:34 | 显示全部楼层 |阅读模式
当我定义“char a[2]"时
编译器会给数组多少内存空间??
为什么我运行以下代码时可以正常输入并输出3个字符??
#include <stdio.h>
void main()
{
char a[2];
scanf ("%s",a);
printf ("%s\n",a);
}
而当括号内改成5时,就可以正常输入7个数!!
为什么??
系统究竟给数组分配多少内存空间??
注:我是用vc 2005 express edition
发表于 2006-12-26 11:20 | 显示全部楼层
我想问一下

printf("%s\n",a)

的结果
回复

使用道具 举报

 楼主| 发表于 2006-12-26 11:30 | 显示全部楼层
#include <stdio.h>
void main()
{
char a[2];
scanf ("%s",a);
printf ("%s\n",a);
}
我用这个代码运行四次,每次分别输如一至四个字符
前三次,输出结果与输入结果一样
第四次我输入四个字符1234
结果是

1234

runtime error R6009
not enough space for enviroment
回复

使用道具 举报

发表于 2006-12-26 11:49 | 显示全部楼层
只申请两个空间输入超过两个字符会造成溢出。。。

每输入一个字符串,都会自动在后面加上'\0'为结束符
也就是说你输入了两个字符,要有容纳三个字符的空间来放
如前面一些帖子讨论的
当你使用了没有向系统申请的空间时,系统就存在风险
可能你占用了其它程序的空间
但也可能刚好使用了没有被用的空间
回复

使用道具 举报

发表于 2006-12-26 11:50 | 显示全部楼层
原帖由 iptton 于 2006-12-26 11:49 发表
只申请两个空间输入超过两个字符会造成溢出。。。

每输入一个字符串,都会自动在后面加上'\0'为结束符
也就是说你输入了两个字符,要有容纳三个字符的空间来放
如前面一些帖子讨论的
当你使用了没有向系统 ...


问题是长度为5时, 可以输入7个, 楼主说....
回复

使用道具 举报

 楼主| 发表于 2006-12-26 12:05 | 显示全部楼层
是啊
我试过,长度为5时,直到输入8个数才报错
如果把空字符算进去的话,如果我定义长度为2的字符数组就可以得到4个字节的空间,长度为5时就可以得到8个字节的空间,这也说明了其他为被配置的内存是不可用的,这与另外一张帖的内容好像由矛盾。能解释一下吗?
回复

使用道具 举报

 楼主| 发表于 2006-12-26 12:08 | 显示全部楼层
我把这个问题发到百度去问了,得到一下答案,看不大懂
当然是2个。不过实际上比较复杂。
原则上来说,对象的定义语句会对该对象分配这个对象所需的存储。然而对数组来说,主要有两个问题:
第一,C语言中对数组的支持相当不完整,它只不过是对一组连续存储的对象进行访问的语法简化。就是说,如下语法形式是等价的。
arr[j] == j[arr] == *(arr+j);
数组名就是数组首地址,而不会进行任何下标访问限制,并且作为函数参数传递的必然是这个地址。
scanf函数获得了这个地址,并试图向这个地址上写入数据,它并不知道这个地址上的数组到底有多大,你输入多少都会被写进去,用%s所写的字符串还要加上一个'\0'字符。
所以你写3个字符实际上是4个字符,而7个字符实际上是8个字符。
第二,自动变量是在运行栈上分配空间的,如果你向超过数组下标范围的地方写入数据,几乎可以肯定会造成在该运行栈上分配的其他自动变量的改动甚至是破坏整个运行栈结构。数据输入多了自然会造成程序崩溃。这是非常常见的C语言“缓冲区溢出”安全问题的主要原理。
第三,内存中分配变量有时不是紧挨着放置的,这其中有关于“对齐”的要求。
所谓对齐问题,简单的说就是按2的指数倍的内存位置进行放置。由于CPU在读写内存时要通过数据总线,而数据总线是4字节或8字节等,而每个读写指令肯定最自然的方式就是一次读写4个字节或8个字节。为了提高CPU访问内存的效率,防止对一个变量需要进行两次读取或写入才能完成访问,通常在分配其内存位置时都把它放在按2、4或8个字节对齐的位置。这种情况下,
char a[2];
会在运行栈上分配2个字节,而按32位机器的对其要求还有2个字节的填充空余,总共是4个字节,而
char a[5];
的填充就会是3个字节。由此可以推断你可以输入3个获7个数字是因为额外的字符和'\0'被放在这些填充位置上。再多就会破坏栈结构了。


----------编辑了下,字体好看些-----Powerwind-------

[ 本帖最后由 powerwind 于 2006-12-26 14:45 编辑 ]
回复

使用道具 举报

发表于 2006-12-26 13:39 | 显示全部楼层
是了。。。

就是这个内存对齐。。。
怎么忘了。。。
回复

使用道具 举报

发表于 2006-12-26 13:46 | 显示全部楼层
对“内存对齐”理解还不够全面,说一说我所知道的吧:



(对齐一般都是4的倍数)
比如:申请两个char,编译器会为你申请4个

为什么要对齐?因为程序的执行指针移动时,以4为单位移动时明显比每次都要找找,看哪里是下一个指令的开头效率要高
回复

使用道具 举报

 楼主| 发表于 2006-12-26 13:54 | 显示全部楼层
那么还是老问题,没有身请过的空间可不可以用?
这里看起来好像不可以用
但我在另外一张帖中看到
“无论分不分配,释不释放,任意内存都可以用
但如果没用malloc等内存管理函数来分配内存的话
就会造成读取时有奇怪的代码或写内存时会覆盖其他正在运行的程序
这样就是所谓的bug了”

“指针只是绝对的...你往哪指都可以...所谓不可用是因为, 超过你指针定义范围的地址可能为别变量代码程序的所使用, 如果你对这些地址进行操作, 将有可能对你的程序造成影响. 指针的使用不要超过自己所定义的范围,

例如, 在内存中开辟的连续空间int allocbuf[ALLOCSIZE], 而紧接着在int allocbuf[ALLOCSIZE]后面的地址是循环控制变量int i的地址. 这样, 当你指针来到从allocbuf+ALLOCSIZE去到i这里对i进行操作的话, 如果你不幸陷入了由这个i所控制的循环, 那么, 你的程序就很有可能会乱套. 这样, 就会出现所谓的Bug.”
好像是在说没有申请过的内存空间也可以用,只要不要影响到有用的数据
回复

使用道具 举报

发表于 2006-12-26 14:20 | 显示全部楼层
打个比方:

某些行为不是不能做,比如,抢劫,你可以去做,但你从小的教育就告诉你,不要这样做。。。
回复

使用道具 举报

发表于 2006-12-26 15:24 | 显示全部楼层
对变量, 指针的控制, 使用, 不要超出自己定义的范围.
回复

使用道具 举报

发表于 2006-12-26 15:43 | 显示全部楼层
我对楼主这个问题的理解是:
关键在于C语言对数组下标不做检查,使用scanf的时候,并没有取得实际
数组的大小,所以就有可能写到内存的其它地方去了。
至于为什么会出现5则写7出错,楼主不妨自己定义一个数组,然后把各element
的地址pr出来,看看他们的差值,你就会发现,其实这些地址并非都是紧挨的。
回复

使用道具 举报

发表于 2006-12-26 15:55 | 显示全部楼层
LS

C标准没有说明字符数组要在连续的内存空间里保存,不过很多时候是连续的。。。
回复

使用道具 举报

发表于 2006-12-26 16:04 | 显示全部楼层
C标准是没有这么说,但是在ADT数组及C教程里面都有提到一点,
那就是:数组是存储同类型数据的一片连续内存区域。记得在一本
机械工业出版社出版的外国数据结构教材中也提到这个问题,并指
出:把数组定义成为一个连续的内存区域并不准确,因为这样只片
面强调了数组的实现问题。
回复

使用道具 举报

发表于 2006-12-26 16:09 | 显示全部楼层
请问楼上两位,我想知道,究竟C语言里的数组的内存空间是不是连续啊??
回复

使用道具 举报

发表于 2006-12-26 16:23 | 显示全部楼层
原帖由 powerwind 于 2006-12-26 16:09 发表
请问楼上两位,我想知道,究竟C语言里的数组的内存空间是不是连续啊??

自己写个程序, 逐个print每个元素的地址, 看看是不是连续的就知道了.
回复

使用道具 举报

发表于 2006-12-26 16:29 | 显示全部楼层
原帖由 黯然销魂 于 2006-12-26 16:23 发表

自己写个程序, 逐个print每个元素的地址, 看看是不是连续的就知道了.



先回帖,然后再测试。

我觉得是连续的,而且一定是连续的。

当然,一个简单的测试并不能说明问题,除非用穷举法去测N次。
回复

使用道具 举报

发表于 2006-12-26 16:43 | 显示全部楼层
我记错了。。。

我看到的资料是下面这种情况:
char a[10];
char b[10];

a 与 b两块内存是否相邻没被定义....
而非数组元素。。。
回复

使用道具 举报

发表于 2006-12-26 16:47 | 显示全部楼层
原帖由 iptton 于 2006-12-26 16:43 发表
我记错了。。。

我看到的资料是下面这种情况:
char a;
char b;

a 与 b两块内存是否相邻没被定义....
而非数组元素。。。


:funk:

差点吓了一跳,原来IP记错了。
原谅你一次 016
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入后院

本版积分规则

QQ|Archiver|手机版|小黑屋|广告业务Q|工大后院 ( 粤ICP备10013660号 )

GMT+8, 2025-8-30 18:04

Powered by Discuz! X3.5

Copyright © 2001-2024 Tencent Cloud.

快速回复 返回顶部 返回列表