首先,我们需要在栈中设置一个抽象的存储结构, void *elem, 其需要动态分配堆内存, 声明如下所示:

typedef struct {void *elem;int elem_size;int length;int position;void (*freefn)(void *elem);
}Stack;void stackNew(Stack *s, int elem_size, void (*freefn)(void *elem));
void push(Stack *s, void *elem);
void pop(Stack *s, void *result);
void stackDestroy(Stack *s);

void (*freefn)(void *elem) 为函数指针,其表示用于回收抽象指针(void *elem)中,需要回收的数据,比如动态分配的字符串和结构体中动态分配的内容,我们可以通过传递函数指针,使得在回收栈时,不必弹出所有栈中数据进行回收,而是通过stackDestroy调用我们定义的回收方法,进行数据回收。

具体实现如下所示:

#include <stdlib.h>
#include <string.h>
#include <iostream>void stackNew(Stack *s, int elem_size, void (*freefn)(void *elem)) {s->length = 4;s->position = 0;s->elem_size = elem_size;s->freefn = freefn;s->elem = malloc(s->length * s->elem_size);
}static void stackGrow(Stack *s) {s->length = s->length * 2;s->elem = realloc(s->elem, s->length * s->elem_size);
}void push(Stack *s, void *elem) {if(s->position == s->length) {stackGrow(s);}void *address;address = (char *)s->elem + s->position * s->elem_size;memcpy(address, elem, s->elem_size);s->position++;
}void pop(Stack *s, void *result) {s->position--;memcpy(result, (char *)s->elem + s->position * s->elem_size, s->elem_size);
}void stackDestroy(Stack *s) {int i = 0;for(; i < s->position; i++) {s->freefn((char *)s->elem + i * s->elem_size);}free(s->elem);
}

由于我们不知道数据类型是什么,所以在初始化栈时,我们需要传递数据类型的大小,在进行数据弹出和压入的时候,我们可以对内存直接进行拷贝工作,这样做的优点是显而易见的。不要忘记,elem_size*length才是需要分配堆内存的大小。

调用时,如下所示:

#include <iostream>
#include <string.h>
#include <stdlib.h>
#include "stack4.h"using namespace std;static char * Strdup(const char * source) {char * temp = (char *)malloc(strlen(source) * sizeof(char) + 1);strcpy(temp, source);return temp;
}void freefn(void *element) {cout << "data free..." << endl;char *temp = *((char **) element);free(temp);
}int main() {char *str[] = {"AAAAAAAA", "BBBBBBBB", "CCCCCCCC", "DDDDDDDDD"};Stack *s = (Stack *) malloc(sizeof(Stack));stackNew(s, sizeof(char *), freefn);int i=0;for(;i < 4; i++) {char *sc = Strdup(str[i]);push(s, &sc);}char *result;pop(s, &result);cout << result << endl;//回收pop的数据free(result);//有了固定的回收函数后,不必弹出所有的栈中数据,即可回收内存//若没有,回收内存时,必须弹出所有栈中数据,手动进行回收,然后回收栈内存stackDestroy(s);free(s);getchar();return 0;
}

使用深度拷贝字符串,是考虑到了实际应用中,动态分配内容的生命周期。

还需注意的是,在压栈时,必须对指向动态分配字符串的指针地址进行操作,因为我们在栈的初始化时,传递的数据大小是sizeof(char *),另一方面,也有助于栈的高效操作。

编程范式之栈的抽象操作相关推荐

  1. RUST语言的编程范式

    总是有很多很多人来问我对Rust语言怎么看的问题,在各种地方被at,其实,我不是很想表达我的想法.因为在不同的角度,你会看到不同的东西.编程语言这个东西,老实说很难评价,在学术上来说,Lisp就是很好 ...

  2. 编程范式:函数式编程防御式编程响应式编程契约式编程流式编程

    不长的编码生涯,看到无数概念和词汇:面向对象编程.过程式编程.指令式编程.函数式编程.防御式编程.流式编程.响应式编程.契约式编程.进攻式编程.声明式编程--有种生无可恋的感觉. 本文试图加以汇总和整 ...

  3. JavaScript 函数式编程范式

    目录 一. 函数式编程范式 1.1 编程范式定义 1.2 函数式编程范式特点 1.3 函数式编程范式基本概念 1.4 章节学习指南 二. 头等函数 2.1 一等公民 和 高阶函数 2.2 函数作为参数 ...

  4. c语言是函数式原型的编程,编程范式|程序世界里的编程范式,探索编程本质

    最近看了一些关于编程范式的文章,简要做一些小结和记录 什么是编程范式 在现实生活中,为了适配各种规格的螺帽,我们需要许多种类的螺丝刀. 在编程世界中,静态语言有许多种类的数据类型. 不过,我们可以发现 ...

  5. 编程范式,程序员的编程世界观

    编程范式(Programming Paradigm)是某种编程语言典型的编程风格或者说是编程方式.随着编程方法学和软件工程研究的深入,特别是OO思想的普及,范式(Paradigm)以及编程范式等术语渐 ...

  6. 再谈编程范式-程序语言背后的思想

    link link 编程范式 托马斯.库尔提出"科学的革命"的范式论后,Robert Floyd在1979年图灵奖的颁奖演说中使用了编程范式一词.编程范式一般包括三个方面,以OOP ...

  7. 基于对象和面向对象编程范式辨析和主流编程语言中的应用

    基于对象和面向对象编程范式辨析和主流编程语言中的应用 前言 本文的目的是想告诉大家,为什么C++的模板这么强大.为什么Ruby的Duck Typing(像鸭子那样编程)这么强大! 基于对象和面向对象编 ...

  8. 编程范式,程序员的编程世界观(转)

    编程范式(Programming Paradigm)是某种编程语言典型的编程风格或者说是编程方式.随着编程方法学和软件工程研究的深入,特别是OO思想的普及,范式(Paradigm)以及编程范式等术语渐 ...

  9. 再谈编程范式—程序语言背后的思想

    编程范式 托马斯.库尔提出"科学的革命"的范式论后,Robert Floyd在1979年图灵奖的颁奖演说中使用了编程范式一词.编程范式一般包括三个方面,以OOP为例: 1,学科的逻 ...

最新文章

  1. Docker视频发布
  2. 【 MATLAB 】ellip 函数介绍(椭圆滤波器设计)
  3. windows下cacti的快速安装
  4. 零基础自学python教程-零基础人员可以学习python吗?|Python培训基础教程
  5. c# 访问hbase_大数据技术 windows下C#通过Thrift操作HBase
  6. 什么叫静态构建版本号码_为什么要使用GatsbyJS构建静态网站
  7. python paramiko_Python3之paramiko模块
  8. 基于SpringBoot的答题系统
  9. Unity3d Network 局域网多人对战之游戏大厅
  10. 上机练习2 类与对象 pc cpu harddisk对象组合
  11. 微信 android应用签名生成工具,GitHub - feinoah/WeChatSignature: 改进版本的微信应用签名生成工具,再也不用输入包名了!...
  12. 数据库-SQL Server数据库查询速度慢(连接超时)原因及优化方法
  13. 雅居乐万豪酒店java_“万豪,我心所属之地” | 上海雅居乐万豪酒店Terence Sun的实习故事...
  14. MYSQL 命令中常出现的error - 1046 1064 1264
  15. 【QT网络编程】实现UDP协议通信
  16. android Wifi自动连接
  17. l2高斯分布_L1正则先验是Laplace分布,L2正则先验分布是高斯分布
  18. 使用c#完成数据库的crud操作
  19. 网页特效之imageflow
  20. informatica 初级操作流程

热门文章

  1. 配置web工程的过程
  2. DCMTK的Lib 引用顺序
  3. POJ 3168 排序+扫描
  4. 【转】Android用NDK和整套源码下编译JNI的不同
  5. ZeroMemory(百度百科 ZeroMemory)
  6. Leetcode 1015. Smallest Integer Divisible by K
  7. JSP和Servlet互相传输数据的过程中产生的乱码问题及解决方案(没有使用AJAX的情况)...
  8. ===,!==,==,!=的使用
  9. python基础之-数据类型
  10. ionic2.x 手动搭建开发环境教程分享(nodejs,jdk,ant,androidsdk)