指针的基础:
<1>定义:
Code
int a = 1;
int *pa = &a;//初始化
/*--------------------------------------------*/
int *pa;//(养成习惯,'*'号紧跟变量名)
pa = &a;//(注意与上边的初始化其实是一样的,初学的话很容易被忽悠的)
以上pa是一个指针,cout<<pa;输出的是它的地址
而*pa是一个int值,cout<<*pa输出的是1;
<2>指针与其指向对象关联性
由以上:
假如我在上面分隔线上的代码中继续添加以下代码:
*pa = 2;或 a = 2;
cout<<(*pa == a)<<endl;//输出1(true),证明是同时更新的;
<3> const与指针的使用(这个东西很阴的)
Code
const char *pa;//重点在于const是修饰int的,所以是指针指向的字符串为常量。
char const *pa;//同上,记住,是修饰int的,“const”了“*pa”因为*pa是字符串,即其值不可改
char * const pa; //很明显地,这个const是修饰pa的,即指针pa不能被改变(即地址不能变))
const char * const pal;//这个简单,都不能变,指向常量字符串的常指针
<4> 指向指针的指针
Code
int *pa;//普通指针
int **ppa;//指向指针的指针,*ppa的值是一个int*指针。
ppa = &pa;//指向指针的指针的f赋值
<5>内存分配(堆中)
Code
char *pa;
pa = new char[10];//new带构造函数!
delete []pa;
pa = (char*)malloc(100);//malloc不带构造函数
free(pa);
pa = NULL;
//此处还有一个比较重要的:当使用strcpy给pa赋值时需要有足够的空间,要不会内存泄露。
关于指针的一些问题:
<1>指向常量的指针与分配了内存的指针
Code
char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char *str5 = "abc";
const char *str6 = "abc";
char *str7 = “abc”;
char *str8 = “abc”;
cout << boolalpha << ( str1==str2 ) << endl; // 输出什么?
cout << boolalpha << ( str3==str4 ) << endl; // 输出什么?
cout << boolalpha << ( str5==str6 ) << endl; // 输出什么?
cout << boolalpha << ( str7==str8 ) << endl; // 输出什么?
答:false,false,true,true
因为str1,str2,str3,str4都是字符串数组,都有分配自己的存储空间,他们的值都是指向各自的首地址,所以不等。而str5,str6不是字符数组而是常量指针,而“abc”是以常量的形式存储与静态数据区,因为相同的常量在数据区只会分配一块空间,因此str5,str6都是指向此静态区域的头地址,str7和str8同理。
<2>关于sizeof
Code
int getLen(char str[])//函数
{return (int)(sizeof(str)-1);}
char str[]="hello world";//从这里开始为main函数
cout<<getLen(str)<<endl;
cout<<sizeof(str)-1<<endl;//假如是int型则需要sizeof(str)/sizeof(int)-1,其他同理
求输出:
答:3(反白可以看见)
11
使用数组作函数形参时数组指针自动退化为指针,因此在函数体内的sizeof只能求出指针的长度4;而在外的sizeof则能求出数值的整体长度,函数内的求长使用strlen,此函数所求长度不包括‘\0’,等于sizeof()-1;
改进方法是:
Code
int getLen(char (&str)[10])
{return sizeof(str);}
//此时只要传递一个char str[10]就可以求出其长度,不过其长度是定死的。
<3>字符串数组与指针
Code
char a[] = "abcdefg";//只能是字符类型才行
char b[] = {'a','b','c','d','e','f','\0'};//此处‘\0’不能少,少了将会输出乱码
char *pc = "abcdefg";//c指向的是一个字符串常量,因此不能对c[n]赋值,紧记与a的区别
char *pa1 = a+1;//其实a+1也是一个数组的头指针,所以pa1也是数组头指针
char *pb1 = b+2;//同上
char *pb2 = (char*)(&b+1);//这里重点,&b取的是整个数组的地址,+1的话移动的是一个数组的距离
//这时pb2指向的是数组的后一个指针位置,将其类型转换为char*,则指向
//的是数组最后一个元素‘\0’的后一个指针的位置
cout<<pa1<<endl;//pa1是一个数组指针
cout<<pb1<<endl;//pb1也是一个数组指针
cout<<*(pb2-2);//pb2指向b数组的最后一个数后一位后向前跳两个位置,跳到了f处
求输出:
答(1)bcdefg(反白可以看见)
(2)cdef
(3)f
<4>关于函数中的参数指针及函数中分配内存
先说明一下;
使用new或malloc来申请空间需要改变pstr,这是重点,指针作参数是否正确使用可以说就是指针的地址值(不是其指向的类型)有没有被改变的问题,将指针看作一个数据类型,那么理解会比较容易。
看以下例子:
Code
void function(char *str)
{
str = new char[12];//这种情况是错误的,因为str只是实参的一个拷贝,为其分内存不与实参有关系
strcpy(str,"Hello world");
}//当函数调用完毕时str这个指针拷贝将被销毁
第一种方法(外部申请内存)(严格来说这种与上面讨论的无关,但是也记录下来吧):
Code
void function(char *str)
{
str = new char[12];//这种情况是错误的,因为str只是实参的一个拷贝,为其分内存不与实参有关系
strcpy(str,"Hello world");
}//当函数调用完毕时str这个指针拷贝将被销毁
然后在main函数中这样使用
Code
char *str = new char[12];//这里一定要分配足够的内存
str = getMemory(str);//使用返回值可行,因为在函数销毁前返回了str自身拷贝的指针str,这样可行。
delete[] str;//不过这种方法有点奇怪ORZ
第二种方法(使用双重指针):
Code
void getMemory(char **ppstr)//使用指向指针的指针
{
*ppstr = new char[12];//可以修改ppstr所指向的指针
strcpy(*ppstr,"hello world");//同上
}
在main函数中这样使用:
char *pstr;
getMemory(&pstr);//将指针地址赋给指针的指针
cout<<pstr<<endl;
delete[] pstr;
pstr = NULL;
第三种方法(使用指针的引用)
Code
void getMemory(char *&pstr)//引用形参不是实参的拷贝,而是传递进函数中的任意指针的别名,但是
{ //它与指向int型对象的指针相关联,因此可以修改其值
pstr = new char[12];
strcpy(*ppstr,"hello world");
}
main函数中
char *pstr;
getMemory(pstr);
cout<<pstr;
delete[] pstr;
pstr = NULL;
<5>strlen的使用;
求字符串长度
Code
int getLen(const char *str)//一个不适用中间变量的求字符串长度函数
{return (*str)?getLen(str+1)+1:0;}//可以说strlen就是通过字符串最后的'\0'来判断长度的
所以有如下:
Code
char str[12];//不赋初值
cout<<strlen(str)<<endl;//因为没有'\0'作结束判断,所以会输出奇异的结果,记得赋初值
<6>指向数组的指针和指针数组
以下有什么不同?
Code
char (*str)[20]; //str是一个数组指针,即指向数组的指针.
char *str[20]; //str是一个指针数组,其元素为指针型数据.
<7>指向类中成员的指针
Code
class Sample{
public:
int num;
int function(){cout<<"I am Sample's function"<<endl;return 1;}
};
int main()
{
int Sample::*pnum = &Sample::num;//将*punm初始化为类Sample中num成员的地址
Sample sam1;
sam1.*pnum = 2;//可以可以对所指向的内存进行复制
cout<<sam1.num<<endl;//这时对象里的num成员被改变了
int (Sample::*fun)() = &Sample::function;//给指向成员函数的指针赋予其成员函数的地址
Sample sam2;//声明一个Sample类
(sam2.*fun)();//调用指向成员函数的指针
return 0;
}
以上是使用指向类成员函数以及成员数据的方法,其实和普通的指向函数的指针和指向数据类型的指针原理是一样的,
不同的是需要在*号的前面加上类作用域。
以后找到一个关于指针的细节就补上一个,请各位也看过的也帮忙提些意见吧,让我好完善一下!谢谢。