Android JNI开发从0到1,java调C,C调Java,保姆级教程详解

前些天发现了一个蛮有意思的人工智能学习网站,8个字形容一下"通俗易懂,风趣幽默",感觉非常有意思,忍不住分享一下给大家。
👉点击跳转到教程

第一步首先配置Android studio的NDK开发环境,首先在Android studio中下载NDK包

在这里插入图片描述
第二步在local.properties文件中,配置对应的NDK路径
在这里插入图片描述
第三歩,在app目录下的build.gradle文件中的,android{}闭包中,指定CMakeLists.txt路径

// 在android节点下// 指定CMakeLists.txt路径externalNativeBuild {cmake {// 在该文件种设置所要编写的c源码位置,以及编译后so文件的名字path 'CMakeLists.txt'}}

在defaultConfig闭包下配置

// 增加cmake控制属性externalNativeBuild {cmake {// 指定编译架构abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'}}

在app目录下,指定CmakeLists.txt文件,根据注释进行相应添加

# CMakeLists.txt
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html# Sets the minimum version of CMake required to build the native library.
#CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
add_library(# 设置so文件名称.Hello# 设置这个so文件为共享.SHARED# Provides a relative path to your source file(s).src/main/jni/Hello.c)
add_library(# 设置so文件名称.Test# 设置这个so文件为共享.SHARED# Provides a relative path to your source file(s).src/main/jni/Test.c)
add_library(# 设置so文件名称.CCallJava# 设置这个so文件为共享.SHARED# Provides a relative path to your source file(s).src/main/jni/CCallJava.c)# 添加 log 库的链接
target_link_libraries(CCallJava log)
target_link_libraries(Test log)# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.log-lib# Specifies the name of the NDK library that# you want CMake to locate.log )# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.# 制定目标库.Hello# Links the target library to the log library# included in the NDK.${log-lib} )

第四步,首先进行Java代码C代码的操作
1.JNI2.java代码如下

/*** @Author: ly* @Date: 2023/8/6* @Description: java调C代码*/
public class JNI2 {static {System.loadLibrary("Test"); //加载动态链接库}/*** 让C代码做加法运算,把结果返回* 场景:大量运算,编解码之类的,需要性能很高的情况下,可以用C代码** @param x* @param y* @return*/public native int add(int x, int y);/*** 从java传入字符串,C代码进行拼接** @param s I am from java* @return I am from java and I am from c*/public native String sayHello(String s);/*** 让C代码给每个元素都加上10** @param intArray* @return*/public native int[] increaseArrayEles(int[] intArray);/*** 应用:检查密码是否正确,如果正确返回200,否则返回400** @param pwd* @return*/public native int checkPwd(String pwd);
}

2.根据命令行javah +JNI2的全类名,生成Test.c对应的C代码头文件com_example_jniproject_JNI2.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_jniproject_JNI2 */#ifndef _Included_com_example_jniproject_JNI2
#define _Included_com_example_jniproject_JNI2
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     com_example_jniproject_JNI2* Method:    add* Signature: (II)I*/
JNIEXPORT jint JNICALL Java_com_example_jniproject_JNI2_add(JNIEnv *, jobject, jint, jint);/** Class:     com_example_jniproject_JNI2* Method:    sayHello* Signature: (Ljava/lang/String;)Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_com_example_jniproject_JNI2_sayHello(JNIEnv *, jobject, jstring);/** Class:     com_example_jniproject_JNI2* Method:    increaseArrayEles* Signature: ([I)[I*/
JNIEXPORT jintArray JNICALL Java_com_example_jniproject_JNI2_increaseArrayEles(JNIEnv *, jobject, jintArray);/** Class:     com_example_jniproject_JNI2* Method:    checkPwd* Signature: (Ljava/lang/String;)I*/
JNIEXPORT jint JNICALL Java_com_example_jniproject_JNI2_checkPwd(JNIEnv *, jobject, jstring);#ifdef __cplusplus
}
#endif
#endif

3.根据jni协议,去写对应的c代码,创建Test.c文件,代码如下

//
// Created by DELL on 2023/8/6.
//
#include "com_example_jniproject_JNI2.h"
#include "string.h"
#include <stdlib.h>#include <android/log.h>#define TAG "luyu"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型JNIEXPORT char *JNICALL Java_com_example_MyClass_myMethod(JNIEnv *env, jobject obj, jstring jstr) {const char *cstr = (*env)->GetStringUTFChars(env, jstr, NULL);// 使用 cstr 进行操作,并获取结果(假设结果为 result)(*env)->ReleaseStringUTFChars(env, jstr, cstr);char *result = (char *) malloc(strlen(cstr) + 1);strcpy(result, cstr);return result;
}/*** jint:返回值* Java_全类名_方法名* JNIEnv *env*/
jint Java_com_example_jniproject_JNI2_add(JNIEnv *env, jobject jobj, jint ji, jint jj) {int result = ji + jj;return result;
};/*** 从java传入字符串,C代码进行拼接** @param s I am from java* @return I am from java and I am from c
*/jstring Java_com_example_jniproject_JNI2_sayHello(JNIEnv *env, jobject jobj, jstring jstring1) {char *fromJava = Java_com_example_MyClass_myMethod(env, jobj, jstring1);char *fromC = " and I am from C";//拼接函数,拼接后得到的结果放到第一个参数里面strcat(fromJava, fromC);//把拼接的结果放在第一个参数里面//jstring     (*NewStringUTF)(JNIEnv*, const char*);LOGE("fromJava==%s\n", fromJava);return (*env)->NewStringUTF(env, fromJava);
};/*** 给每个元素加10* 场景:图片处理,颜色矩阵(就是数组),进行数组的处理*/
jintArray Java_com_example_jniproject_JNI2_increaseArrayEles(JNIEnv *env, jobject jobj, jintArray jintArray1) {//1.得到数组的长度//jsize       (*GetArrayLength)(JNIEnv*, jarray);jsize size = (*env)->GetArrayLength(env, jintArray1);//2.得到数组的元素// jint*       (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);jint *intArray = (*env)->GetIntArrayElements(env, jintArray1,JNI_FALSE);//这里传0 false表示 在同一份内存操作,不开辟新的内存//3.遍历数组,给每个元素加10int i;for (i = 0; i < size; i++) {*(intArray + i) += 10;}// 4. 同步修改到 Java 层(*env)->ReleaseIntArrayElements(env, jintArray1, intArray, 0);//4.返回结果return jintArray1;
};/*** 应用:检查密码是否正确,如果正确返回200,否则返回400*/
jint Java_com_example_jniproject_JNI2_checkPwd(JNIEnv *env, jobject jobj, jstring jstring1) {//假设服务器的密码是123456char *origin = "123456";char *fromUser = Java_com_example_MyClass_myMethod(env, jobj, jstring1);//函数比较字符串是否相同int code = strcmp(origin, fromUser);LOGE("code==%d\n", code);if (code == 0) {return 200;} else {return 400;}
};

第五步,C代码调用Java代码,首先创建JNI3.java

/*** @Author: ly* @Date: 2023/8/6* @Description: C代码调用Java代码*/
public class JNI3 {static {System.loadLibrary("CCallJava"); //加载动态链接库}//当执行这个方法的时候,让C代码调用//public int add(int x, int y)public native void callbackAdd();/*** 当执行这个方法的时候,让C代码调用* public void helloFromJava()*/public native void callbackHelloFromJava();/*** 当执行这个方法的时候,让C代码调用* public void printString(String s)*/public native void callbackPrintString();/*** 当执行这个方法的时候,让C代码调用* public static void sayHello(String s)*/public native void callbackSayHello();public int add(int x, int y) {Log.e("TAG", "add()  x=" + x + " y=" + y);return x + y;}public void helloFromJava() {Log.e("TAG", "helloFromJava");}public void printString(String s) {Log.e("TAG", "C中输入的:" + s);}public static void sayHello(String s) {Log.e("TAG", "我是java代码中的JNI" +".java中的sayHello(String s)静态方法,我被C调用了:" + s);}
}

2.根据命令行,javah +JNI3全类名,生成CCallJava.c对应的头文件
com_example_jniproject_JNI3.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_jniproject_JNI3 */#ifndef _Included_com_example_jniproject_JNI3
#define _Included_com_example_jniproject_JNI3
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     com_example_jniproject_JNI3* Method:    callbackAdd* Signature: ()V*/
JNIEXPORT void JNICALL Java_com_example_jniproject_JNI3_callbackAdd(JNIEnv *, jobject);/** Class:     com_example_jniproject_JNI3* Method:    callbackHelloFromJava* Signature: ()V*/
JNIEXPORT void JNICALL Java_com_example_jniproject_JNI3_callbackHelloFromJava(JNIEnv *, jobject);/** Class:     com_example_jniproject_JNI3* Method:    callbackPrintString* Signature: ()V*/
JNIEXPORT void JNICALL Java_com_example_jniproject_JNI3_callbackPrintString(JNIEnv *, jobject);/** Class:     com_example_jniproject_JNI3* Method:    callbackSayHello* Signature: ()V*/
JNIEXPORT void JNICALL Java_com_example_jniproject_JNI3_callbackSayHello(JNIEnv *, jobject);#ifdef __cplusplus
}
#endif
#endif

3.对应的CCallJava.c文件中的代码如下

//
// Created by DELL on 2023/8/6.
//
#include "com_example_jniproject_JNI3.h"
#include <stdlib.h>
#include <stdio.h>#include <android/log.h>#define TAG "luyu"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型/*** 让C代码调用Java中JNI类的public int add(int x ,int y)*/
JNIEXPORT void Java_com_example_jniproject_JNI3_callbackAdd(JNIEnv *env, jobject jobj) {//1.得到字节码//jclass      (*FindClass)(JNIEnv*, const char*);jclass jclazz = (*env)->FindClass(env, "com/example/jniproject/JNI3");//2.得到方法//jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);//最后一个参数是方法签名jmethodID jmethodId = (*env)->GetMethodID(env, jclazz, "add", "(II)I");//3.实例化该类jobject jobject1 = (*env)->AllocObject(env, jclazz);//4.调用方法//jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);jint value = (*env)->CallIntMethod(env, jobject1, jmethodId, 99, 1);//成功调用LOGE("value==%d\n", value);
};/**** 让C代码调用* public void helloFromJava()*/
JNIEXPORT void JNICALL Java_com_example_jniproject_JNI3_callbackHelloFromJava(JNIEnv *env, jobject jobj) {//1.得到字节码//jclass      (*FindClass)(JNIEnv*, const char*);jclass jclazz = (*env)->FindClass(env, "com/example/jniproject/JNI3");//2.得到方法//jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);//最后一个参数是方法签名jmethodID jmethodIds = (*env)->GetMethodID(env, jclazz, "helloFromJava", "()V");//3.实例化该类jobject jobject1 = (*env)->AllocObject(env, jclazz);//4.调用方法//jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);(*env)->CallVoidMethod(env, jobject1, jmethodIds);
};/**** 让C代码调用* public void printString(String s)**/
JNIEXPORT void JNICALL Java_com_example_jniproject_JNI3_callbackPrintString(JNIEnv *env, jobject jobj) {//1.得到字节码//jclass      (*FindClass)(JNIEnv*, const char*);jclass jclazz = (*env)->FindClass(env, "com/example/jniproject/JNI3");//2.得到方法//jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);//最后一个参数是方法签名jmethodID jmethodIds = (*env)->GetMethodID(env, jclazz, "printString", "(Ljava/lang/String;)V");//3.实例化该类jobject jobject1 = (*env)->AllocObject(env, jclazz);//4.调用方法//jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);// jstring     (*NewStringUTF)(JNIEnv*, const char*);jstring jst = (**env).NewStringUTF(env, "I am Android!");(*env)->CallVoidMethod(env, jobject1, jmethodIds, jst);
};/*** 让C代码调用* public static void sayHello(String s)**/
JNIEXPORT void JNICALL Java_com_example_jniproject_JNI3_callbackSayHello(JNIEnv *env, jobject jobj){//1.得到字节码//jclass      (*FindClass)(JNIEnv*, const char*);jclass jclazz = (*env)->FindClass(env, "com/example/jniproject/JNI3");//2.得到方法// jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);//最后一个参数是方法签名jmethodID jmethodIds = (*env)->GetStaticMethodID(env, jclazz, "sayHello", "(Ljava/lang/String;)V");jstring jst = (**env).NewStringUTF(env, "I am Android!");(*env)->CallStaticVoidMethod(env,jclazz,jmethodIds,jst);
};

之后,在MainActivity中调用对应的方法即可

public class MainActivity extends AppCompatActivity {private JNI2 jin2;private static final String TAG = "MainActivity";private JNI3 mJNI3;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);jin2 = new JNI2();mJNI3 = new JNI3();}/******以下是Java代码调用C*****/public void checkPwd(View view) {int result = jin2.checkPwd("12345678");Log.i(TAG, "result==" + result);}public void increaseArrayEles(View view) {int array[] = {1, 2, 3, 4};jin2.increaseArrayEles(array);for (int i = 0; i < array.length; i++) {Log.i(TAG, "result[" + i + "]:" + array[i]);}}public void sayHello(View view) {String result = jin2.sayHello("I am from java");Log.i(TAG, "result==" + result);}public void add(View view) {int result = jin2.add(99, 1);Log.i(TAG, "result==" + result);}/******以下是C调Java代码*****/public void callbackAdd(View view) {mJNI3.callbackAdd();}public void callbackHelloFromJava(View view) {mJNI3.callbackHelloFromJava();}public void callbackPrintString(View view) {mJNI3.callbackPrintString();}public void callbackSayHello(View view) {mJNI3.callbackSayHello();}
}

点击按钮便可输出对应的日志,表示调用成功。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/35119.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASIC芯片设计全流程项目实战课重磅上线 ,支持 65nm制程流片 !

全流程项目实战课学什么&#xff1f; 此次推出【 ASIC芯片设计全流程项目实战课】&#xff0c;基于IPA图像处理加速器&#xff0c;以企业级真实ASIC项目为案例&#xff0c;学员可参与全流程项目实践&#xff0c;以及65nm真实流片&#xff01; 众所周知&#xff0c;放眼整个IC硕…

【Linux】【驱动】驱动框架以及挂载驱动

【Linux】【驱动】驱动框架以及挂载驱动 绪论1.配置开发环境2. 编写驱动文件3. 编译Makefile文件4.编译5. 挂载驱动注意:有些开发板打开了或者禁止了printk信息&#xff0c;导致你看到的实验现象可能不一样&#xff0c;此时已经将文件移动到了开发板中&#xff0c;开发板查看文…

WebRTC音视频通话-新增或修改SDP中的码率Bitrate限制

WebRTC音视频通话-新增或修改SDP中的码率Bitrate限制参数 之前搭建ossrs服务&#xff0c;可以查看&#xff1a;https://blog.csdn.net/gloryFlow/article/details/132257196 之前实现iOS端调用ossrs音视频通话&#xff0c;可以查看&#xff1a;https://blog.csdn.net/gloryFlo…

连接不上手机,adb devices为空:

首先说明一下&#xff0c;我是已经安装了android studio,也配置了环境变量&#xff0c;但是还是连接不上手机 解决方案&#xff1a; 1.打开开发者模式 https://product.pconline.com.cn/itbk/sjtx/sjwt/1424/14246015.html 2.开启usb调试 https://baiyunju.cc/10770 最后成功…

什么是CSS的box-sizing属性?它有哪些取值,各有什么不同?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ CSS的box-sizing属性⭐ 取值⭐ 不同之处⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web…

关于Vue构建低代码平台的思考

一、前言 在项目实战开发中&#xff0c;尤其是大平台系统的搭建&#xff0c;针对不同业务场景&#xff0c;需要为用户多次编写用于录入、修改、展示操作的相应表单页面。一旦表单需求过多&#xff0c;对于开发人员来说&#xff0c;算是一种重复开发&#xff0c;甚至是繁杂的工作…

【C++起飞之路】初级—— auto、范围for循环、宏函数和内联函数

auto、范围for、内联函数、宏函数和nullptr 一、auto — 类型推导的魔法&#xff08;C 11)1、auto 是什么&#xff1f;2、工作原理3、优势4、限制和注意事项 二、范围for (C11)1、基本语法2、优势3、工作原理4、注意事项5、C11&#xff1a; 范围 for 循环的扩展&#xff1a; 三…

软件测试基础篇——LAMP环境搭建

LAMP 1、Linux系统的其他命令 find命令&#xff1a;在目录下查找文件 ​ 格式一&#xff1a;find 路径 参数 文件名 ​ 路径&#xff1a;如果没有指定路径&#xff0c;默认是在当前目录下 ​ 参数&#xff1a;-name 根据文件名来查找&#xff0c;区分大小写&#xff1b; -…

适配器模式(C++)

定义 将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 应用场景 在软件系统中&#xff0c;由于应用环境的变化&#xff0c;常常需要将“一些现存的对象 ”放在新的环境中应用&#xff0c;但是新环境要求…

sql高频面试题-连续完成两个指定动作的用户统计

用户行为分析 业务背景 某购物APP最近上线了一个新功能&#xff0c;用户签到后可以跳转到大转盘抽奖&#xff0c;抽奖获得的奖金可以抵消购物的费用&#xff0c;以此来培养用户使用app的习惯。 数据表介绍 现有一张用户行为表action_log&#xff0c;主要字段如下&#xff0c…

Styletron: 面向组件的样式设计工具包

styletron官网&#xff1a; styletron的GitHub链接&#xff1a; styletron-react 一. 介绍 Styletron是一个通用的component-oriented&#xff08;面向组件的&#xff09;样式工具。它属于css-in-js类别。Styletron可以很好地与React配合使用&#xff0c;但也可以与其他框架或…

docker复现nginx错误配置漏洞

目录 一、nginx环境搭建 1.1搭建步骤 二、docker复现Nginx配置漏洞 2.1安装docker 2.2复现过程 2.1CRLF(carriage return/line feed)注入漏洞 2.2.目录穿越 一、nginx环境搭建 1.1搭建步骤 1.先创建Nginx的目录并进入&#xff08;命令如下&#xff09; mkdir /soft &&…

Android Framework底层原理之WMS的启动流程

一 概述 今天&#xff0c;我们介绍 WindowManagerService&#xff08;后续简称 WMS&#xff09;的启动流程&#xff0c;WMS 是 Android 系统中&#xff0c;负责窗口显示的的服务。在 Android 中它也起着承上启下的作用。 如下图&#xff0c;就是《深入理解 Android》书籍中的…

【C++】STL初识

1.STL的基本概念 2.vector存放内置数据类型 #include <iostream> using namespace std; #include <vector> #include <algorithm>void MyPrint(int val) {cout << val << endl; }void test01() {//创建vector容器对象&#xff0c;并且通过模板参…

Harbor企业镜像仓库部署(本地)

简述&#xff1a; Docker 官方镜像仓库是用于管理公共镜像的地方&#xff0c;大家可以在上面找到想要的镜像&#xff0c;也可以把自己的镜像推送上去。但是有时候服务器无法访问互联网&#xff0c;或者不希望将自己的镜像放到互联网上&#xff0c;那么就需要用到 Docker Regis…

Leetcode-每日一题【剑指 Offer 15. 二进制中1的个数】

题目 编写一个函数&#xff0c;输入是一个无符号整数&#xff08;以二进制串的形式&#xff09;&#xff0c;返回其二进制表达式中数字位数为 1 的个数&#xff08;也被称为 汉明重量).&#xff09;。 提示&#xff1a; 请注意&#xff0c;在某些语言&#xff08;如 Java&…

【Docker】Windows下docker环境搭建及解决使用非官方终端时的连接问题

目录 背景 Windows Docker 安装 安装docker toolbox cmder 解决cmder 连接失败问题 资料获取方法 背景 时常有容器方面的需求&#xff0c;经常构建调试导致测试环境有些混乱&#xff0c;所以想在本地构建一套环境&#xff0c;镜像调试稳定后再放到测试环境中。 Windows …

多线程与高并发--------线程池

线程池 一、什么是线程池 在开发中&#xff0c;为了提升效率的操作&#xff0c;我们需要将一些业务采用多线程的方式去执行。 比如有一个比较大的任务&#xff0c;可以将任务分成几块&#xff0c;分别交给几个线程去执行&#xff0c;最终做一个汇总就可以了。 比如做业务操…

Windows电脑快速搭建FTP服务教程

FTP介绍 FTP&#xff08;File Transfer Protocol&#xff09;是一种用于在计算机网络上进行文件传输的标准协议。它提供了一种可靠的、基于客户端-服务器模型的方式来将文件从一个主机传输到另一个主机。在本文中&#xff0c;我将详细介绍FTP的工作原理、数据传输模式以及常见…

数据结构【第4章】——栈与队列

队列是只允许在一端进行插入操作、而在另-端进行删除操作的线性表。 栈 栈与队列&#xff1a;栈是限定仅在表尾进行插入和删除操作的线性表。 我们把允许插入和删除的一端称为栈顶&#xff08;top&#xff09;&#xff0c;另一端称为栈底&#xff08;bottom&#xff09;&…