BS-栈溢出判断

栈溢出判断

代码运行过程,经常会出现栈溢出情况,现给定函数调用关系和每个函数的栈大小,判断该程序是否存在栈溢出的风险。
如程序如下:

A()
{
   
    B();
    C();
}
B()
{
   
    D();
}
C()
{
   
    E();
}

其中A、B、C、D、E均为函数,A调用了B、C;B调用了D;C调用了E,如果每个函数独立的栈大小分别为:A为10(不包括B、C的栈大小),B为20,C为5,D为15,E为50。调用过程中最大栈空间为路径A->C->E,最大栈空间为65(A->B->D的路径调用最大栈空间为45)。如果整体系统最大额定栈空间配置为60,则A->C->E调用执行时会出现栈溢出异常。

说明:

  1. 函数名称为单个大写字母,最大不超过26个函数;
  2. 调用栈为正整数;
  3. 调用关系不会出现递归调用;
  4. 最大消耗的栈空间等于系统设定的最大空间,不会发生溢出,只有大于系统最大空间,才会发生溢出。

解答要求

时间限制: C/C++ 1000ms, 其他语言: 2000ms
内存限制: C/C++ 256MB, 其他语言: 512MB

输入格式

输入包括三个信息:每个函数的独立栈大小、函数调用关系、系统配置的最大栈空间。格式如下:

  1. 第一行:数字N,代表有N个函数
  2. 第二行到N+1行:表示每个函数名称和栈大小,空格隔开
  3. 第N+2行:数字M,代表下面M行的函数直接调用关系,第一个字母表示调用函数,后面的字母表示被调用函数,并且是按序调用。如 A B C表示先A->B,然后A->C(如示例所示)
  4. 最后一行:数字K,代表系统配置的最大栈空间
    说明:假设主函数都是从第一个调用关系开始被调用(数字M之后的第一行中第一个函数可以认为是主函数调用口),不会从中间某个函数开始调用。

输出要求

输出信息包括:

  1. 是否会出现栈溢出
  2. 如果栈溢出,则输出发生栈溢出的调用路径(路径只输出到触发栈溢出的函数);如果没有栈溢出,则输出最大消耗找的调用路径(如果存在相同大小的调用路径,输出第一个)
  3. 如果栈溢出,输出发生栈溢出时调用关系的栈大小,如果没有栈溢出,输出最大栈消耗

三个信息一行打印,中间空格隔开:如果栈溢出,只输出第一次触及栈溢出的调用关系即可(实际上如果发生了栈溢出,系统也会异常,不会继续产生后续调用了)。


样例1

输入:6
A 20
B 10
C 5
D 15
E 50
F 60
3
A B C
B D
C E F
70
输出:true A-C-E 75

解释:给定输入,第一个调用关系为A B C,则A为入口函数,先执行A-B-D调用,对应占空间为45,当执行到A-C-E时,超过了70,能力为75能输出。不会再触发后续调用关系了,所以输出为A-C-E,对应的最大空间为75。

样例2

输入:6
A 20
B 10
C 5
D 15
E 50
F 60
3
A B C
B D
C E F
100
输出:false A-C-F 85

解释:该示例中,最大占空间配置为100,可以调用所有函数,不会发生栈溢出。最大调用链路关系为A-C-F,相结合的最大栈空间为85。


理解栈溢出判断题目

这道题目主要涉及函数调用栈栈空间的概念,以及如何通过分析函数调用关系来判断程序是否会出现栈溢出。下面我们一步步来理解题目的各个部分。

1. 什么是函数调用栈?

函数调用栈是程序在运行过程中用于管理函数调用的一种数据结构。当一个函数被调用时,系统会为这个函数分配一块内存区域,称为栈帧,用于存储该函数的局部变量、参数以及返回地址等信息。多个函数的调用会形成一个调用栈,最新调用的函数位于栈顶,先调用的函数位于栈底。

例如,假设有函数A调用了函数B,函数B又调用了函数C,那么函数调用栈看起来像这样:

栈顶
C
B
A
栈底
2. 什么是栈大小?

每个函数在被调用时,会占用一定的栈空间(即栈大小)。这个栈大小是函数在栈帧中占用的内存量。不同的函数可能需要不同的栈大小,具体取决于函数内部的局部变量数量、参数数量等因素。

在题目中,每个函数都有一个独立的栈大小,例如:

  • 函数A的栈大小为10
  • 函数B的栈大小为20
  • 函数C的栈大小为5
  • 函数D的栈大小为15
  • 函数E的栈大小为50
3. 什么是栈溢出?

栈溢出是指程序在执行过程中,函数调用栈所占用的内存超过了系统为其分配的最大栈空间。这通常会导致程序崩溃或抛出异常。在这道题目中,我们需要判断在给定的函数调用关系下,是否会发生栈溢出。

4. 如何计算最大栈空间消耗?

要计算程序运行过程中最大的栈空间消耗,我们需要考虑所有可能的函数调用路径,然后计算每条路径上各个函数的栈大小之和。最终,最大的栈空间消耗就是所有路径中最大的那一个。

让我们通过题目中的示例来具体理解:

示例1:

A()
{
   
    B();
    C();
}
B()
{
   
    D();
}
C()
{
   
    E();
}

对应的栈大小:

  • A: 10
  • B: 20
  • C: 5
  • D: 15
  • E: 50

调用关系分析:

  1. 路径A -> B -> D:

    • A的栈大小:10
    • B的栈大小:20
    • D的栈大小:15
    • 总栈空间:10 + 20 + 15 = 45
  2. 路径A -> C -> E:

    • A的栈大小:10
    • C的栈大小:5
    • E的栈大小:50
    • 总栈空间:10 + 5 + 50 = 65

比较两个路径的栈空间消耗:

  • A -> B -> D 路径消耗45
  • A -> C -> E 路径消耗65

所以最大栈空间消耗为65。

系统配置的最大栈空间为60:

  • 由于最大栈空间消耗65 > 系统配置的最大栈空间60,因此会出现栈溢出。
  • 具体来说,路径A -> C -> E导致栈空间达到65,超过了60。

输出:

true A-C-E 65
  • true 表示有栈溢出
  • A-C-E 是发生栈溢出的调用路径
  • 65 是触发溢出的栈空间大小
5. 理解题目的输入和输出格式

输入格式:

  1. 第一行:数字N,代表有N个函数。
  2. 接下来的N行,每行包含一个函数的名称和其对应的栈大小,用空格分隔。例如:A 20 表示函数A的栈大小为20。
  3. 第N+2行:数字M,代表下面有M行的函数直接调用关系。
  4. 接下来的M行,每行描述一个函数调用关系。第一个字母表示调用者,后面的字母表示被调用者,按顺序调用。例如:A B C 表示A先调用B,然后调用C。
  5. 最后一行:数字K,代表系统配置的最大栈空间。

输出格式:

输出包括三个信息,用空格隔开:

  1. 是否会出现栈溢出,用truefalse表示。
  2. 如果栈溢出,输出发生栈溢出的调用路径(只输出到触发溢出的函数)。如果没有栈溢出,输出最大栈空间消耗的调用路径。如果有多个路径具有相同的栈消耗,输出第一个。
  3. 如果栈溢出,输出触发溢出的栈空间大小。如果没有栈溢出,输出最大栈消耗。

示例2解释:

输入:
6
A 20
B 10
C 5
D 15
E 50
F 60
3
A B C
B D
C E F
100

输出:
false A-C-F 85

解释:

  1. 函数调用关系和栈大小:

    • A调用B和C
    • B调用D
    • C调用E和F
    • 函数栈大小:A=20, B=10, C=5, D=15, E=50, F=60
    • 系统最大栈空间K=100
  2. 计算不同调用路径的栈空间消耗:

    • 路径A -> B -> D

      • A=20, B=10, D=15
      • 总栈空间:20 + 10 + 15 = 45
    • 路径A -> C -> E

      • A=20, C=5, E=50
      • 总栈空间:20 + 5 + 50 = 75
    • 路径A -> C -> F

      • A=20, C=5, F=60
      • 总栈空间:20 + 5 + 60 = 85
  3. 最大栈空间消

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值