1、指针和引用的比较
区别:
1)引用总是指向某个对象:定义引用时没有初始化是错误的;
2)赋值行为的区别:给引用赋值修改的是该引用所关联的对象的值,而并不是使引用与另一个对象关联。引用一经初始化,就始终指向同一个特定对象。
int ival=1024; ival2=2048;
int *pi=&ival, *p2=&ival2;
pi=p2;
赋值结束后,pi所指向的ival对象值保持不变,赋值操作修改了pi指针的值,使其指向了另一个对象。
(指针:从右往左阅读其定义)
2、指向const 对象的指针、const指针和指向const对象的const指针
const double *ptr; //定义一个指向const double对象的指针,指针本身可以更改,但其对象值不能改变;
double *const curptr //定义了一个指向double型对象的const指针,其指针本身的值不能改变,但是其对象的值可变。
const double *const pi_str=π //指向const对象的const指针
3、指针和typedef
typedef string *pstring;
const pstring cstr; //等价于 pstring const cstr;= string *const pstring;
声明const pstring对象时,const修饰的是pstring的类型,这是一个指针,因此,该声明语句应该是把cstr定义为指向string类型对象的const指针。
4、C风格字符串的标准库函数
头文件:#include <cstring> //c++版本
#include <string.h> //c版本
常用函数:
strlen( s ) //返回s的长度,不包括字符串结束符null
strcmp( s1, s2 ) //比较两个字符串的大小,相等返回0;大于返回正式;小于返回负数
strcat ( s1, s2 ) //将s2连接到s1后,并返回s1.
strcpy ( s1, s2 ) //将s2复制给s1后,并返回s1.
strncat ( s1, s2, n ) //将s2的前n个字符连接到s1后面,并返回s1.
strncpy ( s1, s2, n ) //将s2的前n个字符复制到s1后,并返回s1.
注意事项:
1)strlen() 函数其返回s的长度,不包括null,但是sizeof()函数返回的大小包括null;
2)常用的普通关系操作符比较两个字符串,比较的是两个字符串指针上存放的地址值,而strcmp()比较的是字符串的大小;
3)strcat()连接s1,和s2时,s1的大小必须大于或等于strlen(s1)+strlen(s2)+1;
4)strncat()连接n个字符,其中注意的是,每次连接记得字符串后面的null。
eg:char largetstr[16+18+2] //其中16等于strlen( cp1 ),18等于strlen(cp2),2表示空格加null的大小。
strcpy( largetstr, cp1 );
strcat ( largetstr, " " ); //这里连接的是一个空格和null,其中空格覆盖掉cp1后面的null,再添加一个null;
strcat ( largetstr, cp2 );
strncpy( largetstr, cp1, 17 ); //strlen(cp1+null)
strcat ( largetstr, " " , 2 ); //这里连接的是一个空格和null,其中空格覆盖掉cp1后面的null,再添加一个null;
strcat ( largetstr, cp2, 19 ); //strlen(cp2+null)
5、创建动态数组
每一个程序在执行时,都占用一块可用的内存空间,用于存放动态分配的对象,此内存空间称为程序的自由存储区(free store)和堆(heap)
c语言程序使用一对标准库函数:malloc 和 free;
c++语言使用的是:new 和 delete表达式来实现相同的功能。
1)动态数组的定义
动态分配数组时,只需要指定类型和数组长度,不必为数组对象命名,new返回指向新分配数组的第一个元素的指针。
int *pia = new int[10]; //pia存放的是动态分配数组的首地址。
2)初始化动态分配的数组
动态分配数组时,如果数组元素具有类类型,将使用该类的默认构造函数,实现初始化;如果数组元素是内置类型,则无初始化;
string *pia = new string[10]; //分配10个string对象的数组,并用构造函数初始化;
int *pia = new int[10]; //分配10个int对象的内存空间,无初始化;
int *pia new int[10](); // 分配10个int对象的内存空间,并初始化为0;
memset( pia, 0, 10 );
memset(buffer, '*', strlen(buffer) ); //用*初始化为buffer分配的内存空间。
int *ptr=(int *)malloc( n*sizeof( int ) ); //使用malloc分配的数组返回的是void*,所有必须进行强制类型转换。
允许动态分配空数组
size_t n = get_size();
int *p = new int[n];
for ( int *q = p; q!=p+n; ++q )
{
//process the array;
}
【注】 可以调用new动态创建长度为0的数组,返回有效的非零指针,但不能进行解引用操作。
3)动态空间的释放
动态分配的内存最后必须进行释放,否则,内存最终将会逐渐耗尽,如果不再需要使用动态创建的数组,程序员要显示的将其占用的存储空间返还给程序的自由存储区。
c++中用delete [] 表达式释放指针所指向的数组空间,其中“[]”是必不可少的;
c语言中使用free()来释放指针所指向的数组空间;
eg:int *pia new int[10](); // 分配10个int对象的内存空间,并初始化为0;
delete [] pia; //注意其中的[]不能省,"[]"的作用是:告诉编译器该指针指向的是自由存储区中的数组,而并非单个对象。
int *ptr=(int *)malloc( n*sizeof( int ) ); //使用malloc分配的数组返回的是void*,所有必须进行强制类型转换。
free( ptr );
如果指针指向不是用new分配的内存地址的指针,则在该指针上使用delete是不合法的。零值指针的删除是允许的,但这样做没有任何意义。
在delete之后,该指针变成悬垂指针,悬垂指针指向曾经存放对象的内存,然而其所指向的内存已经被释放,不存在了。悬垂指针往往导致程序的错误,因而很难检测出来。
正确的做法是:一旦删除了指针所指向的对象,立即将指针值为0;这样就非常清楚地表明指针不在指向任何对象。
4)动态数组的使用
通常是因为在编译时无法知道数组的维数,所以才需要动态创建该数组。
int dimension = strlen( errorTxt) + 1;
char *errMsg = new char[ dimension ];
strncpy ( errMsg, errorTxt, dimension );
6、新旧代码的兼容
1)混合使用标准库类string和c风格字符串,string使用的是c_str,返回const char 类型的数组;
可以用c风格字符串对string对象进行初始化或赋值,也可用于string类型的加法操作;
eg:char *str=str2.c_str(); //返回c风格字符串的表示方法;其中c_str()返回的指针指向const char类型的数组;
const char *str = str2.c_str(); //ok
2)使用数组初始化vector对象
使用数组初始化vector对象,必须指出用于初始化式的第一个元素以及数组最后一个元素的下一个位置的地址。
eg:const size_t arr_size =6;
int int_arr[arr_size] = {0 , 1, 2, 3 , 4, 5}; //注意初始化数组的格式;
vector< int > ivec ( int_arr, int_arr+arr_size );
7、多维数组
1) 多维数组的初始化
int ia[3][4] = {
{0,1,2,3},
{4,4,5,6},
{4,4,5,6},
};
等价于:
int ia[3][4] = {0,1,2,3,4,4,5,6,4,4,5,6};
2) 指针和多维数组
使用多维数组名,实际上将其自动转换为指向该数组第一个元素的指针;
int ia[3][4];
int (*ip)[4] = ia; //ip 指向一个含有4个整形变量的数组;
ip = &ia[2]; //ia[2]是一个含有4个整形变量的数组;
定义指向数组的指针与如何定义数组本身类似:首先声明元素类型,后接(数组)变量名字和维数。窍门在于(数组)变量的名字其实就是指针,因此需要在标识符前加上“*”。由内向外阅读ip的声明,则可理解为:*ip是int[4]类型————即ip是一个指向含有4个元素的数组的指针。
typedef int int_array[4];
int ia[3][4]; 等价于 //int (*ip)[4] = ia;
for( int i=0; i<3; i++ ) for( int_array *p = ia; p != ia + 3; ++p )
{ {
for( int j=0; j<4; j++ ) for( int *q = *p; q != *p + 4; ++q )
{ {
cout << ia[i][j] << endl; cout << *q << endl;
} }
} }