C语言---NULL

NULL---空指针


 NULL :

在 C 语言中用于表示指针不指向任何有效的内存地址,即它是一个空指针常量。使用 NULL 可以帮助避免以下一些问题:

  1. 野指针(Dangling Pointer):当一个指针指向的内存被释放(例如,使用 free() 函数),但该指针的值没有被设置为 NULL 时,该指针就变成了野指针。如果之后程序错误地尝试访问这个野指针所指向的内存,可能会导致程序崩溃或者产生不可预期的结果。通过将指针设置为 NULL,可以明确地表示该指针不再指向任何有效的内存区域,从而避免这类问题。

  2. 未初始化的指针:如果指针变量在使用前没有被初始化,它可能包含任意的值,这可能导致程序访问一个随机的内存地址,造成不可预期的行为。通过将指针初始化为 NULL,可以确保在使用前指针有一个明确的状态。

  3. 条件判断:在 C 语言中,NULL 常用于条件判断中,以检查指针是否指向有效的内存地址。这有助于在指针操作之前进行错误检查,从而避免由于无效指针访问导致的程序崩溃。

  4. 代码可读性:使用 NULL 可以提高代码的可读性。当看到 NULL 时,读者可以立即知道这是一个空指针常量,而不是一个普通的整数或字符常量。

  5. 跨平台兼容性:在不同的平台上,指针可能具有不同的表示方式和大小。使用 NULL 可以确保代码在不同平台上的兼容性,因为 NULL 宏会根据平台的不同进行适当的定义。


下面这个函数中,在堆区申请了一个int大小的空间;

函数的返回类型是int *,即一个指向整型的指针;

我很好奇为什么可以返回NULL;NULL是什么;

int* fun1(){  
    int *pa = (int*)malloc(sizeof(int));  
    if(pa == NULL) {  
        // 错误处理  
        return NULL;  
    }  
    *pa = 11;  
    return pa;  
}

下面是GPT老师的回答:

在C语言中,NULL的宏定义通常位于头文件stdlib.hstddef.h中;

这些头文件会根据编译器和平台的不同而略有差异,但NULL的宏定义通常如下之一:

第一种定义:直接定义为0;

#define NULL 0

第二种定义:定义为指向void的指针字面量;

#define NULL ((void*)0)

现代C语言标准(C99及以后),推荐使用第二种定义方式,因为它提供了更强的类型安全性;

在将NULL赋值给任何类型的指针时,它都会隐式转换为相应类型的指针,而不仅仅是整数0。

第三种定义:想要自己定义;

#ifndef NULL  
#define NULL ((void*)0)  
#endif

这里的#ifndef是一个预处理指令,用于检查NULL是否已经被定义;

如果没有被定义,那么就会使用#define来定义它;

这样可以防止在多个地方重复定义NULL,从而避免潜在的冲突;

后面我在Dev-C++编译器中跳转了NULL的定义:

#ifndef NULL
    #ifdef __cplusplus
        #ifndef _WIN64
            #define NULL 0
        #else
            #define NULL 0LL
        #endif  /* W64 */
    #else
        #define NULL ((void *)0)
        #endif
#endif

下面是GPT老师的回答:

#ifndef NULL  
    #ifdef __cplusplus  
        #if defined(_WIN64)  
            // 在 Windows 64 位 C++ 中定义 NULL(不推荐)  
            #define NULL 0LL  
        #else  
            // 在非 Windows 64 位 C++ 中定义 NULL(仍然不推荐,但更常见)  
            #define NULL 0  
        #endif   
    #else // 不是 C++  
        // 在 C 中定义 NULL  
        #define NULL ((void *)0)  
    #endif  
#endif

// 但是,更好的做法是在 C++ 中始终使用 nullptr  
//#define NULL nullptr 

1.#ifdef __cplusplus:

检查是否正在编译C++代码;

__cplusplus是一个预定义的宏,当编译器在C++模式下工作时会被定义;

2.#ifndef _WIN64

在C++模式下,这段代码会检查是否定义了_WIN64宏;

这个宏通常在Windows 64位平台上被定义;

3.#define NULL 0

定义NULL为整数0,在C++中,整数字面量0可以隐式转换为任何指针类型,所以这种定义是有效的。

4.#define NULL 0LL

定义NULL为长整型字面量0LL0LL是一个64位整数的字面量;

然而,在C++中,通常不需要这样做,因为0可以隐式转换为任何指针类型,包括64位指针;

所以,这个定义可能是为了某种特定目的,但通常不是推荐的做法;

5.#define NULL ((void *)0)

定义NULL为一个指向void的空指针,明确地表示了一个空指针,并且与任何指针类型都兼容。

总结:

这段代码的目的是在不同的编译器和平台上正确地定义NULL宏;

然而,在C++中,对于64位平台的特定定义(#define NULL 0LL)可能是不必要的;

因为0本身就可以隐式转换为任何指针类型,包括64位指针;

在C中,使用#define NULL ((void *)0)是推荐的做法。

GPT好像更推荐一种叫nullptr的定义方法;

NULL 的标准定义(在 C++11 及以后)是 nullptr,它是一个类型安全的空指针常量;

在 C++ 中,直接使用 0 或 0LL 作为 NULL 的定义通常是不推荐的;

因为 nullptr 提供了更好的类型安全性和可读性。

总结:

  1. 当指针指向的内存被释放时或者初始化时,最好被设置为NULL,确保指针有明确的状态;
  2. 提高代码的可读性;
  3. 用于条件判断,检查指针是否指向有效的内存地址,避免无效指针访问导致程序崩溃;
  4. 跨平台兼容,不同平台都会对NULL进行宏定义;

 崩溃示例:

line 1:     3 Segmentation fault      (core dumped) ./a.out  
Exited with error status 139

这表示你的程序 ./a.out 在运行时遇到了一个段错误(Segmentation Fault)。

段错误是操作系统发出的一个信号,指示你的程序试图访问它没有权限访问的内存区域,或者访问

了已经被释放的内存。

因为空指针不指向任何有效的内存地址,所以无法访问内存;

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值