1. 指针概念
1、变量的地址
我们知道,在计算机的语言里,变量都存在地址,比如定义变量int num,那么使用取地址符 &num,我们就可以得到num这个变量在计算机中的地址。
同样的,对于数组,比如定义一个数组 int num[10],同样使用 &num[0]来得到数组num的首地址。这里需要注意的是,数组名 num 本身也表示这个数组的首地址。
2、直接访问和间接访问
举一个生活的例子:甲有要事找丙。
第一种情况:
如果甲知道丙的住址,那他直接去访问丙就可以了,这就是直接访问。
第二种情况
那如果甲不知道丙的住址怎么办呢?假如这个时候刚好乙知道丙的住址,且甲有乙的地址(甲可直接访问乙),那么就可以产生以下操作:
- 甲先访问乙,从乙处得到丙的住址
- 甲按乙所提供的丙的地址去访问丙
这就是我们所说的间接访问,从而引出了指针的概念。
3、指针的概念
对应直接访问,变量的直接访问就是,int i ; i=3 来访问i(2000表示的变量i在计算机的地址)。

在计算机中,指针就相当于间接访问例子中的乙,我们从乙处得到丙的地址,再去访问丙。如下图所示:
int * i_pointer 表示的就是指针变量,指针里面存放的是其他变量的地址,而不是一个值(比如这里指针指向的是变量i,指针存放的不是i的值3,而是变量i在计算机里的地址2000)。因为存放的是地址,所以我们用一个*号来进行定义区分。
那么定义完了指针变量,这个指针存放的是哪个变量的地址呢?只需要将指针变量i_pointer指向变量i的地址即可。这里的指向我们使用的是=,而变量i的地址使用的是取地址符&i。

这样我们就通过两步完成了指针的定义:第一,定义指针变量;第二,将指针指向其他变量的地址进行赋值。也可以合并为一个语句,完成对变量i的间接访问。
int *i_pointer = &i
总结一下,
- 指针:变量的地址称为该变量的指针。上述的 i_pointer就是指针,表示的是变量i的地址。
- 指针变量:专门用来存放“另一个变量地址(即指针)”的变量。即上述的int *i_pointer就是指整形指针变量,存放的是变量i的地址。由于我们可以通过变量的i的地址来访问变量i的值,所以 *i_pointer表示的就是变量i的值。
*i_pointer是指针,是地址;i_pointer是指针变量,是值
4、指针的类型、定义与赋值
(1)指针的定义:*数据类型 指针变量名
- 存放整型变量的地址–整型变量指针 int *ip
- 存放整型常量的地址–整型常量指针 const int *icp
- 存放字符变量的地址–字符变量指针 char *cp
(2)指针的赋值
我们知道变量必须先赋值,再使用。给指针变量赋初值,也叫做初始化指针变量,其实就是取地址。再次重复如下:
int *iPtr; //定义整型变量指针
int iCount=18; //定义整型变量
iPtr=&iCount; //取iCount的地址存放到iPtr中
在VS中进行测试如下,所以只要理解*p是值,p是地址即可。
#include<iostream>
using namespace std;
int main()
{
int count = 10; //定义整型变量
int *p; //定义整型变量指针,*p表示指针p指向的数据变量count
p = &count; //取count的地址存放到p中。取地址符,p表示的是地址
cout << p <<" " //0x7ff7befb15ac
<< &count << " " //0x7ff7befb15ac
<< *p << " " //10
<< count << endl; //10
double d = 2.333; // 定义整型变量
double *dp = &d; // 也可以定义指针变量的同时赋值
cout << dp << " " //0x7ff7b99de5a8
<< &d << " " //0x7ff7b99de5a8
<< *dp << " " //2.333
<< d << endl; //2.333
return 0;
}
2. const指针
1、&—取地址运算
由于指针变量也是变量,所以由于指针指向的变量不同,指针变量也会改变。
#include<iostream>
using namespace std;
int main()
{
int *p;
int x=1,y=2;
p = &x; //p 指向 x
cout << *p <<endl; // 输出1
p = &y; //p 指向 y, now
cout << *p <<endl; //输出2
return 0;
}
2、const指针
这就引出了const指针的知识点,根据const限定的是int变量还是指针p变量,可以分为如下三种情况
- 指向常量的指针(常量指针):指针指向的对象i是常量,而指针本身p是变量。
- const 数据类型 * 指针名 = &常量名
- 指针常量:指针本身p是常量,而指针指向的对象i可以改变
- 数据类型 * const 指针名 = &变量名
- 指向常量的指针常量(常量指针常量):指针指向的对象和指针本身都是常量
- const 数据类型 *const 指针名 = &常量名
我们接下来看几个例子
const int a =89,b=60; //a,b是常量,指针p是变量
const int *p=&a;
p=&b; //ok,p是变量,可以指向a,也可以指向b
*p=100; //error,*p表示的是a的值,这里a是常量,不能修改
int a =89,b=60; // a,b是变量,p是常量,指向a的地址
int *const p = &a;
p=&b; //error,p是常量,已经指向a的地址了,不能再修改
*p=100; //ok,*p表示的是a的值,a是变量,可以修改
const int a =89,b;
const int *const p = &a;
p=&b; //error
*p=100; //error,同理
3. 指针和一维数组的关系
既然我们可以通过i=1来直接访问i变量,为什么还需要通过指针来访问变量呢?确实,用指针来访问单变量是没有意义的,那指针有什么用呢?
1、指针运算
我们先来进行一下测试,输出数组每个元素的地址和值
#include<iostream>
using namespace std;
int main()
{
const int N =5;
int num[5] = {1,2,3,4,5};
int *p = &num[0];
for(int i=0;i<N;i++)
{
cout << "address:" << &num[i] << " " << p+ i <<endl;
cout << "value:" << num[i] << " " << *(p+i) <<endl;
}
return 0;
}
运行结果如下图所示,可以看到
数组元素地址:&num[i] = p + i
数组元素值:num[i] = *(p + i )
且可以看到,因为这里的数组是int类型,每个数组元素间隔4个字节,所以&num[i] = p + i = p + sizeof(int)

这就是指针运算。指针可以进行加减运算,表示在内存中移动指针。一般将数组起始地址赋值给指针,通过指针运算(移动指针)对数组元素进行操作。
- 指针数组赋值
int a[10];
int *p=&a[0]; //指针指向数组起始地址
或
int *p=a; //数组名本身是数组的起始地址 //也称数组指针
- 指针移动:
数据类型 *p = 值;
p+n = p + sizeof(数据类型)*n //指向数组才有意义
p-n = p – sizeof(数据类型)*n //向前、向后跳过的元素数
- 指针相减
p – q /*中间间隔元素数,必须指向同一数组*/
- 指针比较
p == q, p<q, etc. /*必须指向同一数组,前后关系*/
2、指针与数组
指针和一维数组的关系只需要理解两个核心点即可:
-
指针指向一维数组时,指针当数组名使用
-
根据[ ]变址运算符,a[i] = *(a+i)
基于这两个点,我们对数组元素的地址和值都有多种表示方法。
int a[10];
int *p=a; // 或者int *p=&a[0] 表示指针指向数组起始地址
&a[i] = a + i = &p[i] = p + i // 数组元素地址的等价表示
a[i] = * (a + i) = p[i] = *(p + i) // 数组元素值的等价表示
理解了指针和一维数组的关系,我们对数组进行求和也有了多种方法。
#include<iostream>
using namespace std;
int main()
{
const int N = 5;
int num[5] = {1,2,3,4,5};
int *p;
int sum, i;
for(sum = 0, i = 0;i<N;i++) //最简单的方式
sum += num[i];
cout << sum << endl; //输出15
for(sum = 0,p = num;p < num + N;p++) //使用num来控制
sum += *p;
cout << sum << endl; //输出15
for(sum=0,i=0,p=num;i<N;i++) //使用i来控制
sum += *(p+i);
cout << sum << endl; //输出15
return 0;
3、堆分配内存
- 堆内存 :存放程序动态数据的内存空间,允许程序根据需要申请一定大小的空间,使用完毕可以释放该空间。
分配:数据类型 *指针名=new 数据类型[下标表达式];
释放:delete []a;
例:1) int *a = new int[10];
delete []a;
2) int *a = new int[10]{1,2,3,4,5};
delete []a;
- 空指针
int *p = NULL;
int *p = nullptr; //使用的多,C++11定义
4、指针与函数
函数传值和函数传指针
我们先来看一个例子
#include<iostream>
using namespace std;
void swap1(int x, int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
void swap2(int *px, int *py)。 //这里使用指针
{
int temp;
temp = *px;
*px = *py;
*py = temp;
}
int main()
{
int a=3,b=8;
swap1(a,b);
cout<<a<<" "<<b<<endl; //3 8
swap2(&a,&b); //因为传的是指针,所以这里的参数要取地址,表示指针指向的变量的地址
cout<<a<<" "<<b<<endl; // 8 3
return 0;
}
上述例子可以看到,函数swap1在函数里传的是值,在主函数中调用swap1时并没有改变参数的值。函数传值相当于是备份,同文件复制,复制文件修改,不影响原文件。
而swap2在函数里传的是指针,在主函数中调用sawp2的时候参数的值改变了。函数传指针时,实参、虚参共享空间,同创建文件链接,所以会同时改变。
所以记住:
- 传值不改变参数的值。
- 传指针改变参数的值。
函数传数组
那么如果函数要传数组呢?前面已经讲过,针指向一维数组时,指针当数组名使用,所以传数组首地址,即指针。因此传指针也是传数组。对其进行递增递减的操作可访问数组元素。
我们来进行一个练习: 写函数sort,对数组a进行升序排序。
void sort( int *a, int size ) ,根据指针和数组关系,int *a为传数组。
#include <iostream>
#include <iomanip>
using namespace std;
//void input(int n, int num[]) 输入数组
void input(int n, int *num)
{
for (int i = 0; i < n; i++)
cin >> num[i];
}
//void output(int n, int num[]) 输出数组
void output(int n, int *num)
{
for (int i = 0; i < n; i++)
cout << num[i] << " ";
}
//传地址改变参数值,交换函数
void swap1(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
//void sort(int n, int num[]),排序函数
void sort(int n, int *num)
{
int i, j;
for (i = 1; i < n; i++)
for (j = 0; j < n - i; j++)
if (num[j] < num[j + 1])
swap1(&num[j], num + j + 1); //num[j+1] = *(num+j+1)
}
int main()
{
int n,i;
cin >> n;
int* p = new int[n]; //动态内存分配
if (p == nullptr) //C++11 判断是否是空指针,这里仅做测试用
{
cout << " new error!" << endl;
exit(0);
}
input(n, p);
cout << "--------" << endl;
sort(n, p);
output(n, p);
delete []p; //释放内存
}
指针函数
返回指针的函数称为指针函数。返回的可以是单变量地址或者数组首地址,但是要保证返回的指针(地址)不能是局部指针变量,即要保证出了函数之后函数空间仍然没有释放。
#include <iostream>
#include <iomanip>
using namespace std;
//返回数组首地址,要保证地址不是局部变量,出了函数之后地址还在
char* createstr(int n)
{
//char str[100]; //error,注意:返回的指针可以是堆地址、全局或静态变量的地址,但不能是局部指针变量。
//static char str[100]; // ok,保证出了这个函数后地址还存在
int i;
char* str = new char[100];
for (i = 0; i < n; i++)
{
str[i] = 'A' + i;
}
str[i] = 0;
return str; //返回数组首地址
}
int main()
{
cout << createstr(10) << endl; //ABCDEFGHIJ
}
5、指针和二维数组
二维数组,可以理解为两个一维数组,如下图所示:
int a[N][M]; //假设N,M为已定义的常量。
int (a[N])[M]; //将A数组理解为两个一维数组

虽然说是二维数组,但其实在计算机中是以连续地址进行存放的,我们来看下面这个例子:分别输出二维地址每个元素的地址。
#include<iostream>
using namespace std;
int main()
{
int num[3][4] = {1,2,3,4,5,6,7,8,9};
for(int i=0;i<3;i++)
{
for(int j=0;j<4;j++)
{
cout << & num[i][j]<<" ";
}
cout<<endl;
}
}
输出结果如下,可以看到二维数组其实每个元素的地址都是连接在一起的,就像排队一样,只需要知道首地址,就可以通过加减运算访问二维数组的所有元素。
0x7ff7bd550580 0x7ff7bd550584 0x7ff7bd550588 0x7ff7bd55058c
0x7ff7bd550590 0x7ff7bd550594 0x7ff7bd550598 0x7ff7bd55059c
0x7ff7bd5505a0 0x7ff7bd5505a4 0x7ff7bd5505a8 0x7ff7bd5505ac
接下来我们来看二维数组有哪些访问方式?
方式一:不使用指针,使用数组直接访问
从下面测试可以看出,num和num+1之间间隔了16个字节,也就是跨越了一行(1行4个int元素,1个int类型4个字节);num[0]和num[0]+1跨越了4个字节,也就是相邻元素。
int main()
{
int num[3][4] = {1,2,3,4,5,6,7,8,9};
int *p; //p+1=p+sizeof(int)
cout<<num<<endl; //0x7ff7b1836540
cout<<num+1<<endl; //0x7ff7b1836550
cout<<num[0]<<endl; //0x7ff7b1836540
cout<<num[0]+1<<endl; //0x7ff7b1836544
}
方式二:使用指针,指针指向二维数组的首地址,也就是int * p;p=num[0]或者p = &num[0][0]
看下面这个测试,使用指针输出二维数组每个元素的地址和值。
#include<iostream>
using namespace std;
int main()
{
int num[3][4] = {1,2,3,4,5,6,7,8,9};
int *p; //p+1=p+sizeof(int)
//p=num; //error,num是行指针,对应一行,num+1跨越一行
p = num[0]; //指向一维数组首地址,通过num[0]访问整个二维数组
//p = &num[0][0] //这种方式也可以,都是指向首地址
for(int i=0;i<3;i++)
{
for(int j=0;j<4;j++)
{
cout<<"address "<<"row "<<i<<" "<<"col "<<j<<" "<<": "<<&num[i][j]<<" "<< p+i*4+j<<" "<<&p[i*4+j]<<endl;
cout<<"value "<<"row "<<i<<" "<<"col "<<j<<" "<<": "<<num[i][j]<<" "<<*(p+i*4+j)<<" "<<p[i*4+j]<<endl;
}
cout<<endl;
}
}
运行结果如下:
address row 0 col 0 : 0x7ff7b89f8580 0x7ff7b89f8580 0x7ff7b89f8580
value row 0 col 0 : 1 1 1
address row 0 col 1 : 0x7ff7b89f8584 0x7ff7b89f8584 0x7ff7b89f8584
value row 0 col 1 : 2 2 2
address row 0 col 2 : 0x7ff7b89f8588 0x7ff7b89f8588 0x7ff7b89f8588
value row 0 col 2 : 3 3 3
address row 0 col 3 : 0x7ff7b89f858c 0x7ff7b89f858c 0x7ff7b89f858c
value row 0 col 3 : 4 4 4
address row 1 col 0 : 0x7ff7b89f8590 0x7ff7b89f8590 0x7ff7b89f8590
value row 1 col 0 : 5 5 5
address row 1 col 1 : 0x7ff7b89f8594 0x7ff7b89f8594 0x7ff7b89f8594
value row 1 col 1 : 6 6 6
address row 1 col 2 : 0x7ff7b89f8598 0x7ff7b89f8598 0x7ff7b89f8598
value row 1 col 2 : 7 7 7
address row 1 col 3 : 0x7ff7b89f859c 0x7ff7b89f859c 0x7ff7b89f859c
value row 1 col 3 : 8 8 8
address row 2 col 0 : 0x7ff7b89f85a0 0x7ff7b89f85a0 0x7ff7b89f85a0
value row 2 col 0 : 9 9 9
address row 2 col 1 : 0x7ff7b89f85a4 0x7ff7b89f85a4 0x7ff7b89f85a4
value row 2 col 1 : 0 0 0
address row 2 col 2 : 0x7ff7b89f85a8 0x7ff7b89f85a8 0x7ff7b89f85a8
value row 2 col 2 : 0 0 0
address row 2 col 3 : 0x7ff7b89f85ac 0x7ff7b89f85ac 0x7ff7b89f85ac
value row 2 col 3 : 0 0 0
可以看到,对于二维数组,由于变址运算符的存在,下面的三种访问方式是等价的。
address:&num[i][j] = p+i*4+j = &p[i*4+j]
value: num[i][j] = *(p+i*4+j) = p[i*4+j]
需要注意的是,对于二维数组来说,当指针指向数组首地址时,指针是不能当作数组名来使用的。
需要注意的是,我们这里指针指向的都是数组头,但是其实指针是可以指向任何一个数组元素的。
可以看到,这种访问方式是很麻烦的,还要去算一行有多少个元素,再去加减。所以访问二维数组最好的方式是使用行指针。
第三种访问方式,行指针。它是一个指针,指向一维数组(它不是指向一个数,指向的是一行),叫数组指针。
定义方式是,*int num[][]; int(p)[4] = num;
需要注意的是,指针符号*和变址运算符[]结合再一起时,[]的运算优先级更高。int (*p)[4] 就表示p是一个指针变量,这个指针指向的变量类型是 int [4],也就是含有4个元素的一维数组,所以我们说这是一个行指针。
从下面的例子可以看出,对于二维数组来说,当使用行指针的访问方式时,指针相当于数组名(num+i = p+i)。所以我们说使用行指针访问二维数组是最方便的。
#include<iostream>
using namespace std;
int main()
{
int num[3][4] = {1,2,3,4,5,6,7,8,9};
//行指针, 它是一个指针,指向一维数组,叫数组指针
int(*p)[4] = num;
for (int i = 0; i < 3; i++)
cout << num + i << " " << p + i << endl;
return 0;
}
/*输出结果
0x7ff7bcc55580 0x7ff7bcc55580
0x7ff7bcc55590 0x7ff7bcc55590
0x7ff7bcc555a0 0x7ff7bcc555a0
*/
行指针访问二维数组总结
所以,对于二维数组的访问方式总结一下。关键在于理解变址运算符和指针的等价关系,即对[]不断地进行变址。

我们使用程序来验证一下:
#include<iostream>
using namespace std;
int main()
{
int num[3][4] = {1,2,3,4,5,6,7,8,9};
int(*p)[4] = num;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 4; j++)
{
//address, &num[i][j]
cout << &num[i][j] << " " << num[i]+j << " " << *(num+i) + j << " "<< &(*(num+i))[j] << endl;
cout << &p[i][j] << " " << p[i] + j << " " << *(p + i) + j << " " << &(*(p + i))[j] << endl;
//val, num[i][j]
cout << num[i][j] << " " << *(num[i] + j) << " " << *(* (num + i) + j) << " " << (*(num + i))[j] << endl;
cout << p[i][j] << " " << *(p[i] + j) << " " << *(*(p + i) + j) << " " << (*(p + i))[j] << endl;
}
return 0;
}
*/
这里我们回顾一下之前的一维数组访问方式。
address:&a[i] = a + i = &p[i] = p + i
value:a[i] = * (a + i) = p[i] = *(p + i)
例题:用指针实现转置
#include<iostream>
using namespace std;
int main()
{
int num[4][4] = { 1,2,3,4,5,6,7,8,9 };
int i, j;
// 访问方式一:指针指向首地址
int* p = num[0];
//4*4矩阵,交换
for(i=0; i<4; i++)
for (j = 0; j < i; j++)
{
//[i][j],[j][i]
swap(p[i * 4 + j], p[j * 4 + i]);
}
//输出
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
cout << *(p + i * 4 + j) << " ";
}
cout << endl;
}
// ——————————————————————————————————————————
// 访问方式二:行指针
int(*q)[4] = num;
//4*4矩阵,交换
for (i = 0; i < 4; i++)
for (j = 0; j < i; j++)
{
//[i][j],[j][i]
swap(q[i][j], q[j][i]);
}
//输出
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
cout << q[i][j] << " ";
}
cout << endl;
}
return 0;
}
二维数组的动态内存分配
分配
//定义:分配n行m列的二维数组空间
int **numArray;
//第一步,分配n个元素,每个元素是指针
numArray = new int*[n];
//第二步,对n行的每个元素分配一维数组,含m个元素
for(int i=0; i<n; i++)
numArray[i] = new int[m];
释放
//释放n行m列的二维数组空间
//第一步,释放n行空间,即n个一维数组
for(int i=0; i<n; i++)
delete []numberArray[i];
//第二步,释放最初分配的一维数组
delete []numberArray;
例子
#include<iostream>
using namespace std;
int main()
{
int i, j;
int** p;
int n, m;
cin >> n >> m;
//分配n行m列
p = new int*[n];
for (i = 0; i < n; i++)
p[i] = new int[m];
//输入,分配完就可以当作数组名使用了
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
cin >> p[i][j];
}
//输出
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
cout << p[i][j] << " ";
cout << endl;
}
//释放
for (i = 0; i < n; i++)
delete[]p[i];
delete[]p;
return 0;
}
但需要注意的是,动态分配后的二维数组不一定是连续,所以memcpy、memset不可用
memset(num, 0, sizeof(int) * 4 * 4); //ok , 连续空间ok
memset(p, 0, sizeof(int) * 4 * 4); //error,不连续空间
6、数组指针(行指针)和指针数组(数组)
#include<iostream>
using namespace std;
int main()
{
/*行指针, 它是一个指针,指向一维数组,叫数组指针
int(*p)[4] = num;
for (int i = 0; i < 3; i++)
cout << num + i << " " << p + i << endl;
*/
//p是数组,每一个元素是指针,叫指针数组
int *p[20];
int a = 10, b = 20, c = 30;
p[0] = &a;
p[1] = &b;
p[2] = &c;
for (int i = 0; i < 3; i++)
{
cout << p[i] << " " << *p[i] << endl;
cout << &a << " " << a << endl;
}
return 0;
}
6、字符指针
字符数组和字符串常量
C++中的字面字符串有两种:
char buffer[]=“hello”; //用于字符数组初始化,不占空间
cout<<“good”<<endl; //字符串常量,占有存储空间
当编译器遇到一字符串,就把它放到全局数据区的const区中,以’\0’作为结束符,并记下它的起始地址;
在以后的代码中,使用到该字符串就使用该地址,所以字符串就“变成”了地址。所以我们可以指针变量指向字符串常量。
char *p = “hello world”
我们经常将指针数组和字符串结合起来。这个例子的 const char * city[20] 就是一个指针数组,包含20个元素,每个元素都是一个指针,每个指针都指向字符串的首地址,但因为“beijing”等元素不能改变,所以需要加上const
#include<iostream>
using namespace std;
int main()
{
const char * city[20] = {"beijing","wuhan","guangzhou" };
for(int i=0;i<3;i++)
cout << city[i] << " " << *city[i] <<endl;
}
/* 输出1:运行结果
beijing b
wuhan w
guangzhou g
*/
C++中可以用字符串初始化字符数组,但不能对字符数组赋予字符串。
char buffer[10]=“hello”; //初始化,ok
char buffer[10];
buffer=“hello”; //数组名赋值,error
char *pstr;
pstr=“hello”; //字符指针赋值,ok
可以将字符串复制到字符数组,但不可以复制到字符指针。因为指针指向字符串的方法没有空间。
char buffer[10];
strcpy(buffer,“hello”); // ok
char *pstr;
strcpy(pstr,"hello"); //error,没有空间
typedef类型定义
输入n, 输入n个城市名,输出其字典升序排序
为了解决这个问题,我们需要定义一个数组指针,指向一维数组,含20个字符。
//char (*p)[20]; //数组指针
//p = new char[20][n]; //error,没有这种定义,所以需要使用typedef
所以需要使用到typedef,它有两个作用:
作用一:为现有类型创建别名,定义易于记忆的类型名
typedef long long ll;
// ll是longlong类型的别名
// longlong num; 与 ll num;等价
作用二:掩饰复合类型,如指针和数组
typedef char name[20];
//name是含20个字符的数组类型的别名
//char cityName[20] ; 与 name cityName;等价
typedef int * int_pointer;
//int_pointer是int *类型的别名
//int *pointer;与 int_pointer pointer; 等价
在这里我们使用typedef来解决
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
typedef char name[20];
name* p;
int n;
cin >> n;
p = new name[n];
for (int i = 0; i < n; i++)
cin >> p[i];
for (int i = 0; i < n; i++)
cout << p[i] << endl;
return 0;
}
/* 程序测试
3
beijing shenzhen shanghai
beijing
shenzhen
shanghai
*/
7、函数指针
函数指针,它是指针,指向函数(两种方式指向函数,第一种是等于函数名,一种是指向函数取地址)。函数指针的声明:
返回值类型 ( * 指针变量名) ([形参列表]);
- 返回值类型—函数的返回类型,
- 形参列表—指针变量指向的函数所带的参数列表。
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
//函数指针,它是指针,指向函数
//以系统自带的sqrt ,fabs为例
double (*fun)(double); //声明一个函数指针
fun = sqrt; //第一种方式:指针变量名等于函数名
cout << fun(10) << endl; //调用
fun = &fabs; //第二种方式:函数名取地址
cout << fun(-10) << endl;
return 0;
}
本文深入介绍了C++中的指针,包括指针的概念、直接访问与间接访问、指针的类型定义与赋值、const指针、指针与一维数组的关系、堆内存分配、指针函数、二维数组的指针访问以及动态内存分配。通过实例展示了如何使用指针进行数组排序、转置和动态分配。此外,还探讨了字符指针、函数指针以及typedef的作用。
1696

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



