《c++ primer》读书笔记12

原创 2004年09月23日 18:34:00

距离本笔记的上一篇已经过了很长时间了,很多人问我为什么不写了,其实理由很简单,我写不出什么东西,正如上篇笔记所说的在这之前的东西只是为了向朋友们推荐一本好书以及帮助初学者熟悉作者的思考习惯,这个很容易,但也很肤浅,这样的东西是不合适写的太多的(地球人都知道的东西,还是看书为好)。这就意味着必须选择话题来写(当然也大大增加了笔者犯错的机会)。上面这些话算是对一直支持我的朋友们做个解释,也希望再得到你们的支持。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

在本篇文字中,我选择的话题是指针,是的,我已经听到很多人开始抱怨这个麻烦的该死的东西,但是我不得不说离开了这个东西(那个麻烦的该死的)你很难干得成什么事情,对于c/c++程序员来说这是个不可能回避的问题,那么我们最好还是看看这个东西到底麻烦在那儿,这样比抱怨更能解决问题。

第一,      指针的定义和初始化:在本书的3.3节在这方面作了详细的描述,很简单,指针是一种间接操作对象的方式,指针中存放的是所操作对象在内存中的地址,但请注意,如果指针表示的仅仅是地址的话,事情就好办得多,但是指针还必须与他表示的对象的类型保持一致,就象本书p73的例子:
int *p = NULL;”
double dval = 3.14;
p = &dval;  // error
不是p物理上不能存放dval的地址,而是两种类型的内存布局和内容的解释完全不同(对编译器而言),编译器只好从一开始就拒绝这种赋值形式,当然,从你开始看上面的代码的那一刻,我就知道你不以为然了,一个学过编程的人是不会犯这种低级错误的,真的是这样吗?那么好,我想有时候你会希望对指针直接赋个地址,你是否会这样写?
  int *p = 0x00001010;
然后,编译器就开始骂人了,“0x00001010是那个对象的地址?什么类型?一定是int吗?你让我咋解释他呢?重写!”呵呵,也难怪他脾气这么大,你这个地址根本就没有告诉编译器类型信息嘛,当然如果你非要这样做,要么告诉他你需要这个地址的类型:
  int *p = (int*)0x00001010;
要么干脆先不管类型的事情:”
  void *p = 0x00001010;
但不管你选那个方式,cast总是免不了,建议少用。

 

第二,野指针:当指针赋值的时候,编译器会检查地址的类型信息,这很好,但赋值之后他就不管了,这个正是一切麻烦的根源,比如有个典型的代码:
#include <iostream>

#include <cstdlib>

using namespace std;

int*f()

{

    int a = 0;

    return &a;

}

int g()

{

    double a;

    cin >> a;

    return 0;

}   

int main()

{    

      

       int *p = f();

       cout << *p << endl;

       g();

       cout << *p << endl;

       system("pause");

       return 0;

}

 

我们发现编译器没有报错,而p中存放的地址也没被改变,但两次提领的结果完全不同,这是因为一旦函数f结束后,局部对象a进入了栈粉碎机,但是,请注意,栈粉碎机除去的不是该对象的地址编号和数据。而是该对象地址的类型标志(当然这是编译器行为,和纯内存无关)。而指针则仍然按照之前的约定对该对象地址进行提领等操作,一旦该对象地址被改变了类型信息,就必然错误。一个指针指向的对象的类型信息被改变者被消除,从而使得指针操作的结果不可预测,就成为野指针。

第三,内存泄漏:这个问题跟堆上分配有直接的关系,首先,我们要明白什么是内存泄漏,下面这个函数f内存泄漏了吗?
int*f()

{

    int *p = new(int);

    return p;

}

int main()

{    

      

       int *p = f();

       *p = 11;

       cout << *p << endl;

       system("pause");

       delete p;

       return 0;

}

我们还是引用《effective c++》里的一段话来回答这个问题:
引起内存泄露的原因在于内存分配后指向内存的指针丢失了。如果没有垃圾处理或其他语言之外的机制,这些内存就不会被收回

显然我们没有丢掉控制该地址的指针,被分配的内存仍掌握在我们手里。只不过要相当注意罢了。特别是当有异常出现的时候,不要忘记在程序退出之前delete这个内存。(当然有时候auto_ptr也是个不错的选择)

C++ Primer中文版读书笔记

(注意,Lm 表示第 m 行,L-n 表示倒数第 n 行)■导读 p23原文:template T func( T p1, T p2, int p3 ) // ( T p1, T p2, int p3...
  • jaminwm
  • jaminwm
  • 2007年12月25日 20:04
  • 2431

《C++primer(第五版)》学习之路-第十一章:关联容器

【 声明:版权所有,转载请标明出处,请勿用于商业用途。  联系信箱:libin493073668@sina.com】 11.1 使用关联容器 1. 关联容器类型 按关键字有序保...
  • libin1105
  • libin1105
  • 2015年09月26日 12:28
  • 1486

【c++ primer】第九章读书笔记

第九章   内存模型和名称空间
  • fghbnmjkl1
  • fghbnmjkl1
  • 2017年03月08日 08:09
  • 117

《C++ Primer》读书笔记第十一章-1-关联容器概述

笔记会持续更新,有错误的地方欢迎指正,谢谢!前言:前面学的都是顺序容器,顺序容器中的元素是按它们在容器中的位置来保存和访问的。接下来这一章学习关联容器:关联容器中的元素是按关键字来保存和访问的。 ...
  • BillCYJ
  • BillCYJ
  • 2017年09月22日 16:47
  • 91

C++ primer plus读书笔记(一)

这一系列的blog主要是对以前学过的C++的特点,以及面向对象的相关内容的总结。 面向对象的三大特征:封装、继承、多态。 访问控制原则: public:使用类对象的程序可以直接访问公有成员。...
  • u012927281
  • u012927281
  • 2016年08月17日 10:57
  • 307

c++ Primer Plus(第六版)第十二章习题,写代码之路

c++ Primer Plus(习题12.1) //12.1头文件 #pragma once #ifndef COW_H #define COW_H #include #include class ...
  • Robot_x
  • Robot_x
  • 2017年01月20日 13:01
  • 501

C++ primer读书笔记(1)

写在前面的话:
  • u013457107
  • u013457107
  • 2014年05月02日 00:17
  • 458

c++ primer 读书笔记十一

3.4迭代器 和指针不一样的是,获取迭代器不是使用取地址符,有迭代器的类型同时返回拥有返回迭代器的成员,比如这些类型都拥有名为begin和end的成员,其中begin成员负责指向第一个元素的迭代器 ...
  • sinat_37339643
  • sinat_37339643
  • 2018年01月26日 15:24
  • 14

【c++ primer读书笔记】【第11章】关联容器

1、关联容器类型 按关键字有序保存元素 map 关联数组:保存关键字-值对应 set 关键字既值,既只保存关键字的容器 multimap 关...
  • ruan875417
  • ruan875417
  • 2015年03月29日 17:00
  • 266

C++ primer学习 12.19

一、关联容器 关联容器通过键(key)存储和读取元素 1.1 pair类型 pairanon; anon=make_pair(string("aaa"),5);//不加STring(),vc...
  • steph_curry
  • steph_curry
  • 2017年12月19日 09:00
  • 30
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:《c++ primer》读书笔记12
举报原因:
原因补充:

(最多只允许输入30个字)