对指针来次大的备忘吧!如果恰好帮助了您,不胜荣幸!文章名曰《深入理解C/C++指针(一)》、《深入理解C/C++指针(二)》,需要的博友可连撸效果更佳~~。在此,也感谢郭有强、谭浩强两位教授的C++书籍及众网友的精彩文章。(二)的目录如下:
- 指针数组
- 指向指针的指针
- 指针与函数
- const指针
1 指针数组
二维数组指针变量( 单个变量→二维数组):int (*p)[列数](因指向,p=a;因变量p开辟了自己的地址,&p≠a/p(注意数组名即地址a=&a))。指针数组( 数组,其元素为一个个指针变量储存地址):int * pa[4] //(pa→pa[4]→*pa[4])。比如,指针数组指向二维数组:每个元素指向每行(pa[i]=a[i]);指针数组指向一组字符串:每个元素指向一个字符串。【普通数组存“值”,指针数组存“址”。指针数组&原数组是两个不同的数组,pa=&pa≠a=&a】
1.1 数值型指针数组
int a = 1, b = 2, c = 3;
int *p[3] = { &a,&b,&c }; //地址初始化
cout << "数组元素是指针,装地址:" << p[0] << endl;
cout << "数组元素指针指向的内容:" << *p[0] << "=" << *(*(p + 0) + 0) << endl;
总结。地址:p[i]及其变种;值:*p[i]及其变种;初始化:地址。
int a[3][3] = { 1,2,3,4,5,6,7,8,9 };
int *pa[3] = { a[0],a[1],a[2] }; //指针数组:像数组一样初始化
for (int i = 0;i < 3;i++)
cout << pa[i] << "=" << a[i] << "," << *pa[i] << "=" << *(*(pa + i) + 0) << "=" << a[i][0] << endl;
for (int i = 0;i < 3;i++)
{
for (int j = 0;j < 3;j++)
cout << pa[i][j] << "=" << *(*(pa + i) + j) << "=" << a[i][j] << " ";
cout << endl;
}
cout << pa << "=" << &pa << "≠" << a << "=" << &a << endl; //两个数组各自的首地址
///
int a[3][3] = { { 1,2,3 },{ 4,5,6 } ,{7,8,9} };
int(*p)[3] = a; //二维数组指针变量
for (int i = 0;i < 3;i++)
cout << p[i] << "=" << a[i] << endl;
for (int i = 0;i < 3;i++)
{
for (int j = 0;j < 3;j++)
cout << p[i][j] << "=" << *(*(p + i) + j) << "=" << a[i][j] << " ";
cout << endl;
}
cout << p << "=" << a << "=" << &a << "≠" << &p << endl; //变量指向数组
总结。只想默默说一句,指针数组与二维数组指针变量“何其相近”!但前者:可指向一系列变量、二维数组(即不仅仅指向二维数组),是一个数组(区别于普通数组它存地址);后者:仅能指向二维数组(专有),是一个变量。由于它们都是“新建”,都开辟了内存空间(&p≠a=&a、pa=&pa≠a=&a),且定义都需常量。总之:指针数组比二维指针变量更普适(对二维数组功能相当),但后者比前者节约内存空间(sizeof( T*p)<sizeof(T *p)×n
(n为指针数组长度))。
1.2 字符串型指针数组(一个可列不等二维数组)
char *name[] = { "BASIC","FORTRAN","C+3","C#","C@@" };//字符串初始化
for (int i = 0;i < 5;i++)
{
cout << "name[" << i << "]的地址:" << name + i << endl; //由于name[i]就是地址,所以name+i是指向地址的地址(指向指针的指针)
cout << "name[" << i << "]的值(指针→整体→字符串):" << name[i] << endl;
}
cout << "第二个元素地址:" << name + 1 << "=" << &name[1] << endl; //地址
cout << "第二个元素内容(地址→整体作用→字符串):" << name[1] << "=" << *(name + 1) << endl; //FORTRAN
cout << "name[3]→'C#',它的第二元素*(*(name+3)+1):" << *(name[3] + 1) << "=" << *(*(name + 3) + 1) << "=" << name[3][1] << endl; //#
cout << "name[4][3]不存在(为空,程序未崩):" << name[4][3] << endl; //空
本质为“可列不等的二维数组”,适应二维数组的那套指针理论。但注意:它的列址name[i](整体作用)代表某个字符串(行址name+i仍为地址→name[i]),而name[i][j](i,j可越界)代表某字符串的某个字符。
附:利用指向字符串组的指针数组写排序算法:
// 字符串数组(一组字符串)排序算法
void charSort(char *name[], int n)
{
/*name[i]是指针,可整体表示字符串。时间复杂度:(n-1)+...
(n-2)+...+2+1=(n-1)n/2=O(n²)。*/
char *temp;
int i, j, k;
for (i = 0;i < n - 1;i++) //待比总个数循环
{
k = i; //最初:设待比较的为最小
for (j = i + 1;j < n;j++) //与后面比较
if (strcmp(name[k], name[j]) > 0) //后面如有更小的(交换)
k = j;
if (k != i) //后面确有更小的
{
//同之前“此轮中”暂定为最小的交换
temp = name[i];
name[i] = name[k];
name[k] = temp;
}
}
}
2 指向指针的指针
2.1 指向单个变量时
int **p1, *p2, n = 3;
p2 = &n; p1 = &p2;
cout << "*p2=n:" << *p2 << "=" << n << endl;
cout << "*p1=p2:" << *p1 << "=" << p2 << endl;
cout << "**p1=*(*p1)=*p2=n:" << **p1 << "=" << n << endl;
2.2 指向二维数组时
①a不能赋值给**p:
int a[3][4] = { 100,1,2,3,4,5,6,7,8,9,10,11 };
int ** p = (int **)a; /*不做强制类型转换会报错 */
cout << "p:" << p << ", a:" << a << ", &a[0][0]:" << &a[0][0] << endl;//相等
cout << "*p:" << *p << endl; //100(十六进制)
//cout << "**p:" << **p << endl; //错误:访问了100的空间(即:*(100))
总结:少了一层,p直接指向a[0][0](本应指向“行址”级别)。
②指针数组过渡:
char *name[] = { "BASIC","FORTRAN","C+3","C#","C@@" };
char **p = name; //p+i=name+i(name+i本身是二级指针,指向name[i])
for (int i = 0;i < 5;i++)
{
for (int j = 0;j < strlen(p[i]);j++)
cout << *(*(p + i) + j); //p[i][j]等
cout << endl;
}
③单个指针变量过渡:
int a[2][3] = { 1,2,3,4,5,6 };
int **p, *q;
for (int i = 0;i < 2;i++)
{
q = a[i];p = &q;
for (int j = 0;j < 3;j++)
cout << *(*p + j) << " ";//p[0][j]
cout << endl;
}
总结:将二维数组赋予指针的指针,需要借用“单个指针变量”、“指针数组”来过渡,直接赋值(T **p=a)是不可以的!
3 指针与函数
3.1 函数指针(指向函数的指针变量)
目的:换用指针的方式去 调用函数。 函数类型(*变量名)(形参表) 函数类型(*变量名)(形参表)(仅用“(*变量名)”替代了函数原型声明中的函数名,其他一样),如 int (*p)(int,int);(p→*p→(*p)(int, int))。此外,可于定义时赋值:int (*p)(int, int)=func; //func不能带参数,函数名代表该函数的入口地址。函数指针可作为另一函数的形参(C规定:整个函数不能作为形参,但可作实参)。如double f1(double){f1的函数体}, double func(double a, double b, double (*p)(double)) {func的函数体},main中调用func(a,b,f1)。
3.2 指针函数(返回指针值的函数)
函数的返回值为指针型数据。类型 * 函数名(形参表)。(可一级、多级指针)4 const指针
int a=1,b=3;
(1)指向常量的指针变量:即不能通过指针刷新内容,const int * p=&a; //p=10; 错误,但p=&b和a=10都对
(2)常指针:即不能改变指向,int * const p=&a;// p=&b;错误,但p=10正确
(3)指向常量的常指针:既然不能刷新内容、也不能改变指向,const int *const p=&a; //*p=10或p=&b都错,但a=10对
固定a可用:const int a=1;
《深入理解C/C++指针(一)》整装完毕,等待您的检阅(▽)~~