读书笔记——Accelerated C++ Chapter10 管理内存与低级数据结构

指针与数组--字符串字面量--初始化字符串指针数组--main函数的参数--文件读写--内存读写的三种方法

 

指针与数组

指针和数组都是C与C++语言中最原始的数据结构之一。数组是容器的一种,指针是一种随机存取的迭代器。

指针

   指针是存放地址的值。&是一个求址运算符,x是一个对象,那么&x是该对象的地址。通常用0来初始化指针变量,常量0也是唯一可以用于转化成指针类型的整型值。我们称0转化成的指针类型为空指针。

   当一个函数作为另一个函数的参数时,编译器会将该参数转化为一个指向函数的指针。对一个函数的所能做的全部操作只能是获得它的地址或者对其进行调用。

int (*fp) (int) ;  //fp是具有一个int 类型参数并返回int类型结果的函数的指针

int next(int n)

{return n+1;}

//下面两个语句是等价的;不论是否显式的使用&因为编译器会将他解释成函数的地址

fp = &next;

fp = next;

如果在一个函数的形参中使用了函数指针,那么我们可以以与函数定义相同的形式来定义这个参数的类型是一个函数指针;如果在一个函数的返回值类型中使用了函数指针,那么我们必须使用函数指针的标准形式,或者使用 typedef 定义的函数指针类型名,而不能使用与函数定义相同的形式来进行
声明。

 

数组

  数组是容器的一种,是核心语言的一部分而不是标准库的内容。每个数组均包含一个或几个同类型的对象,每个对象成为一个元素。数组元素的个数必须在编译时确定,即数组无法动态增加或减小。

数组不是类,所以没有size——type这个成员变量。可以用size_t类型(在<cstddef>中定义的无符号类型,它的大小足以装下任何对象)表示一个数组的大小。

  只要我们将数组名作为一个值使用时,数组名都将表示指向数组首元素的指针。可以用*运算符对coords间接引用,以访问该指针指向的对象。

double coords[3];

*coords = 1.5; //将1.5赋给corrds数组的首元素

 

指针算法

  指针是一个随机存储的迭代器。延续数组节中提到的coords数组,coords+3是一个有效的指针,尽管它并不指向coords数组中的任何一个元素。例如:

vector<double> v;

copy(coords,corrds+NDim,back_inserter(v));

// 尽管corrds+NDim不止像数组中的任何元素,它不代表容器的最后一个元素,但他也是有效的

  如果p,q都是指向同一数组中的元素的指针,那么p-q是一个整数,它表示p和q所指向的元素在数组中的间距。这个差值有可能是负数。因此它是一个带符号的整数类型。可用标准库提供的ptrdiff_t(在<cstddef>中定义)来表示相应的类型。

 

索引

  所有随机访问迭代器都支持索引功能。

 

数组初始化

  使用某种初始化方式可以避免显示的定义该数组的大小,就是直接对数组中的每个元素进行初始化,这是在标准提供的容器中没有的。例如:

const int month_lengths[]={31,28,31,30,31,30,31,31,30,31,30,31};//每个月的天数

 

字符串字面量回顾

  字符串字面量是一个字符字面量数组,该数组的大小是字符串的长度加一。这个一是编译器自动在字符串字面量的所有字符后面加上的一个空字符(’\0’)。这个空字符作为该字符串的终止符。一个字符串变量只给出该变量初始字符的地址,程序在一个字符串中遇到第一个空字符时认为字符串结束。strlen函数可用于求一个字符串变量或者一个以空字符结束的数组的大小(在<cstring>定义),但这个大小值没有算上最后的终止符。

  字符串字面量是一个指向空字符结尾的数组的首字符的指针。

 

初始化字符串指针数组

  关键字sizeof可以求出double数组的元素个数,而如果e是一个表达式,那sizeof(e)则返回一个size_t值,表示e类型的对象占用多少内存。sizeof运算符返回的数值以字节(bytes)为单位。

 

main函数的参数

  main函数具有两个参数,一个整型(int)参数与一个指向字符指针的指针参数。这两个参数习惯被称为argc和argv。argv是指向一个指针数组首元素地址的指针,数组中的每个元素都指向一个字符串参数。argc的值是argv指向的数组中的指针个数。argv数组的首元素总是main函数编译后的程序名,所以argc的值至少是1。如果有参数,这些参数总是在数组中作为连续的几个元素出现。

 

文件读写

标准错误流

在C++库中处理标准输入/输出流以外,还定义了标准错误流。可以用cerr或clog进行标准错误流输出。这两个在处理缓冲时有区别。clog流倾向于生成日志,clog流与cout有着一样的缓冲特性;如果要及时反映错误的话,请选择使用cerr,如果只是为了生成一个异常日志,就应该选择使用clog。

 

处理多个输入/输出文件

  如果要处理一个输入/输出文件,就必须分别创建一个ifstream和ofstream类型。在标准库中,ifstream被准确的定义为istream的一种,而ofstream是ostream的一种。这些类的定义可以在头文件<fstream>中找到。

  程序在处理文件的时候一般都要求提供一个指向空字符结尾的字符数组的指针作为文件名参数。即可以用字符串字面量,或是将文件名储存在string类型的变量里,然后使用c_str成员函数,见下:

ifstream infile(file.c_str());

 

内存管理的三种方法

  第一种方法是自动内存管理,这种方法常与局部变量联系在一起 :一个局部变量只在程序执行到该变量定义时才由系统自动分配内存给他,当包含该变量的定义的模块结束时,该变量占用的内存自动释放。这种可以通过将此变量声明成为静态变量,那么系统将对它进行一次而且只进行一次内存分配,之后直到程序结束之前该变量占用的内存都不会被释放。当然如果不希望这个变量每次都为同一个值,还可通过动态分配内存完(new、delete)。

为对象分配/释放内存

new T     将为一个T类型的对象分配内存,该变量由构造函数对其初始化,并且产生一个指向该新分配内存的对象的指针(该对象甚至没有命名)。

new T(args)这样的初始化语句可以给变量赋予一个特定的值

delete p 删除一个指针,这个指针是指向一个用new语句分配内存的对象。释放指针p所指对象占用的内存空间。

  new出对象一直存在直至程序结束或者执行了delete语句。删除一个零指针不进行任何操作。

为数组分配/释放内存

new T[n]   将为一个n个T类型对象的数组分配内存,并且返回一个指向数组首元素的指针(该指针类型为T*,T是一个类型名,n是一个非负整数)。

   如果T是内奸类型而且数组有只是在局部作用域内分配内存,那么对象将不会被初始化;如果T是一个类,那么数组中的每个元素都会运行类的构造函数进行初始化。

   当n=0时,new函数会返回一个有效但无意义的off-the-end指针。

  如果T是一个自定义类型。在初始化要注意两点:1.如果该类不允许默认初始化,那么编译器将终止程序。2.数组中的n个元素的每一个元素都会被初始化,这将带来一定的运行时开销。

delete[] p  释放整个数组占用的内存,在释放数组之前,系统根据相反的顺序逐个释放数组中的每个元素。

  length函数求出的长度包含数组结尾的空字符。

 

觉得之前的总结结构难于集中某个内容,所以改为与书中结构相同的总结模式。

posted @ 2014-01-12 23:44  文火煮姜茶  阅读(210)  评论(0编辑  收藏  举报