指针
理解点一:地址
指针存储的是指向对象的地址,指针自身也有个地址;
代码:
#include <iostream>
using namespace std;
int main()
{
int a = 12; int b; int* p; int** ptr;
p = &a;
cout << "a的地址" << &a << endl;
cout << "p自身的地址" << &p<<endl;
cout << "p存储的地址" << p << endl;
*p = 24;
ptr = &p;
*ptr = &b;
**ptr = 34;
cout << "a="<<a<<endl<<"b="<<b<<endl;
cout << "b的地址" << &b << endl;
cout << "p自身的地址" << &p << endl;
cout << "p存储的地址" << p << endl;
cout << "ptr自身的地址" << &ptr << endl;
cout << "ptr存储的地址" << ptr << endl;
return 0;
}
代码运行结果:
解释:
(1)p为一级指针,p = &a;
说明了p指向了a的地址,即指针p存储了a的地址;而*p = 24;
通过运用取值运算符将p所指向地址即a的地址中存储的值赋值为24,即a=24;
(2)ptr为二级指针,ptr = &p;
说明了ptr指向了p指针自身的地址,即指针ptr存储了指针p自身的地址,即*ptr
的结果为指针类型,即指针p;而语句*ptr = &b;
则是将p指针指向了b的地址即指针p存储了b的地址,故**ptr = 34;
语句实际上是给b赋值为34;
理解点二:指针与数组
指针与数组的输出方式
已知定义一个数组int a[5] = { 1,2,3,4,5 };
和一个指针int *p=a;
,a为该数组的首地址,指针p指向数组a的首地址;
代码
for (int i = 0; i < 5; i++)
cout << a[i] << " ";
for (int i = 0; i < 5; i++)
cout << p[i] << " ";
for (int i = 0; i < 5; i++)
cout << *(a+i) << " ";
for (int i = 0; i < 5; i++)
cout << *(p+i) << " ";
for (int i = 0; i < 5; i++)
cout << *(p++) << " ";
运行结果:
解释:
以上五种方式输出结果相同,当指针p指向数组a的首地址时,a与p共同表示数组的首地址,则均可通过数组的方式或者指针地址改变的方式进行输出,但是cout << *(p++) << " ";
方式仅为指针所独有,这是指针与数组的差别之一;
一维数组与二维数组的联系
用一维数组的方式访问二维数组
#include <iostream>
using namespace std;
int main()
{
int a[3][5] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
int* p = a[0];
for (int i = 0; i < 3; i++)
for (int j = 0; j < 5; j++)
cout << p[i * 5 + j] << " "; //用一维数组的方式访问二维数组的15个元素
cout << endl;
for (int j = 0; j < 15; j++)
cout << *(p++)<<" ";
cout << endl;
return 0;
}
存储方式:
解释:
如图所示,左边是数组矩阵方式的理解,右边是数组存储方式,其存储地址是相连的;
二维数组与指针的联系
区别两个概念:数组指针和指针数组
int* p[3];
表示指针数组,即p是数组,数组元素是指针类型,而指针指向内容的类型是整型;
int(*p)[3];
表示数组指针,即p是一个指针,指针指向的内容是一个数组,数组元素是int类型;
数组指针
代码
#include <iostream>
using namespace std;
int main()
{
int a[3][5] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
int(*p)[5] = a;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 5; j++)
cout << *(p + i) + j << " ";
cout << endl; cout << endl;
for (int j = 0; j < 3; j++)
cout << *(p++) << " ";
cout << endl; cout << endl;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 5; j++)
cout << &(a[i][j]) << " ";
cout << endl; cout << endl;
return 0;
}
运行结果
解释
p是一个指针变量,它指向包含5个int元素的一维数组,此时p的增量以它所指向的一维数组长度为单位,故*(p+i)
是一维数组a[i][0]
的地址,*(p+i)+j
表示a[i][j]
的地址,而*(*(p+i)+j)
表示a[i][j]
的值;简而言之,a相当于二级指针,p与a等价,虽然p定义为一级指针,本质上相当于二级指针,要当作二级指针用,所以第一次用*取值取的是地址;
指针数组
代码
#include <iostream>
using namespace std;
int main()
{
char a[3][10] = {"How","are","you"};
const char* n[3] = { "How","are","you" };
for (int i = 0; i < 3; i++)
cout << a[i] << endl;
for (int i = 0; i < 3; i++)
cout << *(n+i) << endl;//n[i]
return 0;
}
运行结果
解释
系统给数组a分配了固定的3×10的空间(如上图中上面的表格),而给n分配的空间则取决于具体字符串的长度(如上图中下面的表格);此外,系统分配给a的空间是连续的,而给n分配的空间则不一定连续;
理解点三:字符数组与字符指针
字符数组具有的特点
(1)字符串数组能作为整体进行访问,但是需以’\0’结尾;
代码
#include <iostream>
using namespace std;
int main()
{
char name1[] = { 'a','b','c','d' };
char name2[] = "abcd";
for (int i = 0; i < 4; i++)
cout << name1[i];
cout << endl;
cout << name1 << endl;
cout << name2 << endl;
return 0;
}
运行结果
解释
此种定义方式char name1[] = { 'a','b','c','d' };
赋值时没有加’\0’,输出没有截止,所以会出现乱码(name1没有以’\0’结尾,故只是字符数组,不能算作字符串);
而此种赋值方式char name2[] = "abcd";
会自动在字符后面补’\0’,故此字符串数组可通过操作字符串数组名进行输出字符串;
注意:只有结尾有’\0’,才能构成字符串,才能当作一个字符串变量整体输出;
(2)输入时可以直接使用数组名作为输入对象,如果要读取空格,则需要使用cin.getline()给字符数组赋值;
代码
#include <iostream>
using namespace std;
int main()
{
char name1[100];
char name2[100];
cout << "输入字符串:" << endl;
cin >> name1;
cin.getline(name2, 100);
cout << "输出字符串1:" << endl;
cout << name1 << endl;
cout << "输出字符串2:" << endl;
cout << name2 << endl;
return 0;
}
运行结果
解释
cin输入遇到空格停止,cin.getline()可读取空格,遇到回车停止;
字符指针与字符数组的联系
代码
#include <iostream>
using namespace std;
int main()
{
char name1[100];
char *name2=name1;
cin.getline(name1, 20);
cout << name1 << endl;
cout << name2 << endl;
cout << name2 + 1 << endl;
return 0;
}
运行结果
解释
字符串数组名相当于字符串的首地址,即可通过输出字符串的首地址以输出其后连续内存空间所存储的内容,如cout << name2 + 1 << endl;
,其输出结果少了h,原因是从e开始输出其往后的内容;
注意:若要输出name1或name2中存储的地址值,则需使用语句cout << (void*)name1 << endl; cout << (void*)name2 << endl;
;