Android IPC机制(三)进程间通信方式

在Android中有以下几种进程间通信方式:

目录

1.Bundle

2.文件共享

3.Messenger

 4.ContentProvider

5.AIDL


1.Bundle

  Bundle是Android中用于存储一组键值对的类,它实现了Parcelable接口。这使得Bundle能够在不同的进程之间传递数据。当我们通过Intent启动其他应用的组件(如ActivityServiceBroadcastReceiver)时,可以将数据存储在Bundle中,并将其附加到Intent中,从而实现跨进程通信。

下面是一个简单的示例,展示如何在MainActivity中使用Bundle将数据传递到SecondActivity

在MainActivity中:

Intent intent = new Intent(this, SecondActivity.class);
Bundle bundle = new Bundle();
bundle.putString("test", "这是Bundle跨进程通信");
intent.putExtra("test", bundle);
startActivity(intent);

在上述代码中,我们创建了一个Intent对象,用于启动SecondActivity。然后,我们创建了一个Bundle对象,并使用putString方法将一条字符串信息存储在其中。接着,我们将这个Bundle附加到Intent中,并调用startActivity方法启动目标活动。

在SecondActivity中接收数据:

SecondActivity中,我们可以通过以下代码来接收并使用传递过来的Bundle数据:

Bundle result = getIntent().getBundleExtra("test");
Log.e("data", "onCreate:" + result.getString("test"));

在这里,我们使用getIntent().getBundleExtra("test")方法获取传递过来的Bundle,然后通过getString方法提取出我们之前存储的字符串。最后,我们使用Log.e打印出接收到的数据。

运行结果:

当我们运行这个示例时,SecondActivity将会在日志中输出以下内容:

2.文件共享

       两个进程通过读/写同一个文件来交互数据,从而实现通信。但是Android上面没有对文件的并发读/写做限制,甚至两个进程同时对一个文件进行写操作都是运行的,因此有可能发送异常,所以,文件共享发送适合在对数据同步要求不高的进程间通信,并且要妥善处理并发的读/写问题。

      文件共享的实现,在我们的示例中,我们在MainActivity中序列化一个 User对象到应用的内部存储文件中。然后在SecondActivity 中去反序列化,我们期望在 SecondActivity中能够正确地恢复 User 对象的值。关键代码如下:

在MainActivity中序列化到文件:

 private void persistToFile(){try{User user=new User(1,"hello word",false);File file=new File(getExternalCacheDir(),"share_data.txt");if(!file.exists()){file.createNewFile();}FileOutputStream fos = new FileOutputStream(file);ObjectOutputStream objectOutputStream=new ObjectOutputStream(fos);objectOutputStream.writeObject(user);Log.e("xxx","persist user:"+user);fos.close();objectOutputStream.close();} catch (IOException e) {e.printStackTrace();}}

在 SecondActivity中从文件恢复:

 private void recoverFromFile(){try {User user = null;File file = new File(getExternalCacheDir(), "share_data.txt");if (!file.exists()) {file.createNewFile(); }ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));user = (User) objectInputStream.readObject();Log.e("xxx", "recover user:" + user);objectInputStream.close();} catch (Exception e) {e.printStackTrace();}}

下面看一下log,很显然,在SecondActivity 中成功地从文件从恢复了之前存储的 User对象的内容,这里之所以说内容,是因为反序列化得到的对象只是在内容上和序列化之前的对象是一样的,但它们本质上还是两个对象。

SharedPreferences的局限性:

我们知道SharedPerference是存储xml文件里面,从本质上说也是文件的一种,但是由于系统对它的读写有一定的缓存策略,即在内存中会有一份SharedPerference文件的缓存,因此多进程模式下,系统对它的读/写就变得不可靠,当面对高并发的读/写访问时,SharedPerference有很大概率会丢失数据,因此不建议进程间的通信使用SharedPerference。

3.Messenger

        Messenger 可以翻译为信使,通过它可以在不同进程中传递 Message 对象,在Message中放入我们需要传递的数据,就可以轻松地实现数据的进程间传递了。

为什么说Messenger的底层是基于AIDL实现?

我们大致看一下Messenger 这个类的构造方法就明白了。下面是Messenger 的两个构造方法,从构造方法的实现上我们可以明显看出AIDL的痕迹,不管是IMessenger还是 Stub.asInterface,这种使用方法都表明它的底层是 AIDL。

    public Messenger(Handler target) {mTarget = target.getIMessenger();}public Messenger(IBinder target) {mTarget = IMessenger.Stub.asInterface(target);}

既然Messenger是基于AIDL实现的,那么它与AIDL有什么区别呢?

  • Messenger是通过Bundle传递数据,多以只能传递基本数据类型,而AIDL可以传递实体类,其实Bundler也可以传递序列化之后的实体类。
  • Messenger适合传递数据少,数据量少的情况,AIDL适合数据多,数据量大的情况。
  • Messenger返回值是异步的,AIDL是同步的。

下面是一个简单的示例,展示如何在Android应用中使用Messenger进行进程间通信。

客户端代码(MainActivity)

public class MainActivity extends AppCompatActivity {private Handler mHandler=new Handler(Looper.getMainLooper()){@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);if(msg.what==11) {Bundle data = msg.getData();String test = data.getString("test");Log.d("xxx", "handleMessage:" + test);}}};private final  Messenger mMessager=new Messenger(mHandler); // 用于与服务通信的Messenger@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent=new Intent(this,MessengerService.class);// 创建服务的IntentbindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);// 绑定服务}private final ServiceConnection mServiceConnection=new ServiceConnection(){@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {Messenger messenger=new Messenger(service);// 获取服务的MessengerMessage message= Message.obtain();// 创建消息message.what=1;Bundle bundle=new Bundle();bundle.putString("test","Messenger传递数据");message.setData(bundle);message.replyTo=mMessager;// 设置回复的Messengertry {messenger.send(message);// 发送消息到服务} catch (RemoteException e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {}};@Overrideprotected void onDestroy() {super.onDestroy();if(mServiceConnection!=null){unbindService(mServiceConnection);// 解绑服务}}
}

 服务端代码(MessengerService)

public class MessengerService extends Service {private Handler mHandler=new Handler(Looper.getMainLooper()){@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);if(msg.what==1) {Bundle data = msg.getData();String test = data.getString("test");Log.d("xxx", "handleMessage:" + test);Messenger replyTo=msg.replyTo;Message message=new Message();message.what=11;Bundle bundle=new Bundle();bundle.putString("test","这是服务器回传数据到客户端");message.setData(bundle);message.replyTo=mMessenger;try {replyTo.send(message);} catch (RemoteException e) {e.printStackTrace();}}}};private Messenger mMessenger=new Messenger(mHandler);@Nullable@Overridepublic IBinder onBind(Intent intent) {return mMessenger.getBinder();}
}

AndroidManifest.xml配置

在AndroidManifest.xml中,需要声明服务并指定其运行在单独的进程中:

<service android:name=".MessengerService" android:process=":test"/>

运行结果: 服务端收到了客户端发送的信息,而客户端也收到了服务端的回复。

 4.ContentProvider

ContentProvider是 Android 中提供的专门用于不同应用间进行数据共享的方式,虽然ContentProvider的底层实现是 Binder,但是它的使用过程要比 AIDL简单许多,这是因为系统已经为我们做了封装,使得我们无须关注底层细节即可轻松实现IPC。

实现一个 ContentProvider 涉及几个步骤,包括创建类、定义数据模型、实现必要的方法以及在 AndroidManifest.xml 中注册。以下是一个简单的示例,展示如何实现一个 ContentProvider

1. 创建数据模型

首先,我们需要定义一个数据模型。假设我们要管理一个简单的联系人信息,包括姓名和电话号码。

public class Contact {public static final String TABLE_NAME = "contacts";public static final String COLUMN_ID = "_id";public static final String COLUMN_NAME = "name";public static final String COLUMN_PHONE = "phone";
}

2. 创建 ContentProvider 类

接下来,我们创建一个继承自 ContentProvider 的类,并实现必要的方法。

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;public class ContactProvider extends ContentProvider {private static final String AUTHORITY = "com.example.app.provider";private static final String BASE_PATH = "contacts";public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);private static final int CONTACTS = 1;private static final int CONTACT_ID = 2;private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);static {uriMatcher.addURI(AUTHORITY, BASE_PATH, CONTACTS);uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", CONTACT_ID);}private SQLiteDatabase database;@Overridepublic boolean onCreate() {// 初始化数据库DatabaseHelper dbHelper = new DatabaseHelper(getContext());database = dbHelper.getWritableDatabase();return database != null;}@Overridepublic Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {Cursor cursor;switch (uriMatcher.match(uri)) {case CONTACTS:cursor = database.query(Contact.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);break;case CONTACT_ID:selection = Contact.COLUMN_ID + " = ?";selectionArgs = new String[]{uri.getLastPathSegment()};cursor = database.query(Contact.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);break;default:throw new IllegalArgumentException("Unknown URI: " + uri);}cursor.setNotificationUri(getContext().getContentResolver(), uri);return cursor;}@Overridepublic Uri insert(Uri uri, ContentValues values) {long id = database.insert(Contact.TABLE_NAME, null, values);getContext().getContentResolver().notifyChange(uri, null);return Uri.parse(BASE_PATH + "/" + id);}@Overridepublic int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {int rowsUpdated;switch (uriMatcher.match(uri)) {case CONTACTS:rowsUpdated = database.update(Contact.TABLE_NAME, values, selection, selectionArgs);break;case CONTACT_ID:selection = Contact.COLUMN_ID + " = ?";selectionArgs = new String[]{uri.getLastPathSegment()};rowsUpdated = database.update(Contact.TABLE_NAME, values, selection, selectionArgs);break;default:throw new IllegalArgumentException("Unknown URI: " + uri);}if (rowsUpdated != 0) {getContext().getContentResolver().notifyChange(uri, null);}return rowsUpdated;}@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {int rowsDeleted;switch (uriMatcher.match(uri)) {case CONTACTS:rowsDeleted = database.delete(Contact.TABLE_NAME, selection, selectionArgs);break;case CONTACT_ID:selection = Contact.COLUMN_ID + " = ?";selectionArgs = new String[]{uri.getLastPathSegment()};rowsDeleted = database.delete(Contact.TABLE_NAME, selection, selectionArgs);break;default:throw new IllegalArgumentException("Unknown URI: " + uri);}if (rowsDeleted != 0) {getContext().getContentResolver().notifyChange(uri, null);}return rowsDeleted;}@Overridepublic String getType(Uri uri) {switch (uriMatcher.match(uri)) {case CONTACTS:return "vnd.android.cursor.dir/" + AUTHORITY + "." + BASE_PATH;case CONTACT_ID:return "vnd.android.cursor.item/" + AUTHORITY + "." + BASE_PATH;default:throw new IllegalArgumentException("Unknown URI: " + uri);}}private static class DatabaseHelper extends SQLiteOpenHelper {private static final String DATABASE_NAME = "contacts.db";private static final int DATABASE_VERSION = 1;public DatabaseHelper(Context context) {super(context, DATABASE_NAME, null, DATABASE_VERSION);}@Overridepublic void onCreate(SQLiteDatabase db) {String createTable = "CREATE TABLE " + Contact.TABLE_NAME + " (" +Contact.COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +Contact.COLUMN_NAME + " TEXT, " +Contact.COLUMN_PHONE + " TEXT" + ");";db.execSQL(createTable);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {db.execSQL("DROP TABLE IF EXISTS " + Contact.TABLE_NAME);onCreate(db);}}
}

3. 在 AndroidManifest.xml 中注册 ContentProvider

在 AndroidManifest.xml 文件中注册 ContentProvider,并设置权限(如果需要)。

<providerandroid:name=".ContactProvider"android:authorities="com.example.app.provider"android:exported="true" />

4. 使用 ContentProvider

其他应用程序可以通过 ContentResolver 来访问 ContentProvider 提供的数据。例如,查询联系人数据:

Cursor cursor = getContentResolver().query(ContactProvider.CONTENT_URI, null, null, null, null);
if (cursor != null) {while (cursor.moveToNext()) {String name = cursor.getString(cursor.getColumnIndex(Contact.COLUMN_NAME));String phone = cursor.getString(cursor.getColumnIndex(Contact.COLUMN_PHONE));// 处理数据}cursor.close();
}

5.AIDL

     在Android平台中,每个应用程序都运行在自己的独立进程中,并且可以启动另一个应用进程的服务,而且经常需要在不同的进程间传递数据对象。但是一个进程不能直接访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的进行进程边界。而AIDL就用于生成可以在Android设备上两个进程之间进行进程间通信的代码。

在AIDL文件中,并不是所有的数据类型都是可以使用的,那么到底AIDL文件支持哪些数据类型呢?如下所示。

  • 基本数据类型(int、long、char、boolean、double等);
  • String 和 CharSequence;
  • List:只支持ArrayList,里面每个元素都必须能够被 AIDL支持;
  • Map:只支持 HashMap,里面的每个元素都必须被 AIDL支持,包括key和 value;
  • Parcelable:所有实现了Parcelable接口的对象:
  • AIDL:所有的 AIDL接口本身也可以在 AIDL 文件中使用。

参数定向TAG:

AIDL除了基本数据类型,其他类型的参数都需要一个定向tag来指出数据的流向,不管是in,out,还是inout,基于参数的定向tag默认是并且只能是in。

  • in:表示数据只能由客户端流向服务端
  • out:表示数据只能由服务端流向客户端
  • inout:表示数据可在服务端与客户端之间双向流通

以下是AIDL的基本实现步骤和示例:

1. 创建AIDL文件

首先,在你的Android项目中创建一个AIDL文件。通常,这个文件会放在 src/main/aidl 目录下。

例如,创建一个名为 MyAidl.aidl 的文件,内容如下:

// MyAidl.aidl
package com.ex.binder1;interface MyAidl {void add();
}

2. 编写服务端实现

在服务端,你需要实现这个接口。创建一个服务类,继承 Service,并实现AIDL接口。


public class AidlService extends Service {private final Binder mbinder=new MyAidl.Stub(){@Overridepublic void add() throws RemoteException {Log.e("xxx","服务端add被调用");}};@Nullable@Overridepublic IBinder onBind(Intent intent) {return mbinder;}
}

3. 在AndroidManifest.xml中注册服务

在 AndroidManifest.xml 中注册你的服务:

  <serviceandroid:name=".aidl.AidlService"android:process=":aidltest" />

4. 客户端调用

在客户端,你需要绑定到服务并调用AIDL接口。以下是一个简单的示例:

public class AidlActivity extends AppCompatActivity {private ServiceConnection mServiceConnection=new ServiceConnection(){@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {MyAidl myAidl= MyAidl.Stub.asInterface(service);try {myAidl.add();} catch (RemoteException e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_aidl);Intent intent=new Intent(this,AidlService.class);bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);}
}

运行结果:


 

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

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

相关文章

GEE数据集:全球天然林和人工林数据集提供了一张高分辨率(30 米)地图,用于区分截至 2021 年全球的天然林和人工林

目录 简介 全球天然林和人工林 数据生成和分类 代码 引用 License 网址推荐 知识星球 机器学习 GEE数据集&#xff1a;全球天然林和人工林数据集提供了一张高分辨率&#xff08;30 米&#xff09;地图&#xff0c;用于区分截至 2021 年全球的天然林和人工林 简介 全球…

基于SpringBoot司机信用评价的货运管理系统【附源码】

基于SpringBoot司机信用评价的货运管理系统 效果如下&#xff1a; 系统主页面 系统注册页面 司机注册页面 管理员主页面 订单评价页面 货物信息页面 个人信息页面 研究背景 随着我国物流行业的迅猛发展&#xff0c;货运管理系统的效率与安全性日益受到重视。在货运过程中&am…

<项目代码>YOLOv8 煤矸石识别<目标检测>

YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv8具有更高的…

netty之实现一个redis的客户端

写在前面 本文看下如何使用redis来实现一个类似于redis官方提供的redis-cli.exe的客户端工具。 1&#xff1a;用到的模块 主要需要用到netty针对redis的编解码模块&#xff0c;可以解析redis的协议&#xff0c;从而可以实现和redis交互的功能。 2&#xff1a;正文 首先来…

Vision - 开源视觉分割算法框架 Grounded SAM2 配置与推理 教程 (1)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/143388189 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 Ground…

不用买PSP,画质甚至更好,这款免费神器让你玩遍经典游戏

作为掌机游戏爱好者的福音&#xff0c;PPSSPP模拟器为玩家带来了前所未有的PSP游戏体验&#xff0c;彻底改变了掌机游戏的体验方式。这款精湛的软件不仅完美复刻了PSP主机的游戏体验&#xff0c;更通过先进的模拟技术&#xff0c;将经典游戏提升到了全新的高度。对于那些珍藏PS…

第15课 算法(下)

掌握冒泡排序、选择排序、插入排序、顺序查找、对分查找的的基本原理&#xff0c;并能使用这些算法编写简单的Python程序。 一、冒泡排序 1、冒泡排序的概念 冒泡排序是最简单的排序算法&#xff0c;是在一列数据中把较大&#xff08;或较小&#xff09;的数据逐次向右推移的…

golang通用后台管理系统03(登录校验,并生成token)

代码 package serviceimport ("fmt"//"fmt""gin/common""gin/config"sysEntity "gin/system/entity"sysUtil "gin/system/util""github.com/gin-gonic/gin""log" )func Login(c *gin.Contex…

Java环境下配置环境(jar包)并连接mysql数据库

目录 jar包下载 配置 简单连接数据库 一、注册驱动&#xff08;jdk6以后会自动注册&#xff09; 二、连接对应的数据库 以前学习数据库就只是操作数据库&#xff0c;根本不知道该怎么和软件交互&#xff0c;将存储的数据读到软件中去&#xff0c;最近学习了Java连接数据库…

快速遍历包含合并单元格的Word表格

Word中的合并表格如下&#xff0c;现在需要根据子类&#xff08;例如&#xff1a;果汁&#xff09;查找对应的品类&#xff0c;如果这是Excel表格&#xff0c;那么即使包含合并单元格&#xff0c;也很容易处理&#xff0c;但是使用Word VBA进行查找&#xff0c;就需要一些技巧。…

「C/C++」C/C++标准库 之 #include<ctime> 时间日期库

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…

使用wordcloud与jieba库制作词云图

目录 一、WordCloud库 例子&#xff1a; 结果&#xff1a; 二、Jieba库 两个基本方法 jieba.cut() jieba.cut_for_serch() 关键字提取&#xff1a; jieba.analyse包 extract_tags() 一、WordCloud库 词云图&#xff0c;以视觉效果提现关键词&#xff0c;可以过滤文本…

深入解析缓存模式下的数据一致性问题

今天&#xff0c;我们来聊聊常见的缓存模式和数据一致性问题。 常见的缓存模式有&#xff1a;Cache Aside、Read Through、Write Through、Write Back、Refresh Ahead、Singleflight。 缓存模式 Cache Aside 在 Cache Aside 模式中&#xff0c;是把缓存当做一个独立的数据源…

ffmpeg视频滤镜:膨胀操作-dilation

滤镜介绍 dilation 官网链接 > FFmpeg Filters Documentation 膨胀滤镜会使图片变的更亮&#xff0c;会让细节别的更明显。膨胀也是形态学中的一种操作&#xff0c;在opencv中也有响应的算子。此外膨胀结合此前腐蚀操作&#xff0c;可以构成开闭操作。 开操作是先腐蚀…

多线程和线程同步基础篇学习笔记(Linux)

大丙老师教学视频&#xff1a;10-线程死锁_哔哩哔哩_bilibili 目录 大丙老师教学视频&#xff1a;10-线程死锁_哔哩哔哩_bilibili 线程概念 为什么要有线程 线程和进程的区别 在处理多任务的时候为什么线程数量不是越多越好? Linux提供的线程API 主要接口 线程创建 pth…

jeecgbootvue2菜单路由配置静态文件夹(public)下的html

需求:想要在菜单配置src/assets/iconfont/chart.html显示页面(目的是打包上线以后运维依然可以修改数据) 官网没有相关数据&#xff1a;菜单配置说明 JeecgBoot 开发文档 看云 问题现象: 我把文件放在src/assets/iconfont/chart.html然后在vue中作为 iframe 的 src 属性&am…

3种AI黑科技,让照片中的人物开口说话的简易方法,快进来学!

本文背景 用AI工作这么久了&#xff0c;我经常碰到各种关于AI的问题&#xff0c;比如制作让照片中人物开口说话的数字人。 很多小伙伴想知道是怎么弄的&#xff0c;不知从何下手。不过不用担心&#xff0c;今天就给大家带来三种实用的方法&#xff0c;快来一起试试吧。 首先是腾…

【docker compose】docker compose的hello world

安装docker desktop后在终端使用以下命令&#xff0c;代表安装成功&#xff0c;并查看当前安装的版本 docker-compose --version示例docker-compose.yml文件 version: 3.8 # 指定 Docker Compose 文件的版本services:scau_jwc: # 定义一个名为 scau_jwc 的服务image: scau_…

【js逆向学习】某多多anti_content逆向(补环境)

文章目录 声明逆向目标逆向分析逆向过程总结 声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;不提供完整代码&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的…

【C++】动态内存

一、内存区域分布 首先我们来看一段代码并尝试解决以下问题&#xff1a; 1. GlobalVar是全局变量&#xff0c;存储在数据段&#xff08;静态区&#xff09;&#xff0c;选C。2. staticGlobalVar是静态全局变量&#xff0c;也存储在数据段&#xff08;静态区&#xff09;&#x…