C++指针使用的好坏直接反映了编程人员水平的高低,下面从指针和数组的区别、指针参数是如何传递内存、野指针、malloc/free、new/delete和内存耗尽怎么办方面进行总结。

一 指针和数组对比

  C++/C程序中,指针和数组在不少地方可以相互替换着用,让人产生一种错觉,以为两者是等价的。数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操作动态内存。指针远比数组灵活,但也更危险。

(1)修改内容

char a[] = “hello”;
a[] = ‘X’; // 数组可以修改字符串内容 char *p = “world”; // 注意p指向常量字符串
// 编译器不能发现该错误
// 但该语句企图修改常量字符串的内容而导致运行出错
p[] = ‘X’;

(2)内容复制和比较

// 数组…
char a[] = "hello";
char b[];
strcpy(b, a); // 不能用 b = a;
if(strcmp(b, a) == ) // 不能用 if (b == a) // 指针…
int len = strlen(a);
char *p = (char *)malloc(sizeof(char)*(len+));
strcpy(p,a); // 不要用 p = a;
if(strcmp(p, a) == ) // 不要用 if (p == a)

(3)计算内存容量

char a[] = "hello world";
char *p = a;
cout<< sizeof(a) << endl; // 12字节
cout<< sizeof(p) << endl; // 4字节

注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针

void Func(char a[])
{
 cout<< sizeof(a) << endl; // 4字节而不是100字节
}

二 指针参数如何传递内存

(1)错误示例

void GetMemory(char *p, int num)
{
 p = (char *)malloc(sizeof(char) * num);
} void Test(void)
{
 char *str = NULL;
 GetMemory(str, ); // str 仍然为 NULL
 strcpy(str, "hello"); // 运行错误
}

  编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是 _p,编译器使 _p = p。如果函数体内的程序修改了_p的内容,就导致参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。

  在上面的例子中,_p申请了新的内存,只是把_p所指的内存地址改变了,但是p丝毫未变。所以函数GetMemory并不能输出任何东西。事实上,每执行一次GetMemory就会泄露一块内存,因为没有用free释放内存。

(2)解决方法1:使用指向指针的指针

void GetMemory2(char **p, int num)
{
 *p = (char *)malloc(sizeof(char) * num);
} void Test2(void)
{
 char *str = NULL;
 GetMemory2(&str, ); // 注意参数是 &str,而不是str
 strcpy(str, "hello");
 cout<< str << endl;
 free(str);
}

(3)解决方法2:指针作为函数返回值

char *GetMemory3(int num)
{
 char *p = (char *)malloc(sizeof(char) * num);
 return p;
} void Test3(void)
{
 char *str = NULL;
 str = GetMemory3();
 strcpy(str, "hello");
 cout<< str << endl;
 free(str);
}

注:(1)在上面的例子中,要特别注意在函数调用完后用free释放malloc的内存;
  (2)不要在函数体内返回栈内存的指针

三 野指针

  “野指针”不是NULL指针,是指向“垃圾”内存的指针。

  人们一般不会错用NULL指针,因为用if语句很容易判断。但是“野指针”是很危险的,if语句对它不起作用。

  “野指针”的成因主要有三种:

  (1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。

  (2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。

  (3)指针操作超越了变量的作用域范围。

class A
{
public:
  void Func(void){ cout << “Func of class A” << endl; }
}; void Test(void)
{
 A *p;
 {
  A a;
  p = &a; // 注意 a 的生命期
 }
 p->Func(); // p是“野指针”
}

四 malloc/free/new/delete

  malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。

  对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。

  因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。

五 内存耗尽怎么办

  如果在申请动态内存时找不到足够大的内存块,malloc和new将返回NULL指针,宣告内存申请失败。通常有三种方式处理“内存耗尽”问题。

  (1)判断指针是否为NULL,如果是则马上用return语句终止本函数。

  (2)判断指针是否为NULL,如果是则马上用exit(1)终止整个程序的运行。

  (3)用_set_new_hander函数为new设置用户自己定义的异常处理函数。

C++之指针使用的更多相关文章

  1. TODO:Golang指针使用注意事项

    TODO:Golang指针使用注意事项 先来看简单的例子1: 输出: 1 1 例子2: 输出: 1 3 例子1是使用值传递,Add方法不会做任何改变:例子2是使用指针传递,会改变地址,从而改变地址. ...

  2. enote笔记法使用范例(2)——指针(1)智能指针

    要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...

  3. C++虚函数和函数指针一起使用

    C++虚函数和函数指针一起使用,写起来有点麻烦. 下面贴出一份示例代码,可作参考.(需要支持C++11编译) #include <stdio.h> #include <list> ...

  4. C++11 shared_ptr 智能指针 的使用,避免内存泄露

    多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...

  5. c 数组与指针的使用注意事项

    数组变量和指针变量有一点小小的区别 所以把数组指针赋值给指针变量的时候千万要小心 加入把数组赋值给指针变量,指针变量只会包含数组的地址信息 而对数组的长度一无所知 相当于指针丢失了一部分信息,我们把这 ...

  6. Marshal.Copy将指针拷贝给数组

    lpStatuss是一个UNITSTATUS*的指针类型实例,并包含SensorDust字段 //定义一个数组类型 byte[] SensorDust = new byte[30] //将指针类型拷贝 ...

  7. C++智能指针

    引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...

  8. EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针

    一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...

  9. 智能指针shared_ptr的用法

    为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...

  10. 智能指针unique_ptr的用法

    unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...

随机推荐

  1. Sybase:解锁

    Sybase:解锁 Sql代码: --查询锁表 sp_iqlocks --解除锁定 drop connection[连接序号]

  2. ssi include返回404页面

    项目中index.html中包含<!--#include virtual="/commonfrag/djdzkan/recomm_www_info.inc"  --> ...

  3. 20145201《Java程序设计》第1次实验报告

    实验内容 一.命令行下java程序开发 1.建立Code目录,输入mkdir 20145201命令建立实验目录,并使用dir命令查看目录建立情况. 运行结果如图 2.进入实验目录,输入mkdir ex ...

  4. Hibernate : Query.list()、Query.iterator()的区别

    Query上有list()与iterator()方法,两者的差别在于list()方法在读取数据时,并不会利用到快取,而是直接再向数据库查询,而iterator()则将读取到的数据写到快取,并于读取时再 ...

  5. 俄罗斯最新开源的牛掰数据库ClickHouse

    ClickHouse是俄罗斯最近刚刚开源的用于数据库管理系统能够实时生成分析数据报告,性能非常强悍! 使用SQL查询. 他拥有切割你的数据更多的新方法 ClickHouse的性能超过同类市场上目前用于 ...

  6. eclipse中的错误解决——The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path

    看看我们遇到的问题 解决问题

  7. 在myeclipse中安装svn

    首先下载site.zip,然后解压.在myeclipse的安装目录中的dropins文件夹中新建svn文件夹,把site中的features和plugins文件夹复制到svn中即可.然后重启Myecl ...

  8. javascript练习题(2):变量作用域

    1. 外层变量在内部可以找到,反之找不到 以下看个案例: var a=10; function aaa(){ alert(a); } function bbb(){ var a=20; aaa(); ...

  9. css预处理器sass学习

    SASS 叫做css预处理器,他的基本思想是用一门专门的编程语言来进行页面样式的设计,然后在编译成正常的css文件. Sass的用法 安装 sass是用ruby语言写的,所以我们在安装sass之前要先 ...

  10. 在linux上用jmeter压测时出现很多异常java.net.NoRouteToHostException: Cannot assign requested address.

    今天压力测试时, 刚开始出现了很多异常, 都是 java.net.NoRouteToHostException: Cannot assign requested address. 经网上查资料, 是由 ...