当前位置:首页 » 编程语言 » c语言越界访问
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

c语言越界访问

发布时间: 2022-04-03 02:25:34

1. c语言程序中,SIGSEGV越界访问内存的错误

if(pf=NULL)应该是if(pf==NULL)
否则你直接给他赋值NULL了,访问非法指针就会段错误。

2. c语言数组越界

因为,内存的分配是从高地址到低地址进行的,但一个数组内部元素又是从低到高进行的,所以:
语句序列
int i=0; int a[]={10,30};
的内存分配情况是(地址:低--高):
a[0] a[1] i
而语句序列
int a[]={10,30}; int i=0;
的内存分配情况是(地址:低--高):
i a[0] a[1]
所以,前者越界影响到了i,而后者越界没有影响到i。

3. c语言 数组越界

c语言编译器是不会做数组越界检查的。
所以我们在写c程序的时候一定要注意是否会发生越界

4. 在C语言中能否越界访问数组元素 为什么拜托了各位 谢谢

可以 但是任何时候都不要越界访问,会出问题的,就像你上女厕所.... 恶意代码一般都这么干,(*^__^*) 嘻嘻……

5. C语言指针访问越界

与编译器无关,只与内存管理机制有关,是操作系统级别的问题,堆栈的读取方式只是数据结构上的不同,在机器层面,依然是单纯的内存读写操作;
数组越界访问的危险性不好评估,但确实是最严重的危险之一;
结果基本上会100%崩溃,但是崩溃的原因很可能不一样,就算是同一段越界代码跑几遍,原因也可能是不一样的;
指针越界问题是不限于数组访问的,所以全面点的解释如下:
c语言的编译时,会跟你的代码需要,首先申请一块栈空间和堆空间,栈的优先级较高,一般时存放程序运行所必须的数据和变量,内存上是连续的,堆空间是程序运行时动态申请的空间,内存上一般是不连续的,这里说的栈与你自己创建的栈不是一个栈,不过数据结构是一样的,只不过你自己创建的栈是靠你自己写的代码动态创建的,所以其实是在你程序的堆空间中的;
下面关键问题来了,
以上所有内存空间就是你的程序在跑起来之后,向操作系统申请的所有空间,换句话说,这些内存以外的数据,都是不属于你这个程序的资源,当你使用指针操作的时候,如果你的指针越界了,那么接下来你对这个指针的操作就是非法的了,如果这段空间依然是你程序内部的资源,通常会导致你程序自己崩溃,如果是程序之外的资源一般就更糟糕了,甚至会导致更高级别的崩溃,原因很多:
比如你篡改了不属于你的数据,导致该数据所属对象的逻辑混乱;
比如越界区域存在保护,内存空间是有读写权限控制的,如果接下来你对只读的空间进行写操作,也会导致崩溃,windows下你会看到非常亲切的蓝屏;
等等...
这也是内存溢出攻击的基本思想;

6. C语言的越界问题

  1. C语言是不检查下表越界的,因此越界出来结果太正常了,你和书上一样是因为你从-1到6到赋值了,编译器的实现就是安数组首位坐标+-指针而已。如果你输出-3呢,应该就是随机了。

  2. 为什么arr【5】和arr【6】应该一样?

  3. 给你看看我用VC++6.0在Win32位上运行结果:


7. 为什么C语言检查数组访问越界会这么难

C语言中数组和内存管理,是安全性和性能之间矛盾关系的重要部分。

我曾提到要讨论性能和安全性之间的矛盾。这个矛盾的一个重要部分就是因为C语言中数组和内存管理的本质特征导致的。

理论上,数组是一个简单的数据结构:当你需要访问其中的一个元素时,只需要给出该元素的索引位置,就能对该元素进行读或者写操作。这句话中也隐含了
一个问题,那就是你需要访问一个元素时,都需要提供一个索引位置。使用索引位置来找元素通常是一个代价很高的计算,尤其是当元素的大小不是2的整数次幂
时: 在诸如表达式++a[i], 在地址递增的过程中,其计算地址的代价可以轻松超过5倍于a[i]的地址的代价。

在至少50年的时间里,编译器开发人员一直在努力让访问数组元素变得更快。其中很大一部分的工作都围绕想下面这种循环进行:
for (size_t i = 0; i < n; ++i)
c[i] = a[i] + b[i];

这段代码在每次循环迭代中,都需要通过计算将三个索引地址转换成对应的内存位置中,这种计算也带入了一些开销。 许多编译器都通过将循环重写为如下代码的方式来实现高效计算。在这段代码中,我们假设Pointer类型是可以指向a,b,c三个数组中某个元素的指针。
Pointer ap = &a[0], bp = &b[0], cp = &c[0], aend = ap + n;
while (ap < aend) {
*cp++ = *ap++ + *bp++;

}

这段转换后的代码将三个数组索引计算操作转换成了三个地址加操作,这样加速显着。不过,这个简单的转换操作看起来容易,做起来却很复杂,
因为编译器需要能够确认在这个for循环体中没有对i值本身的修改。 上面的例子可以很直观的看到i不会被改变,不过在实际的代码中,往往要困难很多。

C语言与在它之前的编程语言相比,一个非常重要的不同就是C能提供给程序员一些直接优化代码的机会,而不是简单的依赖编译器去做优化。C语言通过将数组和指针的概念统一化,使得程序员可以自己做大部分的数组索引计算,而在C语言之前,这些工作只能通过编译器去做。

用手动计算索引取代自动计算是一种进步,这个听起来有点怪怪的。但是在实际编程中,可能很多程序员都宁愿手工优化代码,而不是依赖编译器自动优化,因为无法确定编译器到底对代码做了什么。这也可能是吸引C程序员使用指针而不是索引来访问数组元素的原因之一。

除了在很多情况下会更快外,指针相比数组还有另外一个很大的优势:可以只用指向数组中特定元素的一个指针来识别数组中的元素。比如,假设我们想写一

个函数来对数组中某个区域内的元素做操作。如果没有指针,我们需要三个参数来确定这个区域:数组名称,区域开始索引,区域结束索引。而如果使用指针的话,
只要两个参数就足够了。

此外,不管是动态分配的内存,还是其他内存地址,都可以统一使用指针。例如,在malloc库函数返回一个指向动态内存的指针后,我们可以用这个指

针创建任何我们需要的数据结构。一旦我们在这块动态分配的内存中创建了这些数据结构之后,我们就能使用指向这些数据结构某个部分的指针来让其他函数可以直
接访问这一部分数据。 相应的,这些函数也无需知道他们将使用的内存到底是什么性质的。

使用指针是方便了很多,但是也要付出代价的。相比于使用索引变量引用数组元素的表示形式,使用指针的表示形式将会引入三种潜在危害。

第一,因为指向数组元素的指针和数组本身是完全独立的。
因此,在数组不存在或者内存释放之后,指针仍然有可能存在。比如,我们将数组元素的地址
&a[0]保存到指针ap中,我们同时也引入了在a不存在的时候,使用*ap的风险。这种风险在完全使用数组加索引的形式中是不存在的,因为一旦
数组a消失了,我们也无法引用他的元素。

第二,指针运算的可行性。
如果我们使用一对指针指向一个数组区间的两端,那么我们就一定能找到其中间元素的位置,因为可以直接使用数学运算得到。但
是这种指针的数学运算也同时引入了很多制造不可用地址的可能性,而且这种通过数学运算得到的不可用地址, 相比简单的一些针对整数的数学运算来说,
更难检测到。

最后,使用指针来表示范围,不仅仅需要指针本身存在且可用,还需要指针指向的内存是可用的内存
。上面代码中的aend变量就是一个典型例子。我们创
建了一个aend变量,并用它指向循环的上界。但是如果我们想试图对*aend取值,结果将是未定义的。这类指针被称为off-the-end指针。这类
指针的存在,也让验证C语言是否存在越界错误变得非常困难。

8. c语言越界是什么意思

书中所说的越界是指如果z很大,大到int类型存不下(超过2^32-1), 就会发生越界溢出,(即内存不够存放z)此时z成为负数,导致计算出错。而模的乘积又等于乘积的模,所以每次乘法的结果都会小于1000,既满足了结果正确又不会发生int存不下

9. c语言越界问题

怎么没有越界,你定义int a[9]这样数组a只包含9个元素,而你循环却是10次,这样最后一次是越界的。注意定义的时候,指定的是数组大小,而不是数组的下标上限。

10. C语言越界访问问题

H指针应始终指向头部,不应被修改,增减变量p指针用于操作
int main()
{
pLinkList H,p;
H = Create_LinkList();
p = H;
for (int i = 0; i < 3; i++)
{
pLinkList T;
T = (pLinkList)malloc(sizeof(LinkList));
T->data = i;
p->next = T;
p = p->next;
}
reverse_LinkList(H);
return 0;
}