如下例1:
int *ptr;
char *ptr;
int **ptr;
int (*ptr)[3];
int *(*ptr)[4];
一、指针 类型
1、指针的类型
从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。 这是指针本身所具有的类型。 让我们看看如下各个指针的类型:
int *ptr; //指针的类型是 int*
char *ptr; //指针的类型是 char*
int **ptr; //指针的类型是 int**
int (*ptr)[3]; //指针的类型是 int(*)[3]
int *(*ptr)[4]; //指针的类型是 int*(*)[4]
2、指针所指向的类型
当你通过指针来访问指针所指向的内存区时, 指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。
从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。 例如:
int *ptr; //指针所指向的类型是 int
char *ptr; //指针所指向的的类型是 char
int **ptr; //指针所指向的的类型是 int*
int (*ptr)[3]; //指针所指向的的类型是 int()[3]
int *(*ptr)[4]; //指针所指向的的类型是 int*()[4]
在指针的算术运算中, 指针所指向的类型有很大的作用。
指针的类型(即指针本身的类型)和指针所指向的类型是两个概念。
3、指针的值或者叫指针所指向的内存区或地址
指针的值是指针本身存储的数值,这个值将被编译器当作一个地址。在 32 位程序里, 所有类型的指针的值都是一个32位整数, 因为32位程序里内存地址全都是32位长。指针所指向的内存区就是从指针的值所代表的那个内存地址开始, 长度为sizeof(指针所指向的类型)的一片内存区。以后,我们说一个指针的值是 XX,就相当于说该指针指向了以 XX 为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。
指针所指向的内存区和指针所指向的类型是两个完全不同的概念。 在例一中, 指针所指向的类型已经有了, 但由于指针还未初始化, 所以它所指向的内存区是不存在的, 或者说是无意义的。
4、指针本身所占据的内存区
指针本身占了多大的内存?你只要用函数 sizeof(指针的类型)测一下就知道了。 在 32 位平台里, 指针本身占据了4个字节的长度。
二、总结&实例:
一个指针 ptrold 加(减)一个整数 n 后, 结果是一个新的指针 ptrnew,ptrnew 的类型和 ptrold 的类型相同, ptrnew 所指向的类型和 ptrold所指向的类型也相同。 ptrnew 的值将比 ptrold 的值增加(减少)了 n 乘sizeof(ptrold 所指向的类型)个字节。 就是说, ptrnew 所指向的内存区将比 ptrold 所指向的内存区向高(低)地址方向移动了 n 乘sizeof(ptrold 所指向的类型)个字节。
实例1:子函数不断调用其他子函数,采用地址传递:
利用指针进行数值交换,然后子函数swap1 、swap2 、swap3中形式参数均为指针。
#include <iostream>
using namespace std;
void swap3(int* a, int* b) {
int temp;
temp = *a;
*a = *b;
*b = temp;
cout << "swap3中a、b的值: a=" << a << " b=" << b << endl;
cout << "swap3中*a、*b的值: *a=" << *a << " *b=" << *b << endl;
}
void swap2(int* a,int* b) {
int temp;
temp = *a;
*a = *b;
*b = temp;
cout << "swap2中a、b的值: a=" << a << " b=" << b << endl; //a b的值为地址,因此swap3中只需要传入a、b 即可!
cout << "swap2中*a、*b的值: *a=" << *a << " *b=" << *b << endl;
swap3(a, b); //
}
void swap1(int *a, int *b) {
int temp;
temp = *a;
*a = *b;
*b = temp;
cout << "swap1中a、b的值: a=" << a << " b=" << b << endl; //a b的值为地址,因此swap2中只需要传入a、b 即可!
cout << "swap1中*a、*b的值: *a=" << *a << " *b=" << *b << endl;
swap2(a, b); //
}
int main() {
int a = 10, b = 100;
cout << "main中a、b的值:a=" << a << " b=" << b << endl;
cout << "main中a、b的地址:&a=" << &a << " &b=" << &b << endl;
swap1(&a, &b);
cout << "a=" << a << " b=" << b << endl;
cout << "main中运行swap1(&a,&b)后,a、b的地址:&a=" << &a << " &b=" << &b << endl;
cout << "main中运行swap1(&a,&b)后,a、b的值:&a=" << a << " b=" << b << endl;
system("pause");
return 0;
}
运行如下:
实例2:指针数组在子函数中,子函数不断调用其他子函数,采用地址传递:
//子函数
extern int reppaths(const char *path, char *rpath[], int nmax, gtime_t ts,
gtime_t te, const char *rov, const char *base)
{
……
……
}
//子函数 postpos
extern int postpos(gtime_t ts, gtime_t te, double ti, double tu,
const prcopt_t *popt, const solopt_t *sopt,
const filopt_t *fopt, char **infile, int n, char *outfile,
const char *rov, const char *base) {
//调用子函数;其中含有 main函数中的infile 、ofile 字符指针数组
nf += reppaths(infile[j], ifile + nf, MAXINFILE - nf, tts, ttte, "", "");
}
int main() {
//其中 infile 为字符指针数组;ofile为字符指针
char* infile[] = {
{"rover_6_min_cut01470.20o"},
{"base_6_min_cut21470.20o"},
{"cut01470.20n"},};
char* ofile = { "myposbyVS.pos" };
//调用子函数
postpos(ts, te, ti, tu, &opt, &sopt, &fopt, infile, n, ofile, "", "");
}
main中,存在两个字符指针数组;其调用方式为:
对于数组 int *arr2[20]={0};为例:
//情况一
void test2(int *arr[20])
传参方式直观,实参与形参参数类型、大小均相同,便于理解。
//情况二
void test2(int **arr)
在这段代码中,可以把int*看作一个整体,将它typedef成为一个类型t
那么实参中的数组定义就可以看成t arr2[20];了,调用函数传参就可以看成t *arr,就与上面所讲的一维整型数组传参如出一辙了。这样传参也是正确的。
所以指针数组可以当做二级指针来传参。
在postpos中:
- main函数中实参 infile,postpos中形参 采用如上第二种方式进行参数传递 **infile ;
- main函数中实参ofile,postpos中形参,采用字符指针进行接收 char *outfile;
在reppaths中:
- postpos函数中实参infile[j] ,实参类型为 字符指针;因此在reppaths中,形参为 const char *path;即 字符指针;
- postpos函数中实参为ifile+nf,即指针数组;因此reppaths中,形参为char *rpath[],即指针数组;
结论:无论怎么传递,数据类型不会变!
三、指针变量在if、for、while语句中的应用
if(指针变量)
当把一个指针作为条件表达式时,所要判断的条件实际上就是“该指针是否为一空指针”。在if,while,for或do/while等语句中,或者在条件表达式中,都可以使用指针。
示例代码:
if (指针) {
// 不是空指针 执行这个
}else {
//指针 是一个空指针, 执行这个
}