欢迎来真孝善网,为您提供真孝善正能量书籍故事!

深入解析C语言中的指针类型:空指针、野指针、悬垂指针与void指针

时间:11-03 现代故事 提交错误

这里解释一下:值为0的整型常量表达式,或强制(转换)为 void * 类型的此类表达式,称为 空指针常量 。如0、0L、3-3、""、017、(void)0等都是空指针常量。

至于系统将使用哪种形式作为空指针常量,取决于具体的实现。大多数通用C系统使用(void *)0或0,有些使用0L。对于C++系统,由于严格的类型转换要求,void *不能像C中那样自由转换为其他指针类型,因此通常选择0。作为空指针常量。

将空指针常量赋值给指针类型变量p,p就变成了空指针

2.NULL值

宏NULL 在(和其他标头)中定义为空指针常量。

也就是说,NULL是一个标准的宏定义,用来表示空指针常量。

我们在stddef.h中找到宏定义:

#define NULL ((void *)0) 毫无疑问,NULL 是一个空指针常量。

有个问题,我们可以自定义NULL值吗?

事实上,NULL是标准库中的保留标识符,因此如果包含相应的标准头文件来引入NULL,那么在程序中将NULL重新定义为其他值(例如将NULL定义为3)。非法的。

一、空指针(null pointer)

1.空指针定义

如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证与任何对象或函数的指针比较不相等。

通过预备知识中空指针常量NULL值的解释,我们可以知道:

只要将空指针常量赋给指针类型变量,该指针变量就是空指针。int *p;

p=0;

p=0L;

p="";

p=3 - 3;

p=0 * 17;

p=(无效*)0;

p=空;如上面的代码所示,在任何赋值操作之后,p都是空指针。并且,由系统保证空指针不指向任何实际的对象或函数。另一种方法是:任何对象或者函数的地址都不可能是空指针。

2.空指针的内存指向

该标准没有指定空指针在内存中指向的位置。也就是说,到底用0x0地址还是其他地址来表示空指针,取决于具体系统的实现。两种实现方式如下:

(1)零空指针(zero null pointer)这是一个常见的实现,即空指针内部用全0表示。

(2)非零空指针(nonzero null pointer)也有一些系统使用特殊的地址值或特殊的方法来表示空指针。

在实际编程中,我们不需要了解我们系统的空指针和内存指向的实现。我们只需要了解一个指针是否为空指针即可。 ——编译器会自动实现转换并使我们免受实现细节的影响。

3.空指针的使用

使用空指针主要是为了防止野指针和悬空指针。

防止野指针int *p=NULL;防止悬垂指针int *p=malloc(sizeof(int));

免费(p);

p=空; //有关null 的详细信息,请参阅下面的野指针和悬空指针。

二、野指针(wild pointer)

1.野指针概念

野指针:未初始化的指针

2.野指针产生原因

指针变量未初始化

以下程序:

int main()

{

整数*p;

printf(%p", p);

返回0;

这里的p没有初始化,它的默认值是随机的。

因此,当我们声明一个指针变量时,为了防止野指针的问题,我们可以将其初始化为NULL,即设置为空指针;我们也可以在初始化时确定指针。

如下图:

整数a=3;

int *p=a;

//或者

int *p=NULL;

整数*p=0;其中int *p=0 和int *p=NULL 都是常用的。

三、悬垂指针(dangling pointer)

1.悬垂指针概念

悬空指针:指向已释放的自由区内存(自由存储)的指针。

它与野指针的区别在于,悬空指针曾经有效,现在无效;但野指针从来都不是有效的。

2.悬垂指针产生原因

(1)指针指向的内存释放之后未置空

指针指向的内存被free或delete释放后,指针的值仍然是刚刚释放的内存的首地址,但此时指针已经失去了合法访问权限对该记忆的权利。

如下程序所示:

int main()

{

int *p=NULL;

p=malloc(sizeof(int));

*p=3;

printf("释放前,p=%p, *p=%dn", p, *p);

免费(p);

/* 注意此时p和p指向的内容并没有改变,只是释放内存后就丢失了。

堆上内存的合法操作*/

printf("释放后,p=%p, *p=%dn", p, *p);

返回0;

}程序输出:

释放前,p=0xe7a010,*p=3

free后,p=0xe7a010, *p=0 程序执行free(p)后,p是一个野指针。为了避免野指针可能带来的问题,我们应该在free(p) 之后添加:

p=空;此操作称为置空

(2)指向同一块内存多个指针之一被释放

严格来说,这种情况和第一种情况是一样的。示例代码如下:

int *p=malloc(sizeof(int));

*p=3;

int *pd=p;

/* 当前p和pd指向同一个内存*/

免费(p);

p=空;

/* 释放p指向的内存,并将p设置为0 */从上面的代码可以看出,如果有两个指针指向同一个内存,一个指针被释放并置空后,另一个指针仍然指向对于释放的内存空间,这成为一个悬空指针。

这是一个典型的悬空指针示例,在实际生产环境中经常见到。

(3)指针操作超出变量生命周期

不要返回堆栈内存的指针或引用,因为堆栈内存在函数结束时被释放。

示例代码如下:

//定义一个函数

字符*getString()

{

char *p="你好世界!";

返回p;

}函数内部定义的字符串指针p指向的内容存放在栈中。当函数执行完退出时,这部分空间会被释放,返回的p指针就变成了悬空指针。

四、void指针(void pointer)

1.void指针概念

void 的意思是“无类型”,因此void指针也称为“无类型指针”。 void指针可以指向任何类型的数据,因此void指针一般称为通用指针泛指针,也称为万能指针

2.void指针的使用

(1)void指针变量p所指向的内容不能通过*p去访问

如果想通过void指针获取它所指向的变量的值,则需要先将void指针转换为与变量名类型匹配的数据类型指针,然后再继续,如下所示:

整数a=5;

无效*p=a;

printf("*p=%dn", *p);编译器会报错并提示:

不允许使用不完整的类型。

这意味着这个类型是不完整的,没有办法获取它所指向的变量的值。更改为:

printf("*p=%dn", *(int *)p);会成功的。

(2)void指针赋给其他类型的指针

常见的使用场景是:动态内存申请与释放

首先,必须明确一件事。 C 语言和C++ 之间的某些语法实现存在差异。这里我们说的是C语言。

在C语言中,很自然地将void指针分配给任何其他类型的指针(函数指针除外,这将在下面讨论),并且不需要手动强制它;将任何其他类型的指针分配给void 指针也是很自然的。

例如:

类型定义结构{

.

.

复杂结构体;

//C语言正确的写法:

复杂结构=malloc(sizeof(复杂结构));

//C语言多余的写法:

//复杂结构=(复杂结构)malloc(sizeof(复杂结构));如果发现不手动强制传输,编译器会发出警告,请注意是否忘记添加malloc函数的头文件:

#include 因为在C语言中,编译器默认会将任何未定义的函数返回为int。因此,如果我们不添加stdlib.h头文件,则malloc函数默认返回int,因此我们会看到编译器警告。如果你看到的话,一不小心就会认为这两种类型不匹配,因为没有强制类型转换。其实编译器提示的是int * 和int 类型不匹配,而不是int * 和void * 类型不匹配!编译器警告

(3)void指针赋给函数指针

void 指针可以分配给除函数指针之外的所有指针。 malloc 函数就是一个例子。至于函数指针的问题,我们这里讨论一下。

Linux中有一个dlsym函数。函数声明如下:

void *dlsym(void *handle, const char *symbol); man手册中有一段示例代码:

int main()

{

.

无效*句柄;

双(*余弦)(双);

.

*(void **) (余弦)=dlsym(handle, "cos");

.

这里它想用一个函数指针来接收dlsym函数返回的void指针,但是它并没有使用下面两种更自然易懂的形式:

余弦=dlsym(句柄, "cos");

余弦=(double (*)(double)) dlsym(handle, "cos");这是因为C99标准的遗漏,导致void指针无法直接转换为函数指针。所以它使用了如下夸张的转换:

*(void **) (余弦)=dlsym(handle, "cos");首先将余弦的地址转换为二级指针,然后将其强制转换为(void **) void 二级指针,然后将指针通过运算符* 变成void 一级指针,这样左右类型就匹配了。

(4)其他类型的指针赋给void指针

void 指针可以用作泛型类型来接收任何数据类型指针。

void指针用于指向一个特定的地址,而不关心这个地址存储的是什么类型的数据。例如常见的memcpy等函数使用void*,函数原型如下:

好了,本文到此结束,如果可以帮助到大家,还望关注本站哦!

用户评论

滴在键盘上的泪

C语言中指针简直是个神级工具,不过要好好理解各种类型的指针,不然容易出错

    有8位网友表示赞同!

在哪跌倒こ就在哪躺下

我对空指针、野指针和悬垂指针的概念一直很模糊,这篇文章正好能帮我理清思路

    有20位网友表示赞同!

晨与橙与城

终于可以解释一下为什么写代码时总是遇到莫名其妙的错误了!一定是这些指针搞的鬼吧

    有17位网友表示赞同!

素衣青丝

void指针真是挺神秘的,它能指向各种类型的数据,有点像万能钥匙的感觉

    有11位网友表示赞同!

容纳我ii

看这篇文章感觉指针的概念一点都不容易理解,还需要多加练习才能掌握

    有10位网友表示赞同!

余温散尽ぺ

学习C语言的时候确实会被指针搞晕,还好现在有详细的文章解説了!

    有13位网友表示赞同!

抚涟i

明白这几种指针的区别真的很关键,否则写出来的程序可能就很难调试了

    有5位网友表示赞同!

代价是折磨╳

感谢作者的讲解,让我对指针类型有了更全面了解!

    有10位网友表示赞同!

墨城烟柳

希望可以找到一些练习题来巩固一下指针的概念

    有5位网友表示赞同!

顶个蘑菇闯天下i

有时候代码出现问题,我总怀疑是指针的问题,现在看来确实有可能!

    有11位网友表示赞同!

醉婉笙歌

感觉学习指针就像是在解谜,需要不断思考和理解才能最终破解!

    有9位网友表示赞同!

暖瞳

这篇文章写的非常清晰易懂,即使对指针不太了解的人也能看明白

    有16位网友表示赞同!

殃樾晨

指针真是C语言的核心概念之一,掌握好它可以写出更健壮的程序

    有5位网友表示赞同!

青楼买醉

我决定从今天开始每天都会练习一下指针,争取尽快把它们弄明白

    有7位网友表示赞同!

别在我面前犯贱

这篇文章让我对C语言的深入理解有了新的认识

    有9位网友表示赞同!

命运不堪浮华

学习指针是编程必经之路,感谢老师和作者的帮助

    有11位网友表示赞同!

心悸╰つ

我发现自己还有很多地方需要学习关于指针的地方!

    有10位网友表示赞同!

﹏櫻之舞﹏

以后在写代码的时候一定要更加谨慎地使用指针,避免出现错误

    有9位网友表示赞同!

あ浅浅の嘚僾

这篇文章是我学习C语言以来见过最棒的解释文章之一!

    有5位网友表示赞同!

西瓜贩子

我要把这篇文章分享给我的朋友们,让他们也能更好地理解指针的概念

    有15位网友表示赞同!

【深入解析C语言中的指针类型:空指针、野指针、悬垂指针与void指针】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活