☰
搞懂C语言的指针(四) 空指针|蒙圈的不止你一个
2026/9/26 11:21:20 网站建设 项目流程

在上一篇我分享了的内容及理解,在这里我们会搞懂空指针到底是怎么回事。

在学C语言时,看到自己写得程序终于通过了编译,感到无比兴奋。但是一运行,就被一个接一个的:segmentation fault搞蒙了。

估计这是所有接触过C语言的人的共同遭遇。

究其原因,无非是你还没有搞懂指针和空指针。那么,空指针是什么呢?

一句话,空指针(Null Pointer)就是不指向任何有效内存地址的指针。

因此我觉得当初把Null Pointer翻译成无效指针会更好一点,起码不会引起初学者的误解。

把一个城市当作内存的话,空指针不是指那些没有人住房子,而是专门用来指那些在城市里不存在的房子,当然那些烂尾楼也可以当作空指针。

但是它又是一个常量,作为NULL被定义在各种头文件里。

比如:stddef.h stdio.h stdlib.h string.h time.h wchar.h

#define NULL ((void*)0) //这个常量的定义会随着编译器的不同而不同 //现在为了保持C++和C的兼容,也有的定义为下面的形式 // C++ compatible: #define NULL 0 // C++ incompatible: #define NULL (10*2 - 20) #define NULL ((void*)0) // since C23 (compatible with C++11 and later) #define NULL nullptr

换个说法,任何有效的指针都不能成为空指针。

其实,它和C语言中其他类型的常量没有本质的区别,比如整数有常量:0,16进制有常量:0x00,char型有常量:'\0'。

因为指针也有类型,所以当把空指针变换成void*,char*,int* 时,就会生成相对类型的空指针。

例8:

#include int main(void) { void *p = 0x0; // 右边为空指针的常量,p为空指针 int *q = 0x0; // 0x0为整数的常量,是否为空指针,在(1)(8)(9)可以确认 int n = 0; /* A */ printf("(A) p [%p]\n", p); // %p的输出会会依存于系统 if(p == NULL) // (1) NULL 空指针常量 // printf("OK, integer constant expression 0x0 " "is a null pointer constant in your computer.\n"); else printf("* WARNING\n" "* Integer constant expression 0x0 may not be " "with \"the value 0\" in your computer.\n" "* Or, NULL may be incompatible with ISO:C11.\n"); /* B */ p = (void *)0; // (2) 右边为看指针常量,p:空指针 // (void *)0 是否为空指针常量,通过(3)确认 printf("(B) p [%p]\n", p); if(p == NULL) // (3) printf("OK, (void *)0 is a null pointer constant in your computer.\n"); else printf("* WARNING\n" "* Integer constant expression 0 may not be " "with \"the value 0\" in your computer.\n" "* Or, NULL may be incompatible with ISO:C11.\n"); /* C */ printf("(C) p [%p]\n" " q [%p]\n", p, q); if(q == (int *)p) // (4) printf("OK, any two null pointers shall compare equal " "[C11 \u00A76.3.2.3, 4; \u00A76.5.9, 6].\n"); else printf("* WARNING\n" "* Either integer constant expression 0x0 or 0 may not be " "with \"the value 0\" in your computer.\n"); /* D */ q = &n; // (5) 右边既不是空指针常量,也不是空指针 // 所以q不是空指针 printf("(D) q [%p]\n", q); if(q != NULL) // (6) printf("OK, q is not a null pointer.\n"); else printf("* WARNING\n" "* NULL may be broken.\n"); /* E */ p = 0x0; // (7) printf("(E) p [%p]\n" " q [%p]\n", p, q); if(q != p) // (8) printf("OK, q is not a null pointer.\n"); else printf("* WARNING\n" "* Integer constant expression 0x0 may not be " "with \"the value 0\" in your computer.\n"); /* F */ printf("(F) q [%p]\n", q); if(q != 0x0) // (9) printf("OK, q is not a null pointer.\n"); else printf("* WARNING\n" "* Integer constant expression 0x0 may not be " "with \"the value 0\" in your computer.\n"); return 0; } //执行结果如下 /* (A) p [0x0] OK, integer constant expression 0x0 is a null pointer constant in your computer. (B) p [0x0] OK, (void *)0 is a null pointer constant in your computer. (C) p [0x0] q [0x0] OK, any two null pointers shall compare equal [C11 xc2xa76.3.2.3, 4; xc2xa76.5.9, 6]. (D) q [0x16fdfeb54] OK, q is not a null pointer. (E) p [0x0] q [0x16fdfeb54] OK, q is not a null pointer. (F) q [0x16fdfeb54] OK, q is not a null pointer. */

既然空指针是无效指针,那么专门定义一个空指针,又有什么用呢?以简洁为宗旨的C语言当然不会做无用之功。

在C语言中,空指针的作用基本如下:

1、初始化尚未被赋予任何有效内存地址的指针变量。

例9:

#include int main() { //声明一个空指针 int* ptr = NULL; // if (ptr == NULL) { printf("Pointer does not point to anything"); } else { printf("Value pointed by pointer: %d", *ptr); } return 0; }

2、用于在访问任何指针变量之前检查其是否为空指针。这样我们可以在与指针相关的代码中进行错误处理,例如,仅当指针变量不为空时才对其进行解引用。

例10:

#include #include int main() { //分配一段动态内存 int* ptr = (int*)malloc(5 * sizeof(int)); //判断是否分配成功 if (!ptr) { printf("Memory Allocation Failed"); exit(0); } free(ptr); return 0; }

3、用于在不希望传递任何有效内存地址时,将空指针传递给函数参数。

例11:

#include void foo(int* string) { if (string == NULL) { printf("NULL Pointer Passed"); return; } printf("Non-Null Pointer Passed"); } // int main() { foo(NULL); return 0; }

4、空指针用于树、链表等数据结构中,表示结束位置。

例12:

#include #include /* 定义链表节点 */ struct Node { int value; struct Node *next; // 指向下一个节点 }; int main(void) { /* 手动创建三个节点 */ struct Node *n1 = malloc(sizeof(struct Node)); struct Node *n2 = malloc(sizeof(struct Node)); struct Node *n3 = malloc(sizeof(struct Node)); n1->value = 1; n2->value = 2; n3->value = 3; /* 串成一个链表 */ n1->next = n2; n2->next = n3; n3->next = NULL; // 关键:NULL 表示“链表到此结束” /* 遍历链表 */ struct Node *p = n1; while (p != NULL) { // 通过判断空指针知道是否结束 printf("%d\n", p->value); p = p->next; } /* 释放内存 */ free(n1); free(n2); free(n3); return 0; } //执行结果 /* 1 2 3 *

最后

说一下,空指针和Void指针的区别

空指针(NULL Pointer)通用【万能】指针(Void Pointer)

空指针不指向任何东西,它是一个特殊的指针变量

一个指向任何类型的指针

任何类型的指针变量都可以被设置为空指针

只有它才可以被定义为void型

所有的空指针都相等

Void指针可以是不同

空指针在头文件里被定义为一个常量值

void指针是一种指针的类型,也就是说它是一种数据类型

例如: int *ptr = NULL;

例如: void *ptr;

以上关于空指针的概念和应用,您理解了吗?

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询