使用callstack在C中实现堆栈数据结构?

2024-03-29

我对 C 下内存结构的理解是,程序的内存与堆栈和堆分开,每个堆栈和堆都从块的两端生长,可以想象分配所有 RAM,但显然抽象为某种操作系统内存片段管理器。
堆栈设计用于处理局部变量(自动存储),堆设计用于内存分配(动态存储)。

(编者注:有一些 C 实现,其中自动存储不使用“调用堆栈”,但这个问题假设在普通 CPU 上有一个正常的现代 C 实现,其中局部变量如果不能只存在于寄存器中,则确实使用调用堆栈。 )


假设我想为某些数据解析算法实现堆栈数据结构。它的生命周期和范围仅限于一个函数。

我可以想到 3 种方法来做这样的事情,但在我看来,考虑到这种情况,它们都不是最干净的方法。

我的第一个想法是在堆中构造一个堆栈,就像 C++ 一样std::vector:

Some algorithm(Some data)
{
  Label *stack = new_stack(stack_size_estimate(data));
  Iterator i = some_iterator(data);
  while(i)
  {
    Label label = some_label(some_iterator_at(i));
    if (label_type_a(label))
    {
      push_stack(stack,label);
    }
    else if(label_type_b(label))
    {
      some_process(&data,label,pop_stack(stack));
    }
    i = some_iterator_next(i);
  }
  some_stack_cleanup(&data,stack);
  delete_stack(stack);
  return data;
}

这个方法没问题,但是很浪费,因为堆栈大小是一个猜测,并且随时都会发生。push_stack可能会调用一些内部 malloc 或 realloc 并导致不规则的速度减慢。对于该算法来说,这些都不是问题,但这种构造似乎更适合必须跨多个上下文维护堆栈的应用程序。这里的情况并非如此;堆栈是该函数私有的,并且在退出之前被删除,就像自动存储类一样。


我的下一个想法是递归。因为递归使用内置堆栈,这似乎更接近我想要的。

Some algorithm(Some data)
{
  Iterator i = some_iterator(data);
  return some_extra(algorithm_helper(extra_from_some(data),&i);
}
Extra algorithm_helper(Extra thing, Iterator* i)
{
  if(!*i)
  {return thing;}
  {
    Label label = some_label(some_iterator_at(i));
    if (label_type_a(label))
    {
      *i = some_iterator_next(*i);
      return algorithm_helper
      (  extra_process( algorithm_helper(thing,i), label),  i  );
    }
    else if(label_type_b(label))
    {
      *i = some_iterator_next(*i);
      return extra_attach(thing,label);
    }
  }
}

这种方法使我免于编写和维护堆栈。对我来说,代码似乎更难遵循,但这对我来说并不重要。

我的主要问题是这使用了更多的空间。
堆栈帧保存此副本Extra构造(基本上包含Some data加上想要保存在堆栈中的实际位)以及每个帧中完全相同的迭代器指针的不必要副本:因为它比引用一些静态全局更“安全”(而且我不知道如何不这样做) 。如果编译器做了一些聪明的尾递归之类的事情,这不会成为问题,但我不知道我是否喜欢交叉手指并希望我的编译器很棒。


我能想到的第三种方法涉及某种可以在堆栈上增长的动态数组,这是使用某种我不知道的 C 语言编写的最后一个东西。
或者是外来的asm block.

考虑到这一点,这就是我正在寻找的东西,但我不认为自己会编写一个汇编版本,除非它非常简单,而且我不认为它更容易编写或维护,尽管它在我的脑海中看起来更简单。显然它不能跨 ISA 移植。

我不知道我是否忽略了某些功能,或者我是否需要寻找另一种语言,或者我是否应该重新考虑我的生活选择。一切都可能是真的……我希望这只是第一个。

我不反对使用一些图书馆。有吗?如果有,它是如何运作的?我在搜索中没有找到任何东西。


我最近了解了可变长度数组,我真的不明白为什么不能利用它们作为增长堆栈引用的方式,但我也无法想象它们以这种方式工作。


TL;博士:使用std::vector或同等内容。


(Edited)

关于你的开场陈词: 分段的日子已经结束了。如今,进程有多个堆栈(每个线程一个),但所有进程共享一个堆。

关于选项1:您应该直接使用,而不是编写和维护堆栈并猜测其大小std::vector,或者它的 C 包装器,或者它的 C 克隆 - 在任何情况下,都使用“向量”数据结构。

Vector https://en.wikipedia.org/wiki/Sequence_container_(C%2B%2B)#Vector的算法一般是相当有效率 https://www.drdobbs.com/c-made-easier-how-vectors-grow/184401375。并不完美,但通常适合许多实际用例。

关于选项2:你是对的,至少只要讨论仅限于 C。在 C 中,递归既浪费又不可扩展。在其他一些语言中,特别是在函数式语言中,递归是表达这些算法的方式,尾部调用优化是语言定义的一部分。

关于选项3:最接近您正在寻找的 C 的东西是alloca() http://man7.org/linux/man-pages/man3/alloca.3.html。它允许您增长堆栈帧,如果堆栈没有足够的内存,操作系统将分配它。然而,围绕它构建一个堆栈对象将非常困难,因为没有realloca()正如@Peter Cordes 所指出的。

另一个缺点是堆栈仍然有限。在 Linux 上,堆栈通常限制为 8 MB。这与递归具有相同的可扩展性限制。

关于变长数组:VLA 基本上是语法糖,一种方便的表示法。除了语法之外,它们还具有与数组完全相同的功能(实际上,甚至更少,即。sizeof()不起作用),更不用说动态功率了std::vector.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用callstack在C中实现堆栈数据结构? 的相关文章

  • 删除字符串 C 的第一个字符

    我试图删除字符串的第一个字符并保留其余部分 我当前的代码无法编译 我对如何修复它感到困惑 My code char newStr char charBuffer int len strlen charBuffer int i 1 char
  • CMake 和 Visual Studio:如何获得快速、安静的命令行构建?

    我有一个 cmake 项目 它成功地完成了我想要的一切 但我有大约 100 个文件 当我只需要重新编译一个文件时 我厌倦了每次看到生成的巨大输出 每个文件 30 行 明确地说 我正在编译cmake build 得到这个结果 我需要传递给编译
  • C 中的复合语句表达式

    下面的代码不起作用 int i void 999 100 添加括号就可以了 为什么 int i void 999 100 还有另一种方法可以完成此类分配 int i void 999 100 是什么让他们与众不同 在这份声明中 int i
  • 如何在 MFC 中调整对话框大小时移动控件?

    我已经在 MFC 中创建了对话框视图 从下图中可以清楚地看到 如滑块控件和编辑框等 当我调整对话框大小时 这些控件不会移动 在此输入图像描述 https i stack imgur com 7OxAK jpg 我想移动控件以适应对话框 但不
  • 隐式方法组转换陷阱

    我想知道为什么给定代码的输出 在 LinqPad 中执行 void Main Compare1 Action Main Dump Compare2 Main Dump bool Compare1 Delegate x return x Ac
  • 使用 Selenium for C# 登录 Facebook

    我一直在使用 Selenium C 框架并尝试进行 facebook 登录 但没有任何运气 这是我到目前为止得到的 基于这篇文章 使用 Selenium 测试 Facebook Connect 应用程序 https stackoverflo
  • 基于 MS Bot Framework 中的响应分支对话框/表单

    我们正在尝试使用 MS Bot Framework 但尚未完全弄清楚如何实现此场景 我们有一个 LUIS 对话框 类型 它工作正常并且经过适当的培训 以常见的三明治为例 LUIS 意图寻找的基本内容是用户询问订单状态 如果问题中提供了订单号
  • 有没有办法使 C90 标准中的枚举无符号? (符合 MISRA-C 2004 标准)

    我正在尝试找到一种使枚举 无符号 的方法 enum x1 0 x2 x3 uint8 t x2 lt PC LINT MISRA C 2004 will complain about mixing signed and unsigned h
  • Entity Framework 4.1 RC:Code First EntityTypeConfiguration 继承问题

    我尝试使用通用的 EntityTypeConfiguration 类来配置所有实体的主键 以便每个派生的配置类不会重复自身 我的所有实体都实现一个公共接口 IEntity 它表示每个实体必须有一个 int 类型的 Id 属性 我的配置基类如
  • 'goto *foo' 其中 foo 不是指针。这是什么?

    我正在玩标签作为值 https gcc gnu org onlinedocs gcc Labels as Values html并最终得到这段代码 int foo 0 goto foo 我的 C C 经验告诉我 foo means dere
  • Azure 2012 年 10 月 SDK 损坏 UseDevelopmentStorage=true

    有人尝试过使用 usedevelopmentstorage true 连接字符串的 2012 年 10 月 Azure sdk 吗 CloudStorageAccount Parse UseDevelopmentStorage true 抛
  • 控制器中的异常处理 (ASP.NET MVC)

    当您自己的代码抛出异常并从控制器中的操作调用时 应该如何处理 我看到很多最佳实践的例子 其中根本没有 try catch 语句 例如 从存储库访问数据 public ViewResult Index IList
  • 套接字:监听积压并接受

    listen sock backlog 在我看来 参数backlog限制连接数量 这是我的测试代码 server initialize the sockaddr of server server sin family AF INET ser
  • .Net Core 中的脚手架以及解决方案中的多个项目

    我创建了一个针对 net461 的 Net Core MVC6 应用程序 我使用了一个我非常熟悉的项目结构 其中我将数据 模型和服务类放置在单独的类库项目中 并且 Web 项目引用这些项目 当我尝试搭建控制器时 我收到一条错误 指出我正在搭
  • 无法将方法组“Read”转换为非委托类型“bool”

    我正在尝试使用SqlDataReader检查条目是否存在 如果存在则返回ID 否则返回false 当我尝试编译时 出现错误 无法将方法组 Read 转换为非委托类型 bool 我一直在遵循在 VB 中找到的示例 但似乎翻译可能不正确 pri
  • Qt mouseReleaseEvent() 未触发?

    我有一个显示图片的库 我们称之为 PictureGLWidget 其中 class PictureGLWidget public QGLWidget 所以 PictureGLWidget 扩展了 QGLWidget 在PictureGlWi
  • C 的“char”使用什么字符集? [复制]

    这个问题在这里已经有答案了 简单的问题 我最近开始用 C 编程 有一个简单的问题 C 编程语言在其 char 类型中使用什么字符集 例如 ASCII 还是取决于软件 操作系统 char 本质上是 1 个字节 主要在所有操作系统上 所以默认情
  • 如何解释“错误C2018:未知字符'0x40'?[关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 在编译一些代码时 我收到以下信息 错误 C2018 未知字符 0x40 我想知道如何解决这样的问题 这是我要开始的地方
  • win32 API 和 .NET 框架之间的选择

    我必须开发一个适用于 Windows 的应用程序 该应用程序将能够通过网络摄像头识别手势来控制鼠标 我将使用 vc 2008 进行开发 但我很困惑是使用 NET 框架还是核心 win32 API 性能对于我的应用程序非常重要 根据 Ivor
  • 编译器可以报告未知属性的错误吗?即使有范围?

    在N3291 7 6 1 3 5 属性语法和语义 decl attr grammar 关于如何属性是用我读过的源代码写的 使用一个属性范围令牌是有条件支持的 实现定义的行为 and For an 属性标记本国际标准中未指定 该行为是实现定义

随机推荐

  • 如何通信两个独立的python进程?

    我有两个 python 程序 我想对它们进行通信 它们都是系统服务 都不是由父进程 fork 的 有没有什么方法可以在不使用套接字的情况下做到这一点 例如 通过创建一些队列 gt 序列化它 gt 由其他进程反序列化并执行通信 或者写入执行通
  • Servlet 在某些点击或时间后停止在 Tomcat 服务器上工作

    我的一些 servlet 遇到了一个非常奇怪的问题 下面是我的配置 文件夹 A 在 Tomcat 目录中部署了 X 个 servlet 文件夹 B 在 Tomcat 目录中部署了 Y 个 servlet 经过一定时间或点击文件夹 B 中的任
  • GCC预处理,内置和命令行是做什么用的?

    我很好奇 GCC 预处理步骤的输出 更准确地说 以下两行的目的是什么 1
  • TFIDF 计算混淆

    我在网上找到了以下计算TFIDF的代码 https github com timtrueman tf idf blob master tf idf py 我在函数 def idf word documentList 中添加了 1 这样我就不
  • 最长已排序子序列的长度

    我的未排序数组是 string a new string 10 22 9 33 21 50 41 60 80 在这个数组中 10 22 33 50 60 80按升序排列 所以输出必须是6 一般来说 我想要由数组元素组成并从第一个元素开始的升
  • 将列表绑定到数据源

    我希望能够将列表绑定到列表框数据源 并且当修改列表时 列表框的 UI 会自动更新 Winform 不是 ASP 这是一个示例 private List
  • 应该在代码中的什么位置保存不变的数据?

    我已经根据数据库中的表定义了模型 现在有一些模型的数据几乎没有变化 例如 电子商务网站销售的产品类别 产品发货城市等 这些不会经常更改 因此为了避免影响数据库 目前将它们保存为静态变量 问题是这些静态变量应该位于代码中的哪个位置 目前 在
  • 在 F# 中,如何生成 Func 类型的表达式?

    我正在使用需要 Func 类型值的 api 具体来说 我想打电话给ModelMetadataProviders Current GetMetadataForType http msdn microsoft com en us library
  • MyBatis 与 Guava 多重映射

    我想用番石榴多重地图 https google github io guava releases snapshot api docs com google common collect Multimap html as a 结果图 http
  • 如何从 django 中删除模型?

    在 Django 中 如何删除已同步到数据库中的模型 例如 在 Django 教程页面中有以下代码 from django db import models class Poll models Model question models C
  • 使用 Ansible 进行 SSH 代理转发

    我正在使用 Ansible 1 5 3 和 Git 以及 ssh 代理转发 https help github com articles using ssh agent forwarding https help github com ar
  • Javascript:无响应的脚本错误

    我收到来自 Firefox 的错误消息 脚本无响应 此错误是由于我添加到页面中的一些 JavaScript 造成的 我想知道无响应是否完全是由代码循环 函数循环调用彼此或无休止的 for 循环 引起的 或者可能还有其他原因 你能帮我调试这些
  • Require 指令 - 文件 url

    在 Rails 3 Sprocket 中 有没有办法使用远程站点的 url 加载 javascript 文件 例如 我希望在您的 js 文件中使用类似的内容require指示 require http example com remote
  • 使用 CruiseControl.NET 和 MSBuild 发布网站

    我正在尝试设置CruiseControl NET http en wikipedia org wiki CruiseControl自动从 SVN 下载新版本 VisualSVN 服务器 http en wikipedia org wiki
  • 即使发生 400 bad request 错误,如何捕获服务器响应?

    考虑以下代码 这只是一个简单的 http post 请求axios图书馆 axios post http localhost users this state then function response if response statu
  • Android - facebook sdk 登录窗口消失

    我正在尝试使用 Android Facebook SDK 但没有成功 问题是 Facebook 登录窗口开始加载 但在发生任何事情之前它就消失了 这是实际设备上的行为 在模拟器上一切都很好 我做了什么 从以下位置下载了 SDKhere ht
  • Crystal Reports - 如果页面上没有记录,则隐藏页眉

    如果最后一页上没有记录 详细信息部分 如何隐藏页眉 如果最后一页上有一些数据 则页眉必须显示在最后一页上 否则隐藏页眉 公式pagenumber totalpagecount不起作用 因为它总是会抑制最后一页的标题 将此公式放入详细信息部分
  • 如何通过串口连接Android模拟器与桌面?

    我有一个模拟器应用程序 可以将串行命令发送到 Android 设备 反之亦然 为了使用此应用程序 我需要通过物理 RS 232 电缆连接真正的 Android 设备 然后选择设备 我的问题是 有没有办法在模拟器和Mac Linux PC之间
  • 这么多未使用的分支。如何清理?

    我有以下分支机构 master newbranch remotes origin HEAD gt origin master remotes origin api notes remotes origin event creation va
  • 使用callstack在C中实现堆栈数据结构?

    我对 C 下内存结构的理解是 程序的内存与堆栈和堆分开 每个堆栈和堆都从块的两端生长 可以想象分配所有 RAM 但显然抽象为某种操作系统内存片段管理器 堆栈设计用于处理局部变量 自动存储 堆设计用于内存分配 动态存储 编者注 有一些 C 实