c++越界为啥不报错?报错-问答-阿里云开发者社区-阿里云

开发者社区> 问答> 正文

c++越界为啥不报错?报错

爱吃鱼的程序员 2020-06-12 14:05:10 217

#include <stdio.h>
void fun(int *n)
{
        n[111] = 0;
}

int main()
{
        int *a = new int[2];
        fun(a);
        printf("aaa\n");
        return 0;
}

//这样不报错


#include <stdio.h>
void fun(int *n)
{
        n[111] = 0;
}

int main()
{
        int a[2];
        fun(a);
        printf("aaa\n");
        return 0;
}
//这样也不报错,

为什么?linux环境,g++编译器。

运行结果

[root@f2 ~]# ./a.out
aaa

[root@f2 ~]# g++ -v
使用内建 specs。
COLLECT_GCC=/usr/bin/g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/i686-redhat-linux/4.5.1/lto-wrapper
目标:i686-redhat-linux
配置为:../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,lto --enable-plugin --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch=i686 --build=i686-redhat-linux
线程模型:posix
gcc 版本 4.5.1 20100924 (Red Hat 4.5.1-4) (GCC)


Java 编译器 Linux C语言 C++
分享到
取消 提交回答
全部回答(1)
  • 爱吃鱼的程序员
    2020-06-12 14:05:26
    printf("aaa\n");这不是在打印a字符吗?,而且,只有段越界才会引起进程的段错误信号,你访问的地址仍然在进程的合法空间范围内,当然空指针这类地址基本不合法。回复 @xxdd:看看gdb进程的infoprocmappings或者去cat/proc/$pid/maps,崩溃指的是程序read,write,execute了一个virtualaddress,这个address不在操作系统给其进程分配的虚拟地址段之内,称其为段错误回复 @xxdd:我的理解是,只有当指针指向只读区域时,你更改才会报错。想想八门神器,一个程序都可以改别的程序里的内存值,这不就很好的解释了你的疑问了吗?您好,我指的是fun()函数里面的n[111],已经越界了,为什么程序可以正常运行,而不是崩溃?

    因为根本报不了错。

    编译器,编译器怎么判断数组下标的范围?没有任何一种万无一失的方法,最多用静态检查工具,处理掉一些错误。

    运行期,程序持有的信息更少,数组元素的访问就是数组其实元素的地址+偏移量计算出地址。这个时候就是对地址的直接访问,运行期是不会记录类型信息的,根本不知道这个数组设定的大小。这个时候程序是否崩溃就要看人品了,只有操作系统发现你访问了不该访问的内存区域,程序才会崩溃。

    谢谢,应该是这样的。c++本来就不会检查边界的,所以遇到数组参数的时候,一般会加一个长度,而java是基于这个问题做了优化编译器不检查,但是为什么运行的时候,也不报错? 数组下标越界是undefinedbehavior. 结果是未定义的知道什么意思吧
    两种写法程序都可以正常运行,为啥?明明操作了非法的地址。越界是 undefinedbehavior。所谓 undefinedbehavior就是怎样都行,可以崩溃、可以什么都不干。你如果非要问为什么C++这样规定,那是因为检查这些错误代价实在太大了。您好,我想知道的是,为什么这个程序可以正常运行?数组已经指向了非法的地址。数组传递变成指针,他允许你进行修改,改的对不对成了问题

    你把堆改成栈再试试

    回复 @xxdd:堆所分配的是系统中剩余的可用内存。new出来的内存指针所指向的地址,在你指定的大小之后,仍然可能有很大一块可用内存,不报错是有可能的。inta[2];fun(a);这个就是栈吧?这应该和系统内存分配有关系吧,报错应该是系统认为地址非法给你报错,系统肯定是认为你这个地址不非法呗,所以不报错newint[2]是从堆上分配的,数组越界是未定义行为,可能是没有进程默认堆大,没有非法访问,所以没有coredump掉。你越界大一些看看好像是这个原因,那栈上那个为什么也不报错?

    楼主听说过“缓冲区溢出”的说法吧

    我个人理解一个指针本来就能在自己的地盘里指来指去,想要指到哪里是程序员的自由,编译器不做这方面的任何限制与检查。

    Linux上检查缓冲区溢出跟内存泄露可以试试valgrind还有电网electric-fence


    0 0
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

推荐文章
相似问题
推荐课程