摘要:
指针由两部分构成,1.目标变量的类型 2.指针类型:如 int *
定义指针时要求必须和该指针所指向变量类型相致
在32位计算机中无论指针(指针变量简称指针)指向的是何种变量,所有指针在内存中占4个字节。
在使用指针前必须给指针赋值;同数据类型的指针可以互相赋值
指针变量只能存放已定义变量的地址,不能直接给制止变量赋予整数或任何地址,不能通过输入得到地址
* 两种不同含义,具体看使用语境,一种为指针说明符;另一种是间接运算符或指针运算符或去内容运算符,若P为指针变量,*p则为P所指向的目标变量
int a = 5;
int *p = &a;
则*p和a等效 其值都是5.
&p 表示指针变量P本身的地址
指针赋值:
int a;
int *p;
p=&a;
或者
int a;
int *p = &a;
指针运算:
1. 对指针赋值
int *p = &a;
2. 地址运算“&”和内容运算“*”,这两个互为逆运算
int a =5;
int *p=&a;
则&(*p)=&a
*(&a)=a
3. 加减
int a[] = "1,2,3,4,5"
int p=&a;
则*p=1
*p++=2;
*(p+2)=3;
*(p+3)=4;
指针加n或减n表示指针由当前所指向的位置向后或向前移动n个数据元素位置
移动后的实际地址为:p±n*sizeof(数据类型) 注意字节编址对齐
*p++相当于*(p++);
4. 比较
指针不能和一般数值进行比较但是可以和0和NULL进行比较
(指向)整型指针:
先看如下示例:
#include <iostream>
using namespace std;
int main()
{
int a = 5;
int * p = &a;
cout << "a = " << a << endl
<< "&a = " << &a << endl
<< "*p = " << *p << endl
<< "p = " << p << endl
<< "&p = " << &p << endl;
return 0;
}
运行结果如下:
我们先看下内存分配图:
由上图可以清楚的知道,输出整形变量a的值是5,指针变量p的值是001BFD18,而*号的作用是取值,*p即取地址001BFD18中存放的值,即5。
(指向)字符型指针:
可以使用字符数组和字符指针代表一个字符串
字符数组只有在定义时才能一起赋值,程序中对字符数组只能对各元素赋值,对字符串指针可以直接赋值字符串。
先看如下示例:
#include <iostream>
using namespace std;
int main()
{
char a[] = "hello";
char *p = a;
cout << "p = " << p << endl
<<"p = " << (void *) p << endl
<< "*p = " << *p << endl;
for(int i = 0 ; i < 5; i++)
{
cout << "&a[" << i << "] = "<< (voi*)&a[i] << endl;
}
return 0;
}
运行结果图如下:
为什么整型指针p输出的是地址,而字符型指针输出的是字符串呢,字符型指针里存放的不是地址吗?
我们先看下内存分配图:
由上图可以看出,其实p中存放的是地址,只是当cout时,如果指针是字符型指针,那么会输出p中地址指向的内存中的内容(这里是h)直到遇到'\0'才结束。所以直接输出p时会输出hello,而将p强制转换为void *时输出的是地址。
指针与数组:数组指针一个数组名实际就是个指针常量,不是指针变量,不能给数组名赋值。数组名的值即编译器给数组分配的数组起始地址
数组名代表数组的第一个元素的地址.
当指针变量指向一维数组的第一个元素,指针变量名就可以当成一维数组名使用。也可以通过指针移动访问数组元素 p=a或者p=&a[0]
访问一个数组元素可以使用:
1. 下标法 a[i];(数组名的下标变量访问)
2.指针法*(p+i);(指针+偏移量的间接地址访问)
3.*(a+i);(数组名作为地址值得直接地址访问)
4.p[i]; (指针作为数组名的下标变量访问)
指针数组:一个数组中每个元素都是指针
如 char *a[]={"hello",
"well",};
指针与结构数组:结构指针
strcut info{
short a;
int b[6];
};
strcut info myinfo, *pinfo;
pinfo =&myinfo;
则可以用指针访问结构成员:
1.通过结构变量名访问 myinfo.a
2. 通过指针间接运算符访问 (*pinfo).a
3. 通过指针和成员运算符访问 pinfo->a
函数指针:
int (*p)(int a ,int b);
p=max;
这里p实际上指向函数指针变量,其指向函数具有两int类型参数并且函数返回int类型数据
我们使用此指针来调用函数int c=p(10 ,5);
其实此时p变量也是存的地址,此地址即该函数入口地址,pint *类型变量进行函数调用
指针强转:
char a='A';
char *p=&a;
int *p1=(int *)p; //p强制转换指向整型数据指针
cout<<*p1<<endl; // 输出'A'ASCII码值65
指向指针的指针:
在说指向指针的指针之前,不得不说指向变量的指针。先看如下示例:
指向整型指针的指针先看如下示例:
#include <iostream>
using namespace std;
int main()
{
int a[5] = {1, 2, 3, 4, 5};
int *p = a;
int **point = &p;
cout << "a = " << a << endl
<< "p = " << p << endl
<< "&p = " << &p << endl
<< "point = " << point << endl
<< "&point = " << &point << endl;
for (int i = 0; i < 5; i++)
{
cout << "&a[" << i << "] = " << &a] << endl;
}
return 0;
}
运行结果图如下:
我们先看下内存分配图:
从上图可以看出point指针中存放的是p指针的地址,而p指针中存放的是a[0]的地址。所以*point和p是一样的,前者是取point指针中存放的地址(0025F754)中的值,即取地址0025F754中存放的值(0025F760),而后者就是0025F760,所以两者是等价的。**point和a[0]是等价的,前者可以写成*p,*p是取p中存放的地址(0025F760)中的值,即地址0025F760中存放的值1。由上可以得出*point等于p, **point 等于 a[0]。通过上图可以清晰的对付诸如*point++等问题。
4. 指向字符型指针的指针
先看如下示例:
#include <iostream>
using namespace std;
int main()
{
char *a[] = {"Wel", "To", "China"};
char **p = a;
for(int i = 0; i < 3; i++)
{
for (int j = 0; j < strlen(a[i]) + 1; j++)
{
cout << a[i][j] << "\t" << (void *)&a[i][j] << endl;
}
cout << endl;
}
for (int i = 0; i < 3; i++)
{
cout << "a[" << i << "] = " << (void**) a[i] << endl
<< "&a[" << i << "] = " << &a[i] << endl;
}
cout << "p = " << p << endl
<< "&p = " << &p << endl;
return 0;
}
运行结果图如下:
我们先看下内存分配图:
由上图可以看出a[0]中存放着'W'的地址,a[1]中存放着'T'的地址,a[2]中存放着'C'的地址,只是这些地址都是指向字符型的,所以直接cout的会输出字符串,而指针p中存放着a[0]的地址,所以*p等于a[0],都是获得'W'的地址,即00A778CCC,而**p和a[0][0]等价都获得了地址00A778CCC中存放的值W。由上图我们可以看到字符地址相隔1个字节,而指针地址相隔4个字节,这样就便于++运算,获得下一个地址了,列如++p后,p就指向a[1],p中存放的是a[1]的地址。