精华内容
下载资源
问答
  • 数组越界

    2021-02-22 22:10:29
    刚学数组那会儿,经常会看到数组越界四个字,当时我也是一脸懵逼 ,现在终于有时间来抓一下这条虫了。 定义:所谓数组越界,就是指数组下标变量的取值超过了初始定义时的大小,导致对数组元素的访问出现在数组的范围...

    平时打题的时候,有时找一个bug找半天,就很难顶。

    刚学数组那会儿,经常会看到数组越界四个字,当时我也是一脸懵逼 ,现在终于有时间来抓一下这条虫了。

    定义:所谓数组越界,就是指数组下标变量的取值超过了初始定义时的大小,导致对数组元素的访问出现在数组的范围之外。

    数组下标的取值范围只能预先推断一个值来确定数组的维数,作为秃头程序猿的我们,就得学会检验数组的边界啦。

    一般情况下,数组的越界包括两种:数组下标取值越界与指向数组的指针的指向范围越界。

    第一种:数组下标取值越界
    意思就是访问数组的时候,下标的取值不在我们已经定义好的数组的取值范围内,而访问的是无法获取的内存地址。
    例如,对于数组 int a[3],它的下标取值范围是[0,2](即a[0]、a[1] 与 a[2])。如果我们的取值不在这个范围内(如 a[3]),就会发生越界错误。贴个代码看看:

    int a[3];
    for(int i=0;i<4;i++)
        a[i]=i;
    for(int i=0;i<4;i++)
    	cout<<a[i]; 
    

    以上代码是错误的,因为我们定义数组长度为3,那么数组就为a[0]、a[1]、a[2],然而在for循环中i的循环条件为i=0且i<4,显然可以有0、1、2、3这四种取值,大于数组的取值范围,即数组越界了。

    怎么修改?
    把 i<4 改成 i<3 即可。

    第二种:指向数组的指针的指向范围越界
    一般在定义数组时,会返回一个指向第一个变量的头指针,对这个指针进行加减运算可以向前或向后移动这个指针,进而访问数组中所有的变量。但在移动指针时,如果不注意移动的次数和位置,会使指针指向数组以外的位置,导致数组越界。还是贴个代码就明白了:

    int *p;
    int a[5];
    p=a;			//数组a的头指针赋值给指针p
    for(int i=0;i<10;i++)
    {
    	*p=i+10;  
        p++;       //指向下一变量 
    }
    

    以上为错误代码,for 循环会使指针 p 向后移动 10 次,每次都向指针指向的单元赋值。但是,这里数组 a 的下标取值范围是 [0,4](即 a[0]、a[1]、a[2]、a[3] 与 a[4])。因此,后 5 次的操作会对未知的内存区域赋值,导致系统发生错误。

    正确的操作应该是指针移动的次数与数组中的变量个数相同

    怎么修改?
    把 i<10 改成 i<5 即可。

    以上是本蒟蒻一点小总结,希望对各位兄台有帮助(溜

    展开全文
  • 昨天晚上,我正在给之前获奖的同学发奖品,正在进行中的时候,看到黄兄推送了一篇文章,里面讲到数组越界会导致无限循环。关于抽奖看这篇文章《Linux进程管理数据结构》,以后也会不定期抽奖,今年多赚点钱,过年的...

    昨天晚上,我正在给之前获奖的同学发奖品,正在进行中的时候,看到黄兄推送了一篇文章,里面讲到数组越界会导致无限循环。

    关于抽奖看这篇文章《Linux进程管理数据结构》,以后也会不定期抽奖,今年多赚点钱,过年的时候,希望给大家抽一个大奖,喜欢的读者使劲给转发点赞,关注,未来是你们的,大奖也是你们的,感谢支持,不喜欢的请轻拍。过年抽奖我还是很期待的,每年公司的年会抽奖的时候,我总是能小中一把,有一年我还中了个一等奖,不知道大家对一等奖什么概念,中一等奖的概率非常低,集人品运气于一身的,我当时酝酿了全宇宙的力量,不说了,发功的时候真的非常累。

    51d10db4cbaf7625d7c53fbe148c0514.png

    就是这个截图,我看了下,感觉有点意思,赶紧就自己敲下代码看看是怎么回事,可惜的是,我怎么也没看到出现无限循环啊。

    代码如下:

    #include "stdio.h"
    
    int main()
    {
    	int a[10] , i;
    	
    	for(i = 1;i<= 10;i++){
    		a[i] = 0;
    		printf("%d %dn",i,a[i]);
    	}	
    	
    	return 0;
    }
    

    我先是在 dev c++ 上面试了下,结果如下

    66437b79c02ece08603ba102ef57da84.png

    我这时候想,黄兄是不是忽悠我了,我要去成都叫他请我吃饭,然后我就给他评论

    评论如下

    2861d2411a20832b93105ac75878f4eb.png

    竟然还有人给我的评论点赞了,啊啊啊啊啊啊~

    不死心,赶紧又到Linux 下用 gcc编译 结果如下

    dc9e8936e0c60a5ffeba42ccea9ef20b.png

    还是没有无线循环,我要死了,要是在群里面讨论这个,我要是说不出来会不会丢脸一个晚上。

    赶紧用大招,看看i的地址和a[i] 的地址

    0fb008d75f46d007bfeda89503a7c12c.png

    看这个图,i等于 10的时候, &a[10] 的地址和 i的地址还是独立的,虽然 a[10]已经超过了 数组的范围,但是并没有对i造成任何影响。

    然后,我脑子一响,突然顿悟发现这个代码的问题所在了,这个数组越界没有越过去,要是越过去了,侵犯了i的领土「内存地址」了肯定就死循环了。

    代码修改一下

    #include "stdio.h"
    
    int main()
    {
    	int a[10] , i;
    	
    	for(i = 1;i<= 12;i++){
    		a[i] = 0;
    		printf("%d %dn",i,a[i]);
    	}	
    	
    	return 0;
    }
    

    045099b8550b097071dc97f3bafdd7e9.png

    看看内存分布

    3adfb99dc2205b21926a191d3a9bb0c7.png

    上图中 i = 10的时候,&a[10] 还没有越界到 &i「i的地址」,等下一次循环 i = 11的时候,那 &a[11] 就等于 &i 了,a[11] = 0,其实也就是 i= 0,死循环也就是这样来了。

    从这个例子我们可以明白一点,为什么数组不能越界操作了没?如果真的是项目里面的代码,要是编译器也不给出提示,那么你即将构造一个非常难排查的bug出来。

    如果对上面的地址还是不感冒,可以看看这个图片

    4266ebbee0dde7ba462314db1aa24929.png

    a我们定义的是10的大小,但是我们使用 a[10],这个是越界操作,越界操作编译器不会提示编译出错,但是这样操作就可能侵犯到i的地址,实际上把i给赋值了,所以会导致i=0,一直跳不出for循环。

    我们正常一个数组遍历会这样写

    #include "stdio.h"
    
    int main()
    {
    	int i;
    	int a[10];
    	
    	for(i = 0;i < sizeof(a)/sizeof(a[0]);i++){
    		a[i] = 0;
    		printf("%d %d %p %pn",i,a[i],&i,&a[i]);
    	}	
    	
    	return 0;
    }
    

    编译器就好像法律,约束着人们的行为,但是有些法律没有涉及到的,就很容易被打擦边球。

    最后用这个代码看看内存的增长「一个读者奉献的」

    #include <stdio.h>
    
    int main(void)
    {
    	#pragma pack (4)
    	int j;
    	int a[10];
    	int i;
    	#pragma pack()
    
    	printf("a=%p &a[10]=%p &i=%p &a[-1]=%p &a[-2]=%p &j=%prn",a, &a[10],&i,&a[-1],&a[-2],&j);
    	
    	return 0;
    }
    

    1e3ea221c18f94a094f638f7862cac6e.png
    展开全文
  • 浅析C语言编程中的数组越界问题因为C语言不检查数组越界,而数组又是我们经常用的数据结构之一,所以程序中经常会遇到数组越界的情况,并且后果轻者读写数据不对,重者程序crash。下面我们来分析一下数组越界的情况...

    浅析C语言编程中的数组越界问题

    因为C语言不检查数组越界,而数组又是我们经常用的数据结构之一,所以程序中经常会遇到数组越界的情况,并且后果轻者读写数据不对,重者程序crash。下面我们来分析一下数组越界的情况:

    1) 堆中的数组越界

    因为堆是我们自己分配的,如果越界,那么会把堆中其他空间的数据给写掉,或读取了其他空间的数据,这样就会导致其他变量的数据变得不对,如果是一个指针的话,那么有可能会引起crash

    2) 栈中的数组越界

    因为栈是向下增长的,在进入一个函数之前,会先把参数和下一步要执行的指令地址(通过call实现)压栈,在函数的入口会把ebp压栈,并把esp赋值给ebp,在函数返回的时候,将ebp值赋给esp,pop先前栈内的上级函数栈的基地址给ebp,恢复原栈基址,然后把调用函数之前的压入栈的指令地址pop出来(通过ret实现)。

    栈是由高往低增长的,而数组的存储是由低位往高位存的 ,如果越界的话,会把当前函数的ebp和下一跳的指令地址覆盖掉,如果覆盖了当前函数的ebp,那么在恢复的时候esp就不能指向正确的地方,从而导致未可知的情况,如果下一跳的地址也被覆盖掉,那么肯定会导致crash。

    -------------------------

    压入的参数和函数指针

    -------------------------

    aa[4]

    aa[3]

    合法的数组空间   aa[2]

    aa[1]

    aa[0]

    -------------------------

    ###sta.c###

    #include

    void f(int ai)

    {

    int aa[5]={1,2,3};

    int i = 1;

    for (i=0;i<10;i++)

    aa[i]=i;

    printf("f()/n");

    }

    void main()

    {

    f(3);

    printf("ok/n");

    }

    ###sta.s###

    .file "sta.c" ;说明汇编的源程序

    .section .rodata ;说明以下是只读数据区

    .LC0:

    .string "f()" ;"f()" 的类型是string,地址为LC0

    .text ;代码段开始

    .globl f ;f为全局可访问

    .type f, @function ; f是函数

    f:

    pushl %ebp

    movl %esp, %ebp

    subl $40, %esp

    movl $0, -24(%ebp)

    movl $0, -20(%ebp)

    movl $0, -16(%ebp)

    movl $0, -12(%ebp)

    movl $0, -8(%ebp)

    movl $1, -24(%ebp)

    movl $2, -20(%ebp)

    movl $3, -16(%ebp)

    movl $1, -4(%ebp)

    movl $0, -4(%ebp)

    jmp .L2

    .L3:

    movl -4(%ebp), %edx

    movl -4(%ebp), %eax

    movl %eax, -24(%ebp,%edx,4)

    addl $1, -4(%ebp)

    .L2:

    cmpl $9, -4(%ebp)

    jle .L3

    movl $.LC0, (%esp)

    call puts

    leave

    ret

    .size f, .-f ;用以计算函数f的大小

    .section .rodata

    .LC1:

    .string "ok"

    .text

    .globl main

    .type main, @function

    main:

    leal 4(%esp), %ecx

    andl $-16, %esp

    pushl -4(%ecx)

    pushl %ebp

    movl %esp, %ebp

    pushl %ecx

    subl $4, %esp

    movl $3, (%esp)

    call f

    movl $.LC1, (%esp)

    call puts

    addl $4, %esp

    popl %ecx

    popl %ebp

    leal -4(%ecx), %esp

    ret

    .size main, .-main

    .ident "GCC: (GNU) 4.1.2 20070115 (SUSE Linux)" ;说明是用什么工具编译的

    .section .note.GNU-stack,"",@progbits

    从main函数开始压入f函数的参数开始,堆栈的调用情况如下

    图1  压入参数

    图二  通过call 命令压入下一跳地址 IP

    图三  函数f 通过pushl   %ebp 把 ebp保存起来

    图四  函数 f 通过movl    %esp, %ebp让ebp指向esp,这样esp就可以进行修改,在函数返回的时候用ebp的值对esp进行恢复

    图五  函数 f 通过subl    $40, %esp 给函数的局部变量预留空间

    图六  int数组 aa[5]占用了20个字节的空间,然后 int i占用了4个字节的空间(紧邻着之前压入栈的%ebp)

    故,如果aa[5]进行赋值,则会把 i 的值覆盖掉,

    如果对aa[6]进行赋值,则会把 栈中的 %ebp 覆盖掉,那么在函数 f 返回的时候则不能对ebp进行恢复,即main函数的ebp变成了我们覆盖掉的值,程序不知道会发生什么事情,但因为我们的程序接下来没有调用栈中的内容,故还是可以运行的。

    如果对aa[7]进行赋值,则会把栈中的 %IP 覆盖掉,在函数 f 返回的时候就不能正确地找到下一跳的地址,会crash;相关阅读:

    jQuery实现的在线答题功能

    php猜单词游戏

    高效的jquery数字滚动特效

    Android应用程序中读写txt文本文件的基本方法讲解

    Java Web开发之MD5加密用法分析

    win7系统怎么修改窗口任务栏颜色?win7修改窗口任务栏颜色的两种方法

    php利用curl获取远程图片实现方法

    固定宽高且DIV绝对居中实现思路及示例

    原生javascript实现图片按钮切换

    javascript向后台传送相同属性的参数即数组参数

    C语言中字符和字符串处理(ANSI字符和Unicode字符)

    Android在不使用数据库的情况下存储数据的方法

    Oracle SQL语句实现数字四舍五入取整

    spreadsheetgear插件屏蔽鼠标右键的方法

    展开全文
  • 在iOS开发中有时会遇到数组越界的问题,从而导致程序崩溃。为了防止程序崩溃,我们就要对数组越界进行处理。通过上网查资料,发现可以通过为数组写一个分类来解决此问题。基本思路:为NSArray写一个防止数组越界的...

    在iOS开发中有时会遇到数组越界的问题,从而导致程序崩溃。为了防止程序崩溃,我们就要对数组越界进行处理。通过上网查资料,发现可以通过为数组写一个分类来解决此问题。

    基本思路:为NSArray写一个防止数组越界的分类。分类中利用runtime将系统中NSArray的对象方法objectAtIndex:替换,然后对objectAtIndex:传递过来的下标进行判断,如果发生数组越界就返回nil,如果没有发生越界,就继续调用系统的objectAtIndex:方法。

    代码:

    .h文件:

    #import

    #import

    @interface NSArray (beyond)

    @end

    .m文件:

    #import "NSArray+beyond.h"

    @implementation NSArray (beyond)

    + (void)load{

    [superload];

    //  替换不可变数组中的方法

    Method oldObjectAtIndex =class_getInstanceMethod(objc_getClass("__NSArrayI"),@selector(objectAtIndex:));

    Method newObjectAtIndex =class_getInstanceMethod(objc_getClass("__NSArrayI"),@selector(__nickyTsui__objectAtIndex:));

    method_exchangeImplementations(oldObjectAtIndex, newObjectAtIndex);

    //  替换可变数组中的方法

    Method oldMutableObjectAtIndex =class_getInstanceMethod(objc_getClass("__NSArrayM"),@selector(objectAtIndex:));

    Method newMutableObjectAtIndex = class_getInstanceMethod(objc_getClass("__NSArrayM"),@selector(mutableObjectAtIndex:));

    method_exchangeImplementations(oldMutableObjectAtIndex, newMutableObjectAtIndex);

    }

    - (id)__nickyTsui__objectAtIndex:(NSUInteger)index{

    if (index >self.count -1 || !self.count){

    @try {

    return [self__nickyTsui__objectAtIndex:index];

    } @catch (NSException *exception) {

    //__throwOutException  抛出异常

    NSLog(@"数组越界...");

    returnnil;

    } @finally {

    }

    }

    else{

    return [self__nickyTsui__objectAtIndex:index];

    }

    }

    - (id)mutableObjectAtIndex:(NSUInteger)index{

    if (index >self.count -1 || !self.count){

    @try {

    return [selfmutableObjectAtIndex:index];

    } @catch (NSException *exception) {

    //__throwOutException  抛出异常

    NSLog(@"数组越界...");

    returnnil;

    } @finally {

    }

    }

    else{

    return [selfmutableObjectAtIndex:index];

    }

    }

    展开全文
  • 关注、星标公众号,直达精彩内容ID:技术让梦想更伟大作者:李肖遥所谓的数组越界,简单地讲就是指数组下标变量的取值超过了初始定义时的大小,导致对数组元素的访问出现在数组的范围之外,这类错误...
  • 最近在网易云捕上看到一些数组越界导致的崩溃日志,所以决定数组的越界做一些处理。崩溃报错信息在项目的开发中,笔者一般遇到的问题就是,数组越界:-[__NSArrayMobjectAtIndex:]:index0beyondboundsforemptyarray...
  • 所谓的数组越界,就是假如你的下标总数现在为32个,然后你在下一秒又执行了一个方法要从50个数据里惊醒赋值啊 筛选之类的 而你此时数量为32 50的数据还没有请求到 往往会出现数组越界的崩溃信息 大概是这样的-[__...
  • 牛客网上做一道编程题,一直报出数组越界问题,但是我一直没看出来哪里越界了求助攻我的思路是 判断目标数是否在当前行范围中,若是,采用二分法咋找,若不是,跳到下一行public class Solution {public boolean ...
  • 题目:读入两个整数m,n,输出一个m行n列的矩阵,这个矩阵是1~mn这些自然数按照右、下、左、上螺旋填入的结果。...注释块的解释:下面两个for循环 在目的数组的外层再套-1 如果不在外层套上-1 则数组越界?...
  • 请检查是否存在数组越界非法访问等情况case通过率为90.00%请各位大牛帮忙看下,下面代码为什么会提示 “请检查是否存在数组越界非法访问等情况 case通过率为90.00%”。代码功能为算式计算,输入格式为:(OP P1 P2)...
  • 源自:4-3 滚动状态判断与处理数组越界异常 求解决!!!package com.example.imooc;import java.io.BufferedInputStream;import java.io.IOException;import java.io.InputStream;import java.net....
  • 题目:读入两个整数m,n,输出一个m行n列的矩阵,这个矩阵是1~mn这些自然数按照右、下、左、上螺旋填入的结果。...注释块的解释:下面两个for循环 在目的数组的外层再套-1 如果不在外层套上-1 则数组越界?...
  • 数组越界其实是很基本的问题,但是解决起来除了count的判断,还有每个调用的时候都要去判断一遍对于不明确的数据总会有崩溃的风险然而 每次调用都判断 那是太累了,runtime&category提供了一个比较简洁的解决...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,162
精华内容 4,864
关键字:

数组越界