当前位置:首页 » 文件传输 » 指针访问越界会出现什么返回值
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

指针访问越界会出现什么返回值

发布时间: 2022-11-27 12:07:07

‘壹’ c语言指针面试常见问题

c语言指针面试常见问题

指针的使用,一直是c语言面试题中必考的部分,因为指针本身使用的复杂性与普适性,所以考点非常多,而且也可以与其他知识相互结合,因此我们将会使用五篇专题的篇幅来介绍指针。

分析下面的程序,指出程序中的错误:

本题解析

没有正确为str分配内存空间,将会发生异常。问题出在将一个字符串复制进一个字符变量指针所指地址。虽然编译的时候没有报错,但是在运行过程中,因为越界访问了未被分配的内存,而导致段错误。

相关知识点

在处理与指针相关的问题时,首先需要搞明白的就是内存,因为指针操作的就是内存。

第一个,就是内存的分区。这也是经常会被考察的一个考点。

写出内存分为几大区域

对于这个问题,有几种不同的说法,有的说内存分为五大分区,有的说分为四大分区,我们先来看五大分区的说法:

认为内存分为五大分区的人,通常会这样划分:

1、BSS段( bss segment )

通常是指用来存放程序中未初始化的'全局变量和静态变量 (这里注意一个问题:一般的书上都会说全局变量和静态变量是会自动初始化的,那么哪来的未初始化的变量呢?变量的初始化可以分为显示初始化和隐式初始化,全局变量和静态变量如果程序员自己不初始化的话的确也会被初始化,那就是不管什么类型都初始化为0,这种没有显示初始化的就 是我们这里所说的未初始化。既然都是0那么就没必要把每个0都存储起来,从而节省磁盘空间,这是BSS的主要作用)的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。 BSS节不包含任何数据,只是简单的维护开始和结束的地址,即总大小。以便内存区能在运行时分配并被有效地清零。BSS节在应用程序的二进制映象文件中并不存在,即不占用 磁盘空间 而只在运行的时候占用内存空间 ,所以如果全局变量和静态变量未初始化那么其可执行文件要小很多。

2、数据段(data segment)

通常是指用来存放程序中已经初始化的全局变量和静态变量的一块内存区域。数据段属于静态内存分配,可以分为只读数据段和读写数据段。字符串常量等,但一般都是放在只读数据段中。

3、代码段(code segment/text segment)

通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等,但一般都是放在只读数据段中 。

4、堆(heap)

堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或 缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张); 当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

5、栈 (stack)

栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括号“{}” 中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变 量)。除此以外, 在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值 也会被存放回栈中。由于栈的先进先出特点,所以 栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

而四大分区的说法,则这么认为:

1、堆区:

由程序员手动申请,手动释放,若不手动释放,程序结束后由系统回收,生命周期是整个程序运行期间。使用malloc或者new进行堆的申请,堆的总大小为机器的虚拟内存的大小。

说明:new操作符本质上是使用了malloc进行内存的申请,new和malloc的区别如下:

(1)malloc是C语言中的函数,而new是C++中的操作符。

(2)malloc申请之后返回的类型是void*,而new返回的指针带有类型。

(3)malloc只负责内存的分配而不会调用类的构造函数,而new不仅会分配内存,而且会自动调用类的构造函数。

2、栈区:

由系统进行内存的管理。主要存放函数的参数以及局部变量。在函数完成执行,系统自行释放栈区内存,不需要用户管理。整个程序的栈区的大小可以在编译器中由用户自行设定,VS中默认的栈区大小为1M,可通过VS手动更改栈的大小。64bits的Linux默认栈大小为10MB,可通过ulimit -s临时修改。

3、静态存储区:

静态存储区内的变量在程序编译阶段已经分配好内存空间并初始化。这块内存在程序的整个运行期间都存在,它主要存放静态变量、全局变量和常量。

注意:

(1)这里不区分初始化和未初始化的数据区,是因为静态存储区内的变量若不显示初始化,则编译器会自动以默认的方式进行初始化,即静态存储区内不存在未初始化的变量。

(2)静态存储区内的常量分为常变量和字符串常量,一经初始化,不可修改。静态存储内的常变量是全局变量,与局部常变量不同,区别在于局部常变量存放于栈,实际可间接通过指针或者引用进行修改,而全局常变量存放于静态常量区则不可以间接修改。

(3)字符串常量存储在静态存储区的常量区,字符串常量的名称即为它本身,属于常变量。

(4)数据区的具体划分,有利于我们对于变量类型的理解。不同类型的变量存放的区域不同。后面将以实例代码说明这四种数据区中具体对应的变量。

4、代码区:

存放程序体的二进制代码。比如我们写的函数,都是在代码区的。

通过上面的不同说法,我们也可以看出,这两种说法本身没有优劣之分,具体的内存划分也跟编译器有很大的关系,因此这两种说法都是可以接受的,搞明白内存的分区之后,指针的使用才能够更加的灵活。

;

‘贰’ C语言指针与返回值

函数A的返回值错误。虽然地址和指针很像,但还是不同的两个东西。而且,一旦出了函数A,返回的地址,也就该被回收,会导致程序出错。是非常危险的行为。
举个例子说明下吧。
int *p=a;
这个,在数值上,p是和a的地址相等的,也就是有p==&a。
这时如果a=1;那么你知道*p==1,是真。
但是此时,p存储的是a的地址,p还有自己本身的地址。就好比,你(p)坐在座位上,用手指向另一个座位(&a)一样。那个座位就是a的地址,上面坐着谁(1),就是a的值。你本身就是指针了。
所以说,返回值是指针和地址是完全不同的两个概念。所以就是错误的!

B函数为啥正确呢?因为NULL是一种特殊的指针,叫空指针。所以是可以算作正确的。

‘叁’ 数组越界访问的危险性到底有多大

数组(指针)越界访问,是指使用了超过有效范围的偏移量。
如只分配了10个元素的空间,但是访问了第11个元素,就属于越界。
当出现越界时,由于无法得知被访问空间存储的内容及功能,所以会出现不可预知后果。可能程序崩溃,可能运算结果非预期,也可能完全没有影响。

在编程时要避免指针越界访问,对于用变量作为参数访问元素时,需要控制好变量范围。如果变量值由外部因素决定,那么访问前先对合法性做判断,防止越界。

‘肆’ 请思考如果在使用数组时,下标越界了,会出现什么情况

最好的情况是指向一个没有用到的内存区域,这样不会对应用程序有影响,最坏的情况是指向的程序的核心区域,会导致系统崩溃。
指针越界,就说明这个指针已经不在数组范围内了,指向了不属于数组的区域,再对他进行操作也不是对数组里面的元素进行操作,而是对一个未知的单元进行操作。
(感觉真恐怖的!)

‘伍’ 什么是指针越界,有何后果

)应该特别注意程序的书写格式,让它的形式反映出其内在的意义结构。 程序是最复杂的东西(虽然你开始写的程序很简单,但它们会逐渐变得复杂起来),是需要用智力去把握的智力产品。良好的格式能使程序结构一目了然,帮助你和别人理解它,帮助你的思维,也帮助你发现程序中不正常的地方,使程序中的错误更容易被发现。 人们常用的格式形式是:逻辑上属于同一个层次的互相对齐;逻辑上属于内部层次的推到下一个对齐位置。请参考本课程的教科书或《C程序设计语言》(The C Programming Language,Brian W. Kernighan & Dennis M. Rirchie,清华大学出版社,大学计算机教育丛书(影印版,英文),1996。) 利用集成开发环境(IDE)或者其他程序编辑器的功能,可以很方便地维护好程序的良好格式。请注意下面这几个键,在写程序中应该经常用到它们:Enter键(换一行),Tab键(将输入光标移到下一个对齐位置——进入新的一个层次),Backspace键(回到前一个对齐位置——退到外面的一个层次)。 -------------------------------------------------------------------------------- 2)用最规范的、最清晰的、最容易理解的方式写程序。注意人们在用C语言写程序的习惯写法,例如教科书中解决类似问题时所使用的写法,《C程序设计语言》一书中有许多极好的程序实例。在这里有一个关于程序模式的相关网页,里面也列出了一些常用的模式。 C语言是一个非常灵活的语言,你可能在这里用许多非常隐晦的方式写程序,但这样写出的程序只能是作为一种玩意儿,就像谜语或者智力游戏。这些东西可以用于消磨时间,但通常与实际无缘。在我们的C语言讨论组里提到过这种东西。 -------------------------------------------------------------------------------- 3)在编程中,应仔细研究编译程序给出的错误信息和警告信息,弄清楚每条信息的确切根源并予以解决。特别是,不要忽略那些警告信息,许多警告信息源自隐含的严重错误。我们有许多办法去欺骗编译程序,使它不能发现我们程序中的错误,但这样做最终受到伤害的只能是自己。 -------------------------------------------------------------------------------- C语言的运算符很多,优先级定义也不尽合理,很难完全记清楚,因此要特别注意。需要时查一查(不要怕麻烦,相关网页有运算符表),或者直接按照自己的需要加上几个括号。 -------------------------------------------------------------------------------- scanf("%d %d", i++, a[i]); m = n * n++; -------------------------------------------------------------------------------- 6)总保证一个函数的定义点和它的所有使用点都能看到同一个完整的函数原型说明。 -------------------------------------------------------------------------------- 7)总注意检查数组的界限和字符串(也以数组的方式存放)的结束。C语言内部根本不检查数组下标表达式的取值是否在合法范围内,也不检查指向数组元素的指针是不是移出了数组的合法区域。写程序的人需要自己保证对数组使用的合法性。越界访问可能造成灾难性的后果。 例:在写处理数组的函数时一般应该有一个范围参数;处理字符串时总检查是否遇到空字符'\0'。

‘陆’ C语言指针越界问题

显然合法

语法说: 字符串就是以0结尾的, 所以p如果看作一个字符串的话也必然以0结尾

问题是既然你这个数组没有保证后面是立刻接0的,运行的时候要到什么地方才能找到p需要的这个0就很难说了, 所以p如果看作字符串,那么它的内容很可能不只包括这4个字母

‘柒’ C语言指针访问越界

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

‘捌’ 指针函数和函数指针的返回值各是什么吖

指针函数返回一个指针,如int *sum (…),返回一个int 型指针,函数指针没有返回值

‘玖’ C语言指针越界问题。

strchr函数就在在字符串中查找指定字符,返回其地址。
这个函数本身就已经把结束符号0,计入遍历查找范围,所以没有把0作为结束位置,所以无所谓。
但字符串最好最后多留一位放0,不然代码长了,传参多了,就弄不清了。

‘拾’ 什么是指针越界

指针对应于内存。
如:
char a[6]="abcde";
会申请6个字节;
char i='q';
会申请一个内存空间为1个字节。

内存会这么存储。
a b c d e q
a[0]会输出a,那我把指针指到a[6]那它会怎么输出呢??
答案就是q.
指针从字面意思就是指到、指向的意思,就是告诉编译器怎么去存取。