对付组织体中指针的一些筹商

发布日期:2022-08-07 16:47    点击次数:76
01 原因原因

在上篇文章《STM32编程中罗列和组织体的联结》中,有读者对如下代码有疑问

typedef struct{   char *name;  //姓名   int num;  //学号   int age;  //年岁   float score;  //成就 }stuff_s; stuff_s xiaoming; void xiaoming_inf_init() {   xiaoming.name = "xiaoming";   xiaoming.num = 1;   xiaoming.age = 18.0;   xiaoming.score = 100; } 

留言到

很分明,这位读者意想到了name成员是个指针,在没有对指针分派内存时,就间接复制“xiaoming”字符串,这是舛误的。先说下结论,这个是没有成就的,在下文我会详细分化下。

02 说明

首先,实际是考试真理的仅有标准,我们间接在编译器运行代码即可,这里我运用的是IAR编译,在VisualStudio中运行终局也是同样的,这里我运用IAR为例

可以或许看到,运行没有成就的,name成员被畸形赋值。这里留心name指针指向的职位地方是0x8002A5C,这是在flash的地点领域,也就是编译器间接把“xiaoming”字符串放到了flash中,作为一个常量,尔后把这个常量的指针赋给name指针,所以不消提早给name指针请求内存空间。对付STM32的内存分派,可以或许看从前推文《C言语在STM32中的内存分派》。这样写也黑白法且准确的,固然我们最意识编制如下

xiaoming.name = (char *)malloc(10); memcpy(xiaoming.name,"xiaoming",8); xiaoming.num = 1; xiaoming.age = 18.0; xiaoming.score = 100; free(xiaoming.name); 

运行终局如下

可以或许看出,name指针是指向内存的,和刚起头的代码是有区其它。那末像刚起头的写法,如下

xiaoming.name = "xiaoming"; 

编译畸形,运行畸形,在运用中有什么限定吗?答案是有的

char test_char; xiaoming.name = "xiaoming"; test_char = xiaoming.name[2]; 

这样写是准确的,test_char可以或许被准确的赋值字符a;但如下写法是舛误的

xiaoming.name = "xiaoming"; xiaoming.name[2] = 'Q'; 

这样写可以或许编译经由过程,执行的岁月也不报错,然则着实不克不迭达到编削第3个字符的目标。

本质上因为name指针指向的是Flash,可以或许经由过程上面的编制举行读取操作,然则不克不迭按上面编制举行写入操作。

假定按上面的写法,读取和写入的操作的操作都是没有成就的,因为name指针指向的是内存,具有可读可写的属性。

xiaoming.name = (char *)malloc(10); memcpy(xiaoming.name,"xiaoming",8); xiaoming.num = 1; xiaoming.age = 18.0; xiaoming.score = 100; free(xiaoming.name); 

所以日常代码编写中需求留心这些,资质荣誉我的概念是:根据上述编制,先对指针请求内存,尔后再赋值。

固然,万事没有绝对于,需求视环境而定,如下环境,你也可以间接将字符串赋给指针

确认指针不会有写入操作,只要读操作,且你觉很多加一句memcpy语句影响你的代码运行速度了。

确认指针不会有写入操作,只要读操作,且体系没有多余的内存给指针请求了。

03 const关键字

上文既然提到了只读属性,那末我们就再说一下const关键字。巨匠先看如下代码操作

typedef struct{   const char *name;  //姓名   int num;  //学号   int age;  //年岁   float score;  //成就 }stuff_s; stuff_s xiaoming; int main(void) {   xiaoming.name = (char *)malloc(10);   memcpy(xiaoming.name,"xiaoming",8);   xiaoming.name[2] = 'Q';   xiaoming.num = 1;   xiaoming.age = 18.0;   xiaoming.score = 100;   free(xiaoming.name); } 

指针name前加了const关键字,这段代码在IAR编译器中是基本编译不经由过程的。

启事很俭朴,就是因为指针name具有const属性,不克不迭被写入。

所以,在上一节最有一部份说到,当你确认指针不会有写入操作,只要读操作,你可以或许在这个指针定义前加一个const属性,因为名目代码不是你一个回护的,你策画时觉得这个指针只要读操作,就加const,这样别人举行写拜访时间接就会在IAR报错,而不会将这个潜匿的隐患遗留在产品中。

固然,上订亲义的const char *name;也是不标准的,当这个指针加了const,就该当在指针的名字中发挥阐发到,这个差别公司有差别的命名标准,每一集团也有每一集团的标准,这里不在演示了。

本文转载自微信群众号「精通编程」

【编辑推选】

Kubernetes容器平台架构解读 领取宝 App 集五福版宣布:福相伴,五福,当即到! Windows 11 22526新版修复大量成就!新特点抢先看 WiFi7有多强?比WiFi6高三倍,速度快如飞 Python再获年度编程言语,微软或成最大赢家