NULL指针解引用出错

本文深入探讨了C语言中NULL指针的概念及其重要性,包括NULL指针的定义、如何避免因解引用NULL指针而导致程序崩溃的问题,并介绍了NULL在不同场景下的正确使用方法。

转自:点击打开链接

一般导致程序崩溃的最重要原因之一就是试图解引用NULL指针。只要对NULL指针解引用,程序就会崩溃

在C语言中对void *指针进行解引用会造成编译错误

在C语言的头文件stddef.h中,NULL的定义如下:
#define NULL
#define __cplusplus  //如果定义了__cplusplus表示是c++程序
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
#interface NULL 0
所以,c语言里NULL的本质是(void *)0。

((void *)0)  本质上是将数字0强制转换为(void *)。0其实就是地址,(void *)只是说我们认为0这个地址中存储的类型是void *,也就是说0这个地址中存储的类型是void*,也就是当前不知道还未指定的.

例如 char i=2;这里的2本身这个数字就是表示地址,不能理解成2存在一个变量中,所以想通过char i=&2去取2的地址,这个是错误的。因为只有变量才有地址,2只是个数字是没有地址的。
因为这个数字我们要把它强制类型转化成指针,所以这个数字就是地址。

C语言中就通过类型来表示这个单元中存的什么玩意,譬如(int)0就表示0地址中存的是int型的数;譬如你(int *)0就表示0地址中存的是个地址,这个地址指向的单元是int型数

NULL只是一个概念,叫作空值,其值本身没有任何含义,可以用0代替,也可以用1,...代替,只要这些值不会与系统实际的有效地址冲突即可。 
因此,在此强调,不要自作聪明地认为NULL就是0,要判断的时候还是老老实实地与NULL做比较,别想当然地用什么!ptr之类的写法,因为在某个特定环境下,NULL可能不是0,而系
统函数返回的是NULL不是0时,你的函数就会出现莫名其妙的错误。所以,养成良好的习惯是非常重要的。
注意:

c语言中NULL表示内存位置0,NULL((void *)0)指针并不指向任何对象。因此除非是用于赋值或比较运算,出于其他任何目的使用NULL指针都是非法的。

在ASCII码的第一个字符是NULL,它的数值是0,占用1字节;C语言把它('\0')作为字符串的最后一个字符,以表示字符串到此结束.

第一:指针初始化(对应于上面的赋值)。

例如 int *x = NULL;

第二:函数返回是否成功判断(对应于做比较运算)。

当函数返回值为指针时,判断函数是否返回成功。举例如下:

FILE * pFile;
pFile = fopen ("myfile.txt" , "r");
if (pFile == NULL) printf("open error");

第三:判断字符串是否为空字符串(对应于做比较运算)。

 

不管是字符串还是字符数组,安全起见,首先要判断指向该字符串或字符数组的指针是否为空,然后在判断首个字符是否为空。典型的做法如下:
char* s = "Blah-blah";
// ... other operations on s
if (s==NULL || s[0]=='\0') //写成if(s==NULL || strlen(s)<=0)会更好
   // ... 哦,空的





<think>首先,用户的问题是:“我想理解并区分C/C++中解引用和成员指针访问的操作 请问C/C++ 解引用指针与成员指针访问的区别及使用方法”。这是一个关于C/C++编程语言的问题,涉及指针操作。 关键点: - 解引用指针:使用操作符`*`来获取指针指向的值。 - 成员指针访问:使用操作符`->`来访问指针所指向对象的成员(如成员变量或成员函数)。 我需要参考系统提供的引用: - 引用[1]:讨论了Java引用和C/C++指针的区别,强调指针可以指向任意地址,而引用更安全。 - 引用[2]:关于C/C++指针运算访问类成员变量。 - 引用[3]:避免空指针解引用的方法。 - 引用[4]:引用和指针的区别,提到指针传递是值传递,但传递地址。 这些引用提供了背景信息,但用户的问题具体是关于解引用和成员指针访问的区别和使用方法。 我的回答需要: - 使用中文。 - 结构清晰,逐步解决问题。 - 确保真实可靠。 - 在行内数学表达式中使用`$...$`格式(但在这个上下文中,可能没有数学表达式,主要是代码)。 - 独立公式使用`$$...$$`(但这里可能不适用)。 - 生成相关问题。 - 在引用的段落末尾添加引用标识。 回答结构: 1. **介绍**:简要解释解引用和成员指针访问。 2. **区别**:详细比较两者的操作符、用法和场景。 3. **使用方法**:提供代码示例说明如何正确使用。 4. **常见错误**:讨论潜在问题,如空指针解引用。 5. **总结**:强调关键点。 6. **相关问题**:生成一些相关问题。 参考引用: - 在解释时,可以自然地引用提供的材料。例如,当讨论空指针解引用时,引用[3]。 - 引用[2]讨论了指针运算访问成员变量,这相关。 - 引用[4]提到指针传递,这有助于理解指针的本质。 内容大纲: - **解引用指针**: - 操作符:`*` - 示例:`int x = 10; int *ptr = &x; int y = *ptr;` // y gets 10 - 用于获取指针指向的值。 - **成员指针访问**: - 操作符:`->` - 示例:`struct Person { int age; }; Person p; Person *ptr = &p; ptr->age = 30;` - 用于通过指针访问对象的成员。 - **区别**: - `*ptr` 用于获取整个对象或值。 - `ptr->member` 等价于 `(*ptr).member`,是简写形式。 - 使用场景:当指针指向结构体、类等复合类型时,使用`->`更方便。 - **使用方法**: - 在C++中,对于类对象,使用`->`调用成员函数或访问成员变量。 - 避免空指针:在解引用或访问成员前检查指针是否为NULL/nullptr。 - **常见错误**: - 空指针解引用:可能导致崩溃。参考引用[3]。 - 错误使用操作符:如用`.`代替`->`。 - **代码示例**:提供简单的代码片段。 生成相关问题: 1. 如何避免C/C++中的空指针解引用? 2. 指针和引用在C++中有什么区别? 3. 在C++中,如何使用指针访问类的成员函数? 4. 指针运算在访问数组元素时如何工作? 确保回答真实可靠:基于标准C/C++知识。</think>### C/C++ 解引用指针与成员指针访问的区别及使用方法 在 C/C++ 中,指针操作是核心概念,理解解引用(dereferencing)和成员指针访问(member access via pointer)的区别至关重要。这些操作涉及不同的操作符和场景,下面我将逐步解释两者的定义、区别、使用方法,并提供代码示例。内容基于标准 C/C++ 规范,确保真实可靠。 #### 1. **基本定义和操作符** - **解引用指针**: - 使用操作符 `*` 来获取指针指向的实际值。 - 语法:`*pointer`。 - 适用于所有指针类型(如基本类型、结构体、类对象)。 - 示例:`int x = 10; int *ptr = &x; int y = *ptr;` // y 的值是 10。 - **成员指针访问**: - 使用操作符 `->` 来直接访问指针所指向对象的成员(成员变量或成员函数)。 - 语法:`pointer->member`。 - 仅当指针指向结构体(struct)或类(class)对象时使用。 - 示例:`struct Person { int age; }; Person p; Person *ptr = &p; ptr->age = 30;` // 设置 p 的 age 为 30。 #### 2. **核心区别** 两者的主要区别在于操作符、语义和使用场景: | 方面 | 解引用 (`*`) | 成员指针访问 (`->`) | |------|--------------|---------------------| | **操作符** | 一元操作符 `*` | 箭头操作符 `->` | | **作用** | 获取指针指向的完整对象或值 | 直接访问对象的成员,无需先获取整个对象 | | **等价形式** | 无直接等价 | `ptr->member` 等价于 `(*ptr).member`(即先解引用,再用 `.` 访问成员) | | **适用类型** | 任何指针类型(如 `int*`, `float*`, 对象指针) | 仅限指向结构体或类对象的指针 | | **常见错误** | 空指针解引用导致崩溃(如 `*nullptr`) | 空指针访问成员同样崩溃(如 `nullptr->member`) | | **性能影响** | 无额外开销 | 与 `(*ptr).member` 相同,编译器优化后通常无差异 | 关键点: - `->` 是语法糖(syntactic sugar),简化了通过指针访问成员的过程。例如,`ptr->age` 避免了写 `(*ptr).age` 的冗余。 - 解引用是基础操作,而成员指针访问依赖于解引用。在底层,`ptr->member` 被编译器转换为 `(*ptr).member`。 - 指针传递本质是值传递(传递地址),但对形参解引用或成员访问会影响实参对象[^4]。 #### 3. **使用方法与代码示例** 正确使用这些操作需要避免空指针类型错误。以下是详细示例: **示例 1: 基本类型解引用** ```c #include <stdio.h> int main() { int num = 5; int *ptr = &num; // ptr 指向 num 的地址 *ptr = 10; // 解引用并修改值 printf("num = %d\n", num); // 输出: num = 10 return 0; } ``` - 这里,`*ptr` 解引用获取 `num` 的值并修改它。 **示例 2: 结构体成员指针访问** ```c #include <stdio.h> typedef struct { int id; char name[20]; } Student; int main() { Student s = {1, "Alice"}; Student *ptr = &s; printf("ID: %d, Name: %s\n", ptr->id, ptr->name); // 使用 -> 访问成员 ptr->id = 2; // 修改成员值 return 0; } ``` - `ptr->id` 直接访问成员,等同于 `(*ptr).id`。 **示例 3: 类对象在 C++ 中的使用** ```cpp #include <iostream> using namespace std; class Car { public: int speed; void accelerate() { speed += 10; } }; int main() { Car myCar; Car *carPtr = &myCar; carPtr->speed = 60; // 使用 -> 访问成员变量 carPtr->accelerate(); // 使用 -> 调用成员函数 cout << "Speed: " << carPtr->speed << endl; // 输出: Speed: 70 return 0; } ``` - `->` 简化了通过指针调用成员函数和访问变量的过程。 **注意事项**: - **空指针检查**:在解引用或成员访问前,始终验证指针有效性。例如: ```c if (ptr != nullptr) { *ptr = 100; // 安全解引用 ptr->member = value; // 安全成员访问 } ``` 空指针解引用是常见错误,可能导致程序崩溃[^3]。 - **指针运算**:指针运算(如 `ptr + offset`)可用于访问数组或类成员,但需谨慎对齐内存[^2]。 - **与引用区别**:C++ 引用是别名(alias),操作符为 `.`,不能为空;而指针更灵活但易出错[^1][^4]。 #### 4. **常见错误与避免方法** - **空指针解引用**:使用前检查指针是否为 `nullptr`(C++)或 `NULL`(C)。 - **类型不匹配**:确保指针类型与对象类型一致,避免未定义行为。 - **野指针**:释放指针后设置为 `nullptr`,防止访问无效内存。 - **替代方案**:在 C++ 中,优先使用引用(`.` 操作符)或智能指针以提高安全性。 #### 5. **总结** - **解引用 (`*`)**: 用于获取指针指向的值,适用于所有指针场景。 - **成员指针访问 (`->`)**: 用于通过指针直接访问对象成员,是解引用的快捷方式。 - 核心区别在于 `->` 专为对象成员设计,而 `*` 是通用解引用操作。正确使用时,两者效率相同。 - 安全提示:始终初始化指针,避免解引用无效地址[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值