关于“指针成员的指针型行为或值型行为”

本文探讨了C++中深拷贝与浅拷贝的区别及其应用场景。重点介绍了指针成员在类中采取的不同行为,包括常规指针型行为、智能指针行为和值型行为,并解释了如何避免因默认拷贝构造导致的问题。

以下为论坛的讨论:

 

1.1.指针成员采取常规指针型行为.这样的类具有指针的所有缺陷但无需特殊的复制控制.
  比如如果一个有指针的类对象之间需要相互赋值,那么常规的指针型行为会使得指针指向同一个内存区域。

  2.类采取值行为.指针所指的对象是唯一的,由每个类对象独立管理.那么通过拷贝构造函数等,实现其指针独立管理各自对 象。因为每个类都定义了拷贝构造函数,赋值操作符。避免了常规指针型的错误

 

 

2.简单的说,是深拷贝和浅拷贝的问题。
一个对象里面如果有指针数据成员,默认拷贝构造函数会直接让两个指针相等。那么当其中一个对象析构后,另一个对象的指针成员岂不是dangling了

 

3.浅拷贝时,指针拷贝之后,两个指针指向同一个内存空间。(指针型行为)但是本来的目的是需要产生一个不同的内存空间并且将值拷贝进去,并用指针指向此空间(值型行为)。实现的方法需要在这个三个函数中指定。

4.1. 浅拷贝
   int *a = new int[5];
   int *b ;
   b
= a;
   delete a;
   delete b;
//出错,空间已经释放
  2. 深拷贝
   char *c = new char[5];
   char *c1 = new char[sizeof(c)];
   strcpy(c,c1);
   delete c;
   delete c1;

5.指针型行为就是浅拷贝,当调用拷贝构造函数或赋值函数时,新对象的指针成员也会指向原对象指针成员指向的地址,即所有对象中的指针是指向同一块区域的,析构时同样也会一起去释放同一个空间。这样的优点是节省空间,各对象一起管理一块内存,缺点是析构时不写控制代码很容易出现重复释放同一空间的错误。

  值型行为就是深拷贝,当调用拷贝构造函数或赋值函数时,新对象不仅有新的指针,而且会为该指针新开辟一块区域,即所有对象分别管理自己的一块数据。

 

6.大多数C++采用以下三种方法之一来管理指针成员:

  1.指针成员采取常规指针型行为。这样的类具有指针的所有缺陷但无需特殊的复制控制。
  2.类可以实现所谓的“智能指针”行为。指针所指向的对象是共享的,但类能够防止野指针。
  3.类采取值型行为。指针所指向的对象是唯一的。由每个类对象独立管理。

7.C++本质:类的赋值运算符=的重载,以及深拷贝和浅拷贝
  http://www.cnblogs.com/Winston/archive/2008/06/03/1212700.html

<think>我们讨论的问题是如何将结构体中的成员(即非指针成员)的引用转换为指针成员。换句话说,我们想要获取结构体中某个成员指针,以便可以通过指针来修改该成员。 在C语言中,结构体的成员可以是(如int, float, 数组等),也可以是指针。如果我们有一个结构体,其中某个成员,而我们想要获得指向该成员指针,我们可以使用取地址运算符`&`。 例如,假设我们有以下结构体: ```c struct Person { char name[20]; int age; }; ``` 如果有一个结构体变量`struct Person p1;`,那么: - `p1.age`是`int`类成员。 - 要获取`age`成员指针,我们可以使用`&p1.age`,这将得到一个`int*`类指针。 同样,对于`name`成员(它是一个字符数组),`p1.name`是数组名,也是数组首元素的地址(即`char*`类),所以`p1.name`本身就是一个指针(严格来说,数组名在表达式中会转换为指针,但注意数组名不是左,不能赋)。但是,如果我们想要一个指向整个数组的指针,我们可以使用`&p1.name`,这将得到一个指向长度为20的字符数组的指针,类为`char (*)[20]`。 因此,将结构体中的成员引用转换为指针成员,其实就是使用取地址运算符`&`。 下面通过一个例子详细说明: 步骤1:定义结构体 步骤2:创建结构体变量 步骤3:获取成员指针 步骤4:通过指针修改成员 示例代码: ```c #include <stdio.h> #include <string.h> struct Person { char name[20]; int age; }; int main() { struct Person p1; strcpy(p1.name, "Alice"); p1.age = 25; // 获取age成员指针 int *age_ptr = &p1.age; // 通过指针修改age *age_ptr = 30; printf("Now age is: %d\n", p1.age); // 输出30 // 获取name成员指针(注意:name是数组,所以这里获取的是数组首元素的指针) char *name_ptr = p1.name; // 等价于 &p1.name[0] // 通过指针修改name(注意:不能直接赋给数组,但可以修改内容) strcpy(name_ptr, "Bob"); // 者直接修改单个字符 name_ptr[0] = 'C'; name_ptr[1] = '\0'; // 这样name就变成了"C" printf("Now name is: %s\n", p1.name); // 输出"C" // 如果想获取指向整个数组的指针 char (*name_array_ptr)[20] = &p1.name; // 使用这个指针访问数组元素 (*name_array_ptr)[0] = 'D'; (*name_array_ptr)[1] = 'a'; (*name_array_ptr)[2] = 'n'; (*name_array_ptr)[3] = '\0'; printf("Now name is: %s\n", p1.name); // 输出"Dan" return 0; } ``` 注意事项: 1. 对于数组类成员(如`char name[20]`),数组名在大多数情况下会退化为指向其首元素的指针(即`char*`),但使用`&`运算符作用于数组名时,会得到指向整个数组的指针(类为`char (*)[20]`)。 2. 通过指针修改结构体成员时,要确保指针正确,以避免未定义行为。 3. 如果结构体成员是另一个结构体(),同样可以使用`&`获取其指针。 引用说明: 在引用[2]中提到:结构体成员studentName(字符数组)的名字代表字符数组的首地址,是一个常量,不能作为赋表达式的左。这解释了为什么我们不能对整个数组赋(例如:`p1.name = "Alice";`是非法的),但我们可以使用`strcpy`者通过指针修改数组内容。 引用[3]说明了指针引用的本质:机器码只是按照指令从内存地址取,不管该地址是否有定义的结构体。因此,我们通过取地址运算符得到结构体成员指针,然后通过指针访问,是合法的,只要该结构体变量是存在的。 因此,将结构体中的成员引用转换为指针成员,只需使用`&`运算符(对于数组,数组名本身就可以作为指针使用,但注意数组名的类)。 相关问题: 1. 如何通过指针修改结构体中的数组成员? 2. 结构体成员指针和整个结构体的指针有什么关系? 3. 如何避免通过指针修改结构体成员时出现的内存越界问题? 4. 在函数中如何通过结构体成员指针来修改原始结构体? </think>### 如何在结构体中将成员引用转换为指针成员 在C语言中,当结构体成员定义为(非指针)时,可以通过取地址操作符`&`获取其内存地址,实现成员指针的转换。以下是详细步骤和原理: #### 核心原理 1. **成员**:直接存储数据的成员(如 `int age;`) 2. **指针转换**:使用取地址符 `&` 获取成员的内存地址 3. **类匹配**:指针必须与成员一致(如 `int` 成员对应 `int*` 指针) #### 操作步骤 1. **定义结构体**: ```c struct Person { char name[20]; // 成员(字符数组) int age; // 成员(整) }; ``` 2. **获取成员指针**: ```c struct Person p1 = {"Alice", 25}; // 转换成员指针 char *name_ptr = p1.name; // 数组名即首地址指针 int *age_ptr = &p1.age; // 使用 & 获取整成员地址 ``` 3. **通过指针修改成员**: ```c // 修改字符数组成员(需用strcpy) strcpy(name_ptr, "Bob"); // 直接修改整成员 *age_ptr = 30; ``` #### 完整示例 ```c #include <stdio.h> #include <string.h> struct Person { char name[20]; int age; }; void modify_member(struct Person *p) { // 将成员转为指针操作 char *name_ptr = p->name; int *age_ptr = &p->age; strcpy(name_ptr, "Charlie"); *age_ptr = 35; } int main() { struct Person p1 = {"Alice", 25}; printf("原始: %s, %d\n", p1.name, p1.age); // 通过函数修改(传结构体指针) modify_member(&p1); printf("修改后: %s, %d\n", p1.name, p1.age); return 0; } ``` #### 关键注意事项 1. **数组类成员**: - 字符数组名 `name` 本身就是指针(类 `char*`) - 可直接赋指针变量,无需 `&` 操作符[^2] ```c char *ptr = p1.name; // 正确(等价于 &p1.name[0]) ``` 2. **非数组成员**: - 必须使用 `&` 获取地址 - 指针需严格匹配成员 ```c int *age_ptr = &p1.age; // int成员 -> int*指针 ``` 3. **内存安全**: - 确保指针指向有效的结构体实例 - 避免指针越界访问(尤其操作数组时)[^3] 4. **结构体指针参数**: - 函数接收结构体指针(`struct Person *p`) - 避免传递导致副本修改无效[^1] #### 典应用场景 1. 跨函数修改结构体成员 2. 实现类似面向对象的成员方法 3. 内存映射硬件寄存器(通过指针直接操作硬件) --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值