【进阶C语言】动态内存分配
本章大致内容介绍:
1.malloc函数和free函数
2.calloc函数
3.realloc函数
4.常见错误案例
5.笔试题详解
6.柔性数组
一、malloc和free
1.malloc函数
(1)函数原型
函数参数:根据用户的需求需要开辟多大的字节空间,为无符号的字节。
返回值:malloc函数成功开辟内存后,会返回该内存的起始地址,可以根据需要强制转换成任意的类型;若开辟空间失败,则会返回空指针(NULL)。
头文件:#include<stdlib.h>
(2)使用方法
1)申请空间:
#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = (int*)malloc(40);return 0;
}
目的:申请十个整形空间,所以参数传:4*10=40。
结果:用一个整形指针来接收其返回值
2)检查安全和使用
#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = (int*)malloc(40);if (p == NULL)//必须对指针安全性检查{printf("申请空间失败\n");return;}//申请成功就开始用int i = 0;for (i=0;i<10;i++){*(p+i) = i;}i = 0;for (i=0;i<10;i++){printf("%d\n",*(p+i));}return 0;
}
当使用结束之后,我们需要删除该动态生成的空间,则需要对空间进行释放,这就是我们接下来讲的free。
2.free函数
(1)函数原型
1.参数为动态开辟内存的首地址
2.无参数返回
3.头文件#include<stdlib.h>
(2)配合动态内存开辟的函数使用
前面malloc函数开辟的内存还没释放,接下来它们配合使用。
#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = (int*)malloc(40);if (p == NULL){printf("申请空间失败\n");return;}//申请成功就开始用int i = 0;for (i=0;i<10;i++){*(p+i) = i;}i = 0;for (i=0;i<10;i++){printf("%d\n",*(p+i));}free(p);p = NULL;//及时将指针置空return 0;
}
注意事项:
1.free只能释放由动态内存开辟的空间
2.free释放的是指针所指向的那块空间,释放后指针仍在,但是指向的空间不咋了,就会变成野指针,所以我们需要及时置空。
二、calloc
1.函数定义
函数参数:第一个参数是需要开辟的数据个数,第二个是该数据类型的内存大小。
返回值:calloc函数成功开辟内存后,会返回该内存的起始地址,可以根据需要强制转换成任意的类型;若开辟空间失败,则会返回空指针(NULL)。
头文件:#include<stdlib.h>
2.calloc的使用
目的:需要开辟10个整形空间
#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = (int*)calloc(10,sizeof(int));if (p == NULL){printf("申请空间失败\n");return;}//申请成功就开始用int i = 0;for (i = 0; i < 10; i++){*(p + i) = i;}i = 0;for (i = 0; i < 10; i++){printf("%d\n", *(p + i));}free(p);p = NULL;//及时将指针置空return 0;
}
运行结果:
根据malloc和calloc函数使用的两段代码,好像除了名字和参数之外,其他没什么不同呀?其实他们还有一处区别。
3.calloc函数与malloc函数的区别
(1)区别
malloc函数开辟好空间之后,并不会对其初始化,但是calloc函数开辟好空间之后,会将数据的每一个字节都初始化成0。
(2)对照
1)malloc
2)calloc
除了以上三点不同之外,其他的都一样。所以我们需要根据内存需求,需不需要初始化内存而选择合适的开辟方式。
三、realloc
1.函数定义
realloc可以对已有的内存进行调整
函数参数:ptr是要调整的内存地址,size为内存调整之后的新大小,单位是内存总大小(字节)
返回值:内存调整后的起始地址,同样有申请内存成功和失败两种情况
头文件:#include<stdlib.h>
2.realloc申请空间成功的两种情况
(1)原空间后的空间足够大
开辟空间方式:直接原有内存之后直接追加空间,原来空间的数据不发生变化。
(2)原空间之后没有足够大的空间
原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小
的连续空间来使用。这样函数返回的是一个新的内存地址。而原有数据也会被拷贝到新内存中。
3.realloc的使用
#include<stdio.h>
#include<stdlib.h>
int main()
{int* p = (int*)calloc(10,sizeof(int));if (p == NULL){printf("申请空间失败\n");return;}//申请成功就开始用int i = 0;for (i = 0; i < 10; i++){*(p + i) = i;}i = 0;for (i = 0; i < 10; i++){printf("%d\n", *(p + i));}//要求加大空间内存int* ptr = realloc(p,40*sizeof(int));if (ptr == NULL){printf("内存开辟失败\n");return;}p = ptr;//将新开辟好的内存赋值原地址free(p);p = NULL;//及时将指针置空return 0;
}
realloc的使用一般在原有空间的情况下,同样也需要对指针进行判空操作和free。
我们也可以看到,free和这些函数是紧紧联系在一起的。
四、常见错误解析
这些错误都是动态内存开辟前后的问题,与指针也有很大的联系
1.对NULL指针的解引用操作
错误写法:
int main()
{int* p = (int*)malloc(4);*p = 20;printf("%d\n",*p);return 0;
}
malloc有可能开辟动态内存失败,则会返回NULL,这个时候对NULL指针解引用操作就是非法的。
正确写法:
int main()
{int* p = (int*)malloc(4);*p = 20;if (p == NULL)//对指针安全性限制{perror(malloc);return;}printf("%d\n",*p);
//后续需要对内存释放return 0;
}
知识点1:在每次动态内存开辟完成之后,都要先对其指针进行判空操作;若非空,才能对其进行后续的操作。
2.对动态开辟空间的越界访问
错误写法:
int main()
{int i = 0;int* p = (int*)malloc(10 * sizeof(int));if (NULL == p){exit(EXIT_FAILURE);}for (i = 0; i <= 10; i++){*(p + i) = i;//当i是10的时候越界访问}free(p);
}
错误的后果提示:
知识点2:在对指针解引用操作时,要注意指针所指向的个数
3.对非动态开辟内存使用free释放
错误写法:
test()
{int a = 100;int* p = &a;free(p);//错误
}
知识点3:free函数只能释放动态开辟的内存,否则会非法。
4.使用free释放一块动态开辟内存的一部分
错误写法:
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
当p++之后,p指向的起始位置就变了,当free(p)之后,会释放不完整,也会造成内存泄漏。
知识点4:使用指针,尽量不要改变指针指向的起始地址。可以再重新使用新指针进行++或--操作;或者+1/-1操作。
5.对同一块动态内存多次释放
错误写法:
void test()
{
int *p = (int *)malloc(100);
free(p);
free(p);//重复释放
}
知识点5:切记要对内存释放,但是每一块内存有且只能释放一次。
6.动态开辟内存忘记释放(内存泄漏)
错误:
void test()
{
int *p = (int *)malloc(100);
if(NULL != p)
{
*p = 20;
}
}
int main()
{
test();
while(1);
}
这是忘记对动态内存的释放的,也是不可取的。
五、关于动态内存开辟的笔试题
分析下面四道代码题存在什么问题
运行Test函数会有什么样的后果
1.对NULL解引用操作
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
1.str指针为空
2.malloc开辟的空间只是被p指向,没有被str指向(相当于形参的改变不影响实参)
3.所以strcpy函数就会对NULL指针进行解引用操作
4.没有free操作,还会操作内存泄漏
图解:
正确写法:
void GetMemory(char** p)
{*p = (char*)malloc(100);
}
void Test(void)
{char* str = NULL;GetMemory(&str);strcpy(str, "hello world");printf(str);free(str);str=NULL;
}
2.
问题代码:
char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
1.字符数组p为栈空间的局部变量,函数返回后会被销毁
2.数组被销毁,返回的p就是野指针(所指向的空间已不属于自己)
类型代码情况:
int* test()
{int a = 10;return &a;
}
int main()
{int* p = test();printf("%d\n",*p);return 0;
}
这种运行的结果仍然可以得到10,虽然空间依然属于p,但是值仍在,没有被其他的数据覆盖。但是下面这种情况则不行。
3.题目3
问题代码:
void GetMemory(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
动态开辟的内存,最后没有被free释放
4.
问题代码:
void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, "hello");
free(str);
if(str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
1.str所指向的空间已被销毁
2.str变成野指针,对其解引用操作为非法
六、柔性数组
1.柔性数组的定义
标准定义:C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。
也就是说,柔性数组不是指简单的数组,而是在结构体中的数组。
有两种写法:
第一种:
typedef struct st_type
{
int i;
int a[0];//柔性数组成员
}type_a;
a数组就称为柔性数组。但是这种定义方式容易报错,所以我们还有第二种。
第二种:
typedef struct st_type
{
int i;
int a[];//柔性数组成员
}type_a;
就是不需要指定数组的大小,数组的大小是未知的。
2.柔性数组的特点
(1)sizeof 返回的这种结构大小不包括柔性数组的内存。
(2)结构中的柔性数组成员前面必须至少一个其他成员。
因为柔性数组是不计入sizeof的计算的,只有柔性数组成员sizeof就会出错。
(3)包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
在计算包含柔性数组的结构体时,柔性数组是不计入内存的计算的。大于结构体内存大小的部分就会分配给柔性数组。
(4)代码验证
struct S
{int a;int arr[];
};
int main()
{struct S s;printf("%zd\n",sizeof(s));//计算该结构体的内存大小return 0;
}
运行的结果:
柔性数组确实是不会参加sizeof对结构体的计算
3.柔性数组的使用
(1)开辟空间
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct S
{int a;int arr[];
};
int main()
{struct S* ps=(struct S*)malloc(sizeof(struct S)+16);if (ps == NULL){perror(malloc);return;}return 0;
}
(2)增容(realloc函数)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct S
{int a;int arr[];
};
int main()
{struct S* ps=(struct S*)malloc(sizeof(struct S)+16);if (ps == NULL){perror(malloc);return;}struct S* str = (struct S*)realloc(ps,sizeof(struct S)+40);if (str != NULL){ps = str;}else{perror(realloc);return;}return 0;
}
用malloc开辟空间之后,再用reallo增容(减容)。增容之后的空间都会加在柔性数组上,这个时候数组的大小就可以根据realloc变化,因此称为柔性数组。
4.柔性数组的优势
(1)方便内存释放
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct S
{int a;int arr[];//定义一个柔性数组
};
int main()
{struct S* ps=(struct S*)malloc(sizeof(struct S)+16);if (ps == NULL){perror(malloc);return;}struct S* str = (struct S*)realloc(ps,sizeof(struct S)+40);if (str != NULL){ps = str;}else{perror(realloc);return;}free(ps);ps = NULL;return 0;
}
因为开辟的空间都是连续的,在一块内存中,所以只需要free一次即可。
我们再对比一下另一种写法就更加明显了。
结构体中有指针的写法:
struct S
{char c;int i;int* data;//定义一个指针
};
int main()
{struct S* ps = (struct S*)malloc(sizeof(struct S));if (ps == NULL){perror("malloc1");return 1;}ps->c = 'w';ps->i = 100;ps->data = (int*)malloc(20);if (ps->data == NULL){perror("malloc2");return 1;}int i = 0;for (i = 0; i < 5; i++){ps->data[i] = i;}for (i = 0; i < 5; i++){printf("%d ", ps->data[i]);}//空间不够了,增容int* ptr = (int*)realloc(ps->data, 40);if (ptr == NULL){perror("realloc");return 1;}else{ps->data = ptr;}//增容成功就使用//...//释放free(ps->data);//第一次ps->data = NULL;free(ps);//第二次ps = NULL;return 0;
}
1.两次开辟空间的原因是使得他们的数据都开辟在堆区上
2.使得跟第一种一样的写法,突然第一种的优势
3.这种写法开辟的空间是不连续的,容易造成空间零碎空间,导致空间浪费。
(2)有利于访问速度和节约内存
连续的内存有益于提高访问速度,也有益于减少内存碎片,更大程度的利用内存空间。
相关文章:
【进阶C语言】动态内存分配
本章大致内容介绍: 1.malloc函数和free函数 2.calloc函数 3.realloc函数 4.常见错误案例 5.笔试题详解 6.柔性数组 一、malloc和free 1.malloc函数 (1)函数原型 函数参数:根据用户的需求需要开辟多大的字节空间ÿ…...
手机上记录的备忘录内容怎么分享到电脑上查看?
手机已经成为了我们生活中不可或缺的一部分,我们用它来处理琐碎事务,记录生活点滴,手机备忘录就是我们常用的工具之一。但随着工作的需要,我们往往会遇到一个问题:手机上记录的备忘录内容,如何方便地分享到…...
LeetCode 2251. 花期内花的数目:排序 + 二分
【LetMeFly】2251.花期内花的数目:排序 二分 力扣题目链接:https://leetcode.cn/problems/number-of-flowers-in-full-bloom/ 给你一个下标从 0 开始的二维整数数组 flowers ,其中 flowers[i] [starti, endi] 表示第 i 朵花的 花期 从 st…...
【3】贪心算法-最优装载问题-加勒比海盗
算法背景 在北美洲东南部,有一片神秘的海域,那里碧海蓝天、阳光 明媚,这正是传说中海盗最活跃的加勒比海(Caribbean Sea)。 有一天,海盗们截获了一艘装满各种各样古董的货船,每一 件古董都价值连…...
JavaScript 的 for 循环应该如何学习?
JS for 循环语法 JS for 循环适合在已知循环次数时使用,语法格式如下: for(initialization; condition; increment) {// 要执行的代码 }for 循环中包含三个可选的表达式 initialization、condition 和 increment,其中: initial…...
C++核心编程--对象篇
4.2、对象 4.2.1、对象的初始化和清理 用于对对象进行初始化设置,以及对象销毁前的清理数据的设置。 构造函数和析构函数 防止对象初始化和清理也是非常重要的安全问题 一个对象或变量没有初始化状态,对其使用后果是未知的同样使用完一个对象或变量&…...
安装php扩展XLSXWriter,解决php导入excel表格时获取日期变成浮点数的方法
安装php扩展XLSXWriter 1、下载安装包 PECL :: Package :: xlswriter #例如选择下载1.3.6版本 2、解压下载包 tar -zxvf xlswriter-1.3.6.tgz 3、进入文件夹,编译 cd xlswriter-1.3.6 phpize ./configure --with-php-config=/usr/local/php7.1/bin/php-config make&am…...
Vue+element开发Simple Admin后端管理系统页面
最近看到各种admin,头大,内容太多,根本不知道怎么改。所以制作了这个项目,只包含框架、和开发中最常用的表格和表单,不用自己从头搭建架构,同时也容易上手二次开发。可以轻松从其他开源项目整合到本项目。项…...
源码编译安装pkg-config
安装环境:银河麒麟 1 到这个网址下载pkg-config源码: Index of /releases (pkg-config.freedesktop.org) 2 解压 3 进入解压后的目录。输入 ./configure 但是报错。 4 根据报错信息,将configure改为: ./configure --with-i…...
游览器找不到服务器上PHP文件的一种原因
最近在练习搭建网站,遇到游览器找不到服务器上的php文件的问题。后来查找发现,apache文档根目录跟apache虚拟主机文档根目录不同,服务器开启了虚拟主机功能。这导致游览器找不到php文件。使用的环境LAMP 里操作系统和软件版本如下:…...
C++之std::function的介绍
C之std::function的介绍 std::function和函数指针的区别介绍std::function 的常见用法包括用法举例 std::function和函数指针的区别介绍 std::function 和函数指针在 C 中都可以用来存储和调用函数,但它们的使用方式和功能有所不同。 函数指针是一种指向函数的指针…...
卷积神经网络学习(一)
CNN应用对象是图像,CNN可被应用于的任务: 1、分类(classification):对图像按其中的物体进行分类,如图像中有人与猫,则图像可分为两类。 2、目标检测(object detection)&a…...
使用KEIL自带的仿真器仿真遇到问题解决
*** error 65: access violation at 0x40021000 : no read permission 修改debug选项设置为下方内容。...
4700 万美元损失,Xn00d 合约漏洞攻击事件分析
4700 万美元损失,Xn00d 合约漏洞攻击事件分析 基础知识 ERC777 ERC777 是 ERC20 标准的高级代币标准,要提供了一些新的功能:运营商及钩子。 运营商功能。通过此功能能够允许第三方账户代表某一合约或者地址 进行代币的发送交易钩子功能。…...
第5讲:v-if与v-show的使用方法及区别
v-if条件判断 v-if是条件渲染指令,它根据表达式的真假来删除和插入元素,它的基本语法如下: v-if “expression” expression是一个返回bool值的表达式,表达式可以是一个bool属性,也可以是一个返回bool的运算式 &#…...
C理解(一):内存与位操作
本文主要探讨C语言的内存和为操作操作相关知识。 冯诺依曼结构和哈佛结构 冯诺依曼结构:数据和代码放在一起,便于读取和修改,安全性低 哈佛结构是:数据和代码分开存放,安全性高,读取和修麻烦 内存 内存是用来存储全局变量、局…...
ESP8266使用记录(四)
放上最终效果 ESP8266&Unity游戏 整合放进了坏玩具车遥控器里 最终只使用了mpu6050的yaw数据,因为roll值漂移…… 使用了https://github.com/ElectronicCats/mpu6050 整个流程 ESP8266取MPU6050数据,处理后通过udp发送给Unity显示出来 MPU6050_Z…...
云原生Kubernetes:K8S安全机制
目录 一、理论 1.K8S安全机制 2.Authentication认证 3.Authorization授权 4.Admission Control准入控制 5.User访问案例 6.ServiceAccount访问案例 二、实验 1.Admission Control准入控制 2.User访问案例 3.ServiceAccount访问案例 三、问题 1.生成资源报错 2.镜…...
【数据结构】归并排序、基数排序算法的学习知识点总结
目录 1、归并排序 1.1 算法思想 1.2 代码实现 1.3 例题分析 2、基数排序 2.1 算法思想 2.2 代码实现 2.3 例题分析 1、归并排序 1.1 算法思想 归并排序是一种采用分治思想的经典排序算法,通过将待排序数组分成若干个子序列,将每个子序列排序ÿ…...
【C++】C++模板进阶 —— 非类型模板参数、模板的特化以及模板的分离编译
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:C学习 🎯长路漫漫浩浩,万事皆有期待 上一篇博客:【C】C多…...
HTML的相关知识
1.什么是HTML?基本语法 HTML: Hyper Text Markup Language (超文本标记语言) 超文本?超级文本,例如流媒体,声音、视频、图片等。 标记语言?这种语言是由大量的标签组成。HTML标签参考手…...
基于微信小程的流浪动物领养小程序设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言系统主要功能:具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…...
Java后端接口编写流程
💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! Java后端接口编写流程 Java后端接口编写流程,更具业务逻辑编写Java后端接口,提供给前端访问 实现逻辑流程 POJO:实体类编写 Data B…...
【问题记录】解决“命令行终端”和“Git Bash”操作本地Git仓库时出现 中文乱码 的问题!
环境 Windows 11 家庭中文版git version 2.41.0.windows.1 问题情况 在使用 “命令行终端” 和 “Git Bash” 在本地Git仓库敲击命令时,对中文名称文件显示一连串的数字,如下所示:这种情况通常是由于字符编码设置不正确所引起的 解决办法 设置…...
软考高级之系统架构师之软件需求工程
概述 一个完整的软件生存周期是以需求为出发点。软件需求是指用户对系统在功能、行为、性能、设计约束等方面的期望。 需求开发: 需求获取需求分析需求定义(需求规格说明书)需求验证 需求管理: 变更控制版本控制需求跟踪需求状态跟踪 需…...
使用 Velocity 模板引擎的 Spring Boot 应用
使用 Velocity 模板引擎的 Spring Boot 应用 模板引擎是构建动态内容的重要工具,特别适用于生成HTML、邮件内容、报告和其他文本文档。Velocity是一个强大的模板引擎,它具有简单易用的语法和灵活性。本文将介绍如何在Spring Boot应用中使用Velocity模板…...
mysql的mvcc详解
一 MVCC的作用 1.1 mvcc的作用 1.MVCC(Multiversion Concurrency Control)多版本并发控制。即通过数据行的多个版本管理来实现数据库的并发控制,使得在InnoDB事务隔离级别下执行一致性读操作有了保障。 2.mysql中的InnoDB中实现了MVCC主要…...
FreeRTOS两个死机原因(中断调用接口异常)【杂记】
1、中断回调函数中没有使用中断级API (xxFromISR) 函数 xSemaphoreGiveFromISR(uart_busy,&HighterTask);----正确 xSemaphoreGive(uart_busy);-----错误2、比configMAX_SYSCALL_INTERRUPT_PRIORITY优先级高的中断函数中使用了FreeRTOS的函数 3、临界代码保护后不可调用os…...
【AI视野·今日Robot 机器人论文速览 第四十三期】Thu, 28 Sep 2023
AI视野今日CS.Robotics 机器人学论文速览 Thu, 28 Sep 2023 Totally 37 papers 👉上期速览✈更多精彩请移步主页 Interesting: 📚****触觉力控学习策略,基于触觉的主动推理与力控用于小孔插入任务。提出了姿态控制与插入控制双策略模型。 (from 东京大学…...
批量快捷创建新数组的几种方式
1. for循环, push(比较简单, 就不上代码了) 2.创建空数组,填充null,然后map: function createData() { return new Array(1000) .fill(null) .map((v,i)>({name: name${i1}})) } console.log(createData()) 3.Array.frommap function createData() { return Array.from…...
wordpress改网页电话/软件培训机构排行榜
【小白从小学Python、C、Java】 【Python-计算机等级考试二级】 【Python-数据分析】 定义一个方法,作用到对象上获取对应索引的值 operator.itemgetter() [太阳]选择题 请问对以下Python代码说法错误的是? from operator import itemgetter #定义方法&a…...
江阴市做网站的/如何写好一篇软文
目录写在前面正文同步FIFO回顾异步FIFO设计参考资料交个朋友写在前面一开始是想既然是极简教程,就应该只给出FIFO的概念,没想到还是给出了同步以及异步FIFO的设计,要不然总感觉内容不完整,也好,自己设计的FIFO模块不用…...
wordpress本地添加图片不显示图片/站内推广有哪些具体方式
本地方法栈 Java虚拟机栈于管理Java方法的调用,而本地方法栈用于管理本地方法的调用。 本地方法栈,也是线程私有的。 允许被实现成固定或者是可动态扩展的内存大小。(在内存溢出方面是相同的) 如果线程请求分配的栈容量超过本…...
自己做物流网站/域名买卖交易平台
在本文中,我将向你展示如何使用ASP.NET AJAX框架对添加可点击的热点的HTML Map控件进行扩展。经扩展后,当我们的鼠标移动到这些热点上后,即弹出关于这些热点的详细信息;但是,这些详细信息都是通过AJAX异步方式从远程服务中取得的。…...
镇江网站建设联系思创/sem是什么电镜
在总部位于新加坡的员工福利初创公司CXA Group对我们的核心Web平台进行评估的过程中,我们决定将方向从陈旧的现有体系结构转向,从头开始重建前端。 该平台面临的挑战之一是创建一个在CXA Group的12个目标国家/地区(在整个亚洲)都能…...
婚纱设计网站首页/电话营销系统
面试中最难回答的一个问题:你的优点和缺点分别是什么? 面对这个问题,很多人自作聪明的会把自己的优点当做缺点去说,比如:我最大的优点是认真,我最大的缺点就是太认真了。 这么回答只会让面试官觉得你是在装…...