对指针来次大的备忘吧!如果恰好帮助了您,不胜荣幸!文章名曰《深入理解C/C++指针(一)》、《深入理解C/C++指针(二)》,需要的博友可连撸效果更佳~~。在此,也感谢郭有强、谭浩强两位教授的C++书籍及众网友的精彩文章。(一)的目录如下:
- 什么是指针?
- 指向一维数组的指针
- 指向二维数组的指针
- 例子与理解
1 什么是指针?
指针是一种变量,它保存某个变量的地址(特殊的整型数据)。如int *p=&a:指针p→变量a,且p=&a=地址(&取址运算符),a=*p=内容(*间接访问运算符)。任何指针变量使用前须赋值(明确指向关系;且必须为地址、0/NULL),没有合法、有效的指向关系的野指针禁止使用!不管是变量还是指针作函数参数,实参与形参间的交流都是“单向值传递”!(C++参数传递方式共两种:①传值方式(包括普通变量、指针);②传址方式(引用))也就是说:形参指针(调用结束释放)绝不可能改变实参指针的指向,它顶多能在被调函数中改变实参指针指向的变量的值!即 “能刷新内容,但不能改变指向!(常指针)”
指针变量的运算:①赋值;②加减一个整数(移动位置;对数组);③两个指针比较(对数组才有意义);④两个指针相减(对数组,相隔元素个数)。总之:指针运算仅针对数组才有意义!
2 指向一维数组的指针
首地址:&a[0]、a、p;第i+1个元素的值:a[i]、p[i]、*(a+i)、*(p+i);第i+1个元素的地址:&a[i]、a+i、p+i。
注意:a是常量,不可改变(如a++是错的);p是(指针)变量,可改变(如p+=n,且p新址=p旧址+n×sizeof(指针类型)=p旧址+n×4(因sizeof(T *)=4))。
3 指向二维数组的指针
行地址:每行的首地址(以“行”变化),a=a+0、a+1、a+i、&a[i];列地址:数组元素的地址(以“元素”变化),*(a+0)=*a=a[0]、*(a+1)=a[1]、*(a+i)=a[i];【“*”+行地址→列地址;*+()→[]】普通指针:指向元素,赋值也只能是“列地址”,以“元素”为单位变化;专有指针:指向每行,赋值也只能是“行地址”,以“行”为单位变化;【定义:类型 (* 指针变量名)[长度],这里的指针变量是“行指针”】a[i][j]表示过程:行地址(a)→行偏移(a+i)→加“*”转为列地址(*(a+i)=a[i])→列元素偏移(*(a+i)+j=a[i]+j)→加“*”取元素(*(*(a+i)+j)=*(a[i]+j)=a[i][j]);值:a[i][j]=*(*(a+i)+j)=*(a[i]+j)=(*(a+i))[j];地址:&a[i][j]=*(a+i)+j=a[i]+j。
注解:如a[3][4],数组名有:a、a[0]、a[1]、a[2];数组有:a[3]、(a[0])[4]、(a[1])[4]、(a[2])[4](即二维由一维扩展而成→先列向后行向);等价地址有:a(行址)、a[0](列址)、a(列址)、&a[0][0](元素址);行址通式:a+i;列址通式:(a+i)=a[i]。
4 例子与理解
(1)多维数组a(数组名),其本质是一个指向数组(a[0]/a[1]/a[2]~)的指针,多维数组的元素也是数组。除第一维外的所有维都是元素类型的一部分。 实参为一维数组,则形参为普通指针;实参为二维数组(数组名是“行地址”),形参为二维专用指针(才能接受“行址”)。(2)指针&二维数组:
int a[2][3] = { { 1,2,3 },{ 4,5,6 } };
int(*p)[3] = a; //行址(a+i)=(p+i)、列址*(a+i)+j=a[i]+j=p[i]+j、p=a
cout << **p << endl; //=>*(*(p+0)+0), 1
cout << **(p + 1) << endl; //=>*(*(p+1)+0), 4
cout << *(*p + 1) << endl; //=>*(*(p+0)+1), 2
cout << *(p[0] + 1) << endl; //=>*(*(p+0)+1), 2
cout << *(p[1]) << endl; //=>*(*(p+1)+0), 4
(3)sizeof()的作用值(a一定符合,注意p的!):
int a[5] = { 1,2,3,4,5 }, *p = a; //仅将a的首地址赋予p
cout << "&a[0]:" << &a[0] << endl; //&a[0]=a=p
cout << "a-p:" << a - p << endl; //0
cout <<"sizeof(a):"<< sizeof(a) << endl; //20
cout << "sizeof(p):" << sizeof(p) << endl; //=>sizeof(int *)=4
总结:对一维,sizeof§不能求出长度,仅能sizeof(a)。并且形参不管怎么写都是“p”,所以一定有int n。
int a[2][3] = { 1,2,3,4,5,6 }, (*p)[3] = a;
cout << "sizeof(a):" << sizeof(a) << endl; //24
cout << "sizeof(a[1]):" << sizeof(a[1]) << ", sizeof(*(a+1)):" << sizeof(*(a + 1)) << endl; //12
cout << "sizeof(a[1][0]):" << sizeof(a[1][0]) << ", sizeof(*(*(a+1)+0)):" << sizeof(*(*(a + 1) + 0)) << ", sizeof((*(a+1))[0]):" << sizeof((*(a + 1))[0]) << endl; //4
cout << "sizeof(p):" << sizeof(p) << endl; //4【注意这里不同】
cout << "sizeof(p[1]):" << sizeof(p[1]) << ", sizeof(*(p+1)):" << sizeof(*(p + 1)) << endl; //12
cout << "sizeof(p[1][0]):" << sizeof(p[1][0]) << ", sizeof(*(*(p+1)+0)):" << sizeof(*(*(p + 1) + 0)) << ", sizeof((*(p+1))[0]):" << sizeof((*(p + 1))[0]) << endl;//4
总结:对二维,sizeof(p)不能求出长度。此外,由于形参应为(*p)[列数],失去了通用性(尽管sizeof(p[i])、sizeof(p[i][j])还可以用)!所以,二维数组作形参仅能传替“列数”(这是已知/必须的),还至少应加上int m(行),即写成:func(int [][10],int m)或func(int(*p)[10],int m)。引申三维:func(int a[][4][10], int m)。二维数组作形参想具备通用性,则必定使用模板!
附上sizeof()用法:
//sizeof是操作符(operator):返回一个对象或类型所占“内存字节数”
int i = 1;char str[] = "abcd";int a[] = { 1,2,3 };
cout << sizeof(int) << endl; //值为4
cout << sizeof(i) << endl; //值为4,等价于sizeof(int)
cout << sizeof i << endl; //值为4
cout << sizeof(2 + 3.14) << endl; //值为8,等价于sizeof(double)
cout << sizeof(str) << endl; //值为5('\0')
cout << sizeof(a) << endl; //值为12=4×3
char ary[sizeof(int) * 10]; //OK,编译无误
(4)C++一维、二维数组作形参:
1)一维数组作形参:
void dim1_para(int p[], int n)
{
//第一种
for (int i = 0;i < n;i++)
{
*(p + i) = *(p + i) * 2;
}
//第二种
for (int *t = p;t < p + n;t++)
{
*t = *t * 2;
}
}
2)二维数组作形参:
void dim2_para(int [][10],int m)或void dim2_para(int(*p)[10],int m) //毫无通用性
{
/*函数体 */
}
(5)函数返回二维数组:
1)方法一(多级指针,参数至多一维):
//函数
int **dim2_Return(int m,int n)
{
int **ret;//堆区不随函数退出而释放
ret = (int**)malloc(m * sizeof(int*));
for (int i = 0;i < m;++i)
{
ret[i] = (int*)malloc(n * sizeof(int));
for (int j = 0;j<n;++j)
{
ret[i][j] = i;
}
}
return ret;
}
总结:要想返回二维数组,必须动态申请堆区空间,否则函数返回栈区释放!(此同样适用于返回一维数组)
//main()中调用
int main()
{
int **cpy = dim2_Return(3, 4);//错误:int cpy[3][4] = dim2_Return(3, 4);
for (int i = 0;i < 3;++i)
{
for (int j = 0;j<4;++j)
{
printf("%d ", cpy[i][j]);
}
printf("\n");
free(cpy[i]); //先释放一级指针
}
free(cpy);//再释放二级指针
return 0;
}
总结:“谁申请谁释放”,调用地一定要做好空间释放工作。
2)方法二(模板函数,参数可二、可一(一看情况)):
template <typename T, unsigned M, unsigned N> //矩阵转置
T(*transM(T(&mat)[M][N]))[M]
{
T(*t)[M] = new T[N][M];
for (int i = 0;i < M;i++)
{
for (int j = 0;j < N;j++)
t[j][i] = mat[i][j];
}
return t; //调用需释放
}
/*释放格式:delete []t;*/
总结1)2):从函数返回二维数组,指针数组(T *p[N])无望。二维数组指针变量(专有指针T (*p)[N])在模板下可用、二级指针(T **p)可用(这两者都需动态分配内存)。
深入理解C/C++指针(二)整装完毕,等待您的检阅(▽)~~~
本文深入解析C/C++中的指针概念,包括一维和二维数组的指针使用方法,指针运算规则,以及如何通过指针传递数组到函数,并详细探讨了指针在数组、函数参数和返回值中的应用。
&spm=1001.2101.3001.5002&articleId=96472538&d=1&t=3&u=3f65da46130940af9043a120c9d66e88)
375

被折叠的 条评论
为什么被折叠?



