www.91084.com

GVKun编程网logo

C语言空(null)指针和NULL指针的区别详解(c语言空指针null以及void指针)

26

在本文中,我们将带你了解C语言空在这篇文章中,我们将为您详细介绍C语言空的方方面面,并解答null指针和NULL指针的区别详解常见的疑惑,同时我们还将给您一些技巧,以帮助您实现更有效的c–使用Asse

在本文中,我们将带你了解C语言空在这篇文章中,我们将为您详细介绍C语言空的方方面面,并解答null指针和NULL指针的区别详解常见的疑惑,同时我们还将给您一些技巧,以帮助您实现更有效的c – 使用Assert和NULL指针验证哪个更好用、C++ NULL指针、C++中指针和引用的区别详解、C语言NULL指针

本文目录一览:

C语言空(null)指针和NULL指针的区别详解(c语言空指针null以及void指针)

C语言空(null)指针和NULL指针的区别详解(c语言空指针null以及void指针)

对于空(null)指针与 NULL 指针,相信许多读者对它们之间的关系都很迷惑,甚至有很大一部分读者会认为它们根本就是一回事。其实不然,它们之间存在着一定的本质区别,下面就来详细阐述它们之间的不同。

对于空(null)指针的概念,在 C 标准中明确地定义:值为 0 的整型常量表达式,或强制(转换)为“void*”类型的此类表达式,称为空指针常量。当将一个空指针常量赋予一个指针或与指针作比较时,将把该常量转换为指向该类型的指针,这样的指针称为空指针空指针在与指向任何对象或函数的指针作比较时保证不会相等。

根据上面的定义,我们可以对空指针做如下几点剖析:
1) 每一种指针类型都有一个空指针,它与同类型的其他所有指针值都不相同。

2) 由系统保证空指针不指向任何实际的对象或函数,也就是说,任何对象或者函数的地址都不可能是空指针,空指针与任何对象或函数的指针值都不相等。因此,取地址操作符 & 永远也不能得到空指针,同样对 malloc() 函数的成功调用也不会返回空指针,但如果调用失败,则 malloc() 函数返回空指针。

3) 空指针表示“未分配”或者“尚未指向任何地方”。它与未初始化的指针有所不同,空指针可以确保不指向任何对象或函数,而未初始化指针可能指向任何地方。

4) 0、0L、'\0'、3-3、0*17以及(void*)0等都是空指针常量,则:

int *p;
p=0;
/*或者*/
p=0l;
/*或者*/
p='\0';
/*或者*/
p=3-3;
/*或者*/
p=0*17;
/*或者*/
p=(void*)0;

指针变量 p 经过上面任何一种赋值操作之后都将成为一个空指针。至于编译时系统究竟选取哪种形式作为空指针常量使用,则与具体实现相关。在一般情况下,对于 C 语言系统,选择“(void*)0”或 0 的居多(也有个别的选择 0L);而对于 C++ 语言系统,由于存在严格的类型转化的要求,“void*”不能像在 C 语言中那样自由转换为其他指针类型,所以通常只选 0 作为空指针常量,而不选择“(void*)0”。

5) 对于空指针究竟指向内存的什么地方,在标准中并没有明确规定。也就是说,用哪个具体的地址值(0 地址还是某一特定地址)来表示空指针完全取决于系统的实现。在一般情况下,空指针指向 0 地址,即空指针的内部用全 0 来表示,也可以称它为零空指针。当然,也有一些系统用一些特殊的地址值或特殊的方式来表示空指针,也可以称它为非零空指针

但在实际编程中,我们并不需要了解在系统上的空指针到底是一个零空指针还是一个非零空指针。而我们仅仅只需要知道一个指针是否是空指针就可以了,编译器会自动实现其中的转换,为我们屏蔽其中的实现细节。因此,千万不要把空指针的内部表示等同于整数0的对象表示,有时它们是不同的。

在了解空指针的概念之后,下面来看 NULL 指针。

作为一种良好的编程习惯,很多程序员都不愿意在程序中到处出现未加修饰的 0 或者其他空指针常量。为了让程序中的空指针使用更加明确,从而保持统一的编程风格,标准 C 专门定义了一个标准预处理宏 NULL,其值为“空指针常量”,通常是 0 或者“((void*)0)”,即在指针上下文中的 NULL 与 0 是等价的,而未加修饰的 0 也是完全可以接受的。如在 VC++ 中定义预处理宏 NULL 的代码如下:

/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else
#define NULL   ((void *)0)
#endif
#endif

这里需要说明的是,当 NULL 定义为“((void *)0)”时,即 NULL 是可以赋值给任何类型指针的值,它的类型为 void*,而不是整数 0,因此初始化“FILE*fp=NULL;”是完全合法的。

而为了区分整数 0 和空指针 0,当需要其他类型的 0 时,即使可能工作,也不能使用 NULL,因为这样处理其格式是错误的,这种类型在非指针上下文中是不能工作的。特别需要注意的是,不能在需要 ASCII 空字符(NUL)的地方使用 NULL。如果确实需要,则可以自定义为:

#define NUL '\0'

由此可见,常数 0 是一个空指针常量,而 NULL 仅仅是它的一个别名。NULL 可以确保是 0,但空(null)指针却不一定。

c – 使用Assert和NULL指针验证哪个更好用

c – 使用Assert和NULL指针验证哪个更好用

在进行编程时,我使用的是assert以及NULL指针验证.

但正如我所知,断言仅在DEBUG模式下有用.

我的问题是假设我有一个内部指针,我肯定不能是NULL示例函数返回一个指针(但指针不是类的成员)在这种情况下,我可以使用断言

test* ptr = fun(); // return a pointer of type test
assert(ptr);

//do some operation

或NULL指针验证

test* ptr = fun(); // return a pointer of type test
assert(ptr);
if (NULL != ptr)
{
    //do some operation
}

这里的代码实践很好.据我所知,它将是第二个.
因为我遇到了一些ptr的值由于某些我们甚至无法想到的异常情况而返回NULL的情况.

但我们还有其他更好的选择吗?

解决方法

真正的解决方案取决于功能乐趣的语义.

如果返回NULL在语义上是无效的,那么我认为有趣应该抛出一个适当的异常(例如std :: logic_error1)而不是返回NULL,并且你可以在调用站点上使用assert来确保乐趣正常工作,如果是工作不正常,然后中止程序.通过这种方式,有趣的bug不会传播到程序的其余部分,因为它会被立即捕获.

但是,如果从fun返回NULL在语义上是有效的,那么你应该使用if检查调用站点上的返回值,在这种情况下确实不需要assert,因为无论如何你都会使用if.

1.或者您可以使用std :: runtime_error或std :: domain_error.

C++ NULL指针

C++ NULL指针

#include <iostream>

using namespace std;

int main () {
   int  *ptr = NULL;
   cout << The value of ptr is  << ptr ;

   return 0;
}

C++中指针和引用的区别详解

C++中指针和引用的区别详解

C++中指针和引用的区别

指针和引用在C++中很常用,但是对于它们之间的区别很多初学者都不是太熟悉,下面来谈谈他们2者之间的区别和用法。

1.指针和引用的定义和性质区别:

(1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已。如:

int a=1;int *p=&a;

int a=1;int &b=a;

上面定义了一个整形变量和一个指针变量p,该指针变量指向a的存储单元,即p的值是a存储单元的地址。

而下面2句定义了一个整形变量a和这个整形a的引用b,事实上a和b是同一个东西,在内存占有同一个存储单元。

(2)可以有const指针,但是没有const引用;

(3)指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的)

(4)指针的值可以为空,但是引用的值不能为NULL,并且引用在定义的时候必须初始化;

(5)指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不会再改变了。

(6)"sizeof引用"得到的是所指向的变量(对象)的大小,而"sizeof指针"得到的是指针本身的大小;

(7)指针和引用的自增(++)运算意义不一样;

2.指针和引用作为函数参数进行传递时的区别。

(1)指针作为参数进行传递:

#include<iostream>
using namespace std;

void swap(int *a,int *b)
{
  int temp=*a;
  *a=*b;
  *b=temp;
}

int main(void)
{
  int a=1,b=2;
  swap(&a,&b);
  cout<<a<<" "<<b<<endl;
  system("pause");
  return 0;
}

结果为2 1;

用指针传递参数,可以实现对实参进行改变的目的,是因为传递过来的是实参的地址,因此使用*a实际上是取存储实参的内存单元里的数据,即是对实参进行改变,因此可以达到目的。

再看一个程序;

#include<iostream>
using namespace std;

void test(int *p)
{
  int a=1;
  p=&a;
  cout<<p<<" "<<*p<<endl;
}

int main(void)
{
 int *p=NULL;
 test(p);
 if(p==NULL)
 cout<<"指针p为NULL"<<endl;
 system("pause");
 return 0;
}

运行结果为:

0x22ff44 1

指针p为NULL

大家可能会感到奇怪,怎么回事,不是传递的是地址么,怎么p回事NULL?事实上,在main函数中声明了一个指针p,并赋值为NULL,当调用test函数时,事实上传递的也是地址,只不过传递的是指地址。也就是说将指针作为参数进行传递时,事实上也是值传递,只不过传递的是地址。当把指针作为参数进行传递时,也是将实参的一个拷贝传递给形参,即上面程序main函数中的p何test函数中使用的p不是同一个变量,存储2个变量p的单元也不相同(只是2个p指向同一个存储单元),那么在test函数中对p进行修改,并不会影响到main函数中的p的值。

如果要想达到也同时修改的目的的话,就得使用引用了。

2.将引用作为函数的参数进行传递。

在讲引用作为函数参数进行传递时,实质上传递的是实参本身,即传递进来的不是实参的一个拷贝,因此对形参的修改其实是对实参的修改,所以在用引用进行参数传递时,不仅节约时间,而且可以节约空间。

看下面这个程序:

#include<iostream>
using namespace std;

void test(int &a)
{
  cout<<&a<<" "<<a<<endl;
}

int main(void)
{
 int a=1;
 cout<<&a<<" "<<a<<endl;
 test(a);
 system("pause");
 return 0;
}

输出结果为: 0x22ff44 1

          0x22ff44 1

再看下这个程序:

这足以说明用引用进行参数传递时,事实上传递的是实参本身,而不是拷贝。

所以在上述要达到同时修改指针的目的的话,就得使用引用了。

#include<iostream>
using namespace std;

void test(int *&p)
{
  int a=1;
  p=&a;
  cout<<p<<" "<<*p<<endl;
}

int main(void)
{
 int *p=NULL;
 test(p);
 if(p!=NULL)
 cout<<"指针p不为NULL"<<endl;
 system("pause");
 return 0;
}

输出结果为:0x22ff44 1

         指针p不为NULL

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

C语言NULL指针

C语言NULL指针

// C语言NULL指针 
// C语言NULL指针 --------------------
#include <stdio.h>

int main () {

   int  *ptr = NULL;

   printf(The value of ptr is : %x\n, ptr  );

   return 0;
}

关于C语言空null指针和NULL指针的区别详解的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于c – 使用Assert和NULL指针验证哪个更好用、C++ NULL指针、C++中指针和引用的区别详解、C语言NULL指针的相关信息,请在本站寻找。

本文标签: