一、指针与变量
1.取地址符&和取值符*
(1)&
int a;
cout<<&a<<endl;
//0x6ffe4c
char b[10];
cout<<&b<<endl;
//0x6ffe40
(2)*
int n=6;
int *p=&n;
cout<<*p<<endl;
//6
(3)进阶
char c='a';
char *p=&c;
//c的值
cout<<c<<endl; //a
//存储c变量名的地址
cout<<hex<<(long long)&c<<endl; //6ffe3f
//存储p变量名的地址
cout<<&p<<endl; //0x6ffe40
//p变量的值是p指针指向的地址,可以看出这是存储c变量名的地址
cout<<hex<<(long long)p<<endl; //6ffe3f
//p指针指向的对象的值
cout<<*p<<endl; //a
2.定义指针
(1)定义一个指针
一步到位:类型* 指针名 = &变量名
int n=6;
int *p=&n;
cout<<p<<endl;
//0x6ffe44
分步进行:类型* 指针名;指针名=&变量名
int n=6;
int *p;
p=&n;
cout<<p<<endl;
//0x6ffe44
(2)定义多个指针
int n=6,m=7;
int *p,*q;
//都要有*
p=&n,q=&m;
cout<<*p<<" "<<*q<<endl;
//6 7
3.通过指针修改值
int n=10;;
int *p=&n;
*p=6;
printf("%d %d\n",n,*p);
//6 6
4.指针传递
(1)一级指针
改变传递的指针的值:可以传递改变
int n=5;
int *p=&n;
int *q=p;
printf("%d %d %d\n",n,*p,*q);
//5 5 5
*q=3;
printf("%d %d %d\n",n,*p,*q);
//3 3 3
改变传递的指针的指向 :不可以传递改变
int n=3,m=5;
int *p=&n;
int *q=p;
printf("%d %d %d %d\n",n,m,*p,*q);
//3 5 3 3
q=&m;
printf("%d %d %d %d\n",n,m,*p,*q);
//3 5 3 5
(2)二级指针
规则同一级指针
改变传递的指针的值:
注意:下面*q=&m代表改变指针的值,它的实际意义是改变指针p指向的地址。
int n=3,m=5;
int *p=&n;
int **q=&p;
printf("%d %d %d %d\n",n,m,*p,**q);
//3 5 3 3
*q=&m;
//取值改变,但意义是*q==p,p=&m,改变p的指向
printf("%d %d %d %d\n",n,m,*p,**q);
//3 5 5 5
改变指针的指向:
int n=3,m=5,z=10;
int *p=&n;
int *x=&z;
int **q=&p;
printf("%d %d %d %d\n",n,m,*p,**q);
//3 5 3 3
q=&x;
printf("%d %d %d %d\n",n,m,*p,**q);
//3 5 3 10
5.函数传参
定义void vex(int *q),以及调用时vex§,其实就是int *q=p;
#include<iostream>
using namespace std;
void vex(int *q)
{
*q=6;
}
int main()
{
int n=10;;
int *p=&n;
vex(p);
cout<<n<<endl;
//6
return 0;
}
例子:通过指针来交换a和b的值
#include<iostream>
using namespace std;
void swap(int *p,int *q)
{
int temp=*p;
*p=*q;
*q=temp;
}
int main()
{
int a=3,b=4;
int *p=&a,*q=&b;
swap(p,q);
cout<<a<<" "<<b<<endl;
//4 3
return 0;
}
二、数组与指针
1.n等同于&n[0]
int n[10]={1,2,3,4,5};
int *p=n;
//其实就是int *p=&n[0]。这是数组的隐式转换
//当然写成int *p=&n[0]也对。
cout<<*p<<endl;
//1
//完整写法
int *q=&n[1];
cout<<*q<<endl;
//2
int m[10],n[10];
int i1=&m[5]-&m[3]; //指针或下标的减法,地址的值除以sizeof(int)
cout<<&m[5]<<' '<<&m[3]<<endl;
//0x6ffdf4 0x6ffdec
cout<<i1<<endl;
//2
cout<<0x6ffdf4-0x6ffdec<<endl;
//8
int i2=&m[5]-&n[3]; //无意义,每次实现都不确定
cout<<i2<<endl;
//-10
int*p1=m+5; //即p1=&m[5]
int*p2=m-5; //无意义
cout<<p1<<' '<<p2<<endl;
//0x6ffdf4 0x6ffdcc
2.指针遍历数组
int n[]={1,10,100};
int *p=n;
p++;
cout<<*p<<endl;
//10
//通常一起写作 cout<<*(++p)<<endl;
//注意:不要写成cout<<*(p++)<<endl; 你需要的是指针移位后的结果
*px++或*(px++),*++px或*(++px)。(*px)++,++(*px)或++*px
int n[]={1,2,3,4};
for(int *p=n;p<(n+4);p++) //p<(n+4)也可以写成p<&n[4]
{
cout<<*p<<" ";
}
//1 2 3 4
3.char指针等效于数组(注意:指针名和数组名一样)
(1)都可以通过使用指针的算术运算或数组索引来访问数组
int n[10]={1,2,3,4};
for(int i=0;i<4;i++)
{
cout<<n[i]<<" ";
}
//1 2 3 4
for(int *p=n;p<(n+4);p++)
{
cout<<*p<<" ";
}
//1 2 3 4
(2)指针和数组并不是完全互换的
将数组名变量以指针的形式使用
int n[10]={1,2,3,4};
cout<<*n<<endl;
//1 可以使用
把指针运算符 * 应用到 n 上是完全可以的,但修改 n 的值是非法的(n++就是n=n+1,n被用在左值出现在等于号左边了)。这是因为 n 是一个指向数组开头的常量,不能作为左值。
int n[10]={1,2,3,4};
for(int i=0;i<4;i++)
{
cout<<*n<<" ";
n++;
}
//error
只要不改变数组的值,仍然可以用指针形式的表达式。
int n[10]={1,2,3,4};
for(int i=0;i<4;i++)
{
*(n+i)=6;
cout<<n[i]<<endl;
}
(3)与函数
这六个函数就是为了说明指针和数组完全可以互化,除了(2)的n++情况。
#include <iostream>
#include <string.h>
using namespace std;
void vex1(char *p)
{
for(int i=0;i<strlen(p);i++)
{
cout<<p[i];
}
cout<<endl;
}
void vex2(char *p)
{
cout<<p<<endl;
}
void vex3(char *p)
{
for(int i=0;i<strlen(p);i++)
{
cout<<*(p+i);
}
cout<<endl;
}
void vex4(char t[])
{
for(int i=0;i<strlen(t);i++)
{
cout<<t[i];
}
cout<<endl;
}
void vex5(char t[])
{
char *p=t;
cout<<p<<endl;
}
void vex6(char t[])
{
for(int i=0;i<strlen(t);i++)
{
cout<<*(t+i);
}
cout<<endl;
}
int main()
{
char *s={"thanks"};
vex1(s);
vex2(s);
vex3(s);
cout<<endl;
char t[]={"sorry"};
vex4(t);
vex5(t);
vex6(t);
return 0;
}
/*
thanks
thanks
thanks
sorry
sorry
sorry
*/
4.字符串数组与指针
strlen()内可以使用字符串数组,也可以使用指向字符串的指针。(必须是char类型的,如strlen(int数组)就报错)
注意:p和*p。p输出字符串,*p输出单个char。
char n[10]={"thanks"};
char *p=n;
cout<<strlen(n)<<endl;
//6
cout<<strlen(p)<<endl;
//6
cout<<p<<endl;
//thanks
cout<<*p<<endl;
//t
cout<<*++p<<endl;
//h
ps:char[] 与int []的区别 :
int[] 通过指针输出的是地址,char[] 通过指针输出的是字符串。
int n[]={1,2,3,4};
int *p=n;
cout<<p<<endl;
//0x6ffe30
5.int二维数组传参
数组 | 调用形式 | 函数传参 | 含义 | 函数传参时维度指定 | 数值可更改? |
---|---|---|---|---|---|
int a[10][10] | a | (int a[10][10]) | 同样规模的数组 | 指定两个维度 | 可更改 |
int a[10][10] | a | (int a[][10]) | 可以省略第一维,但第二维不能省 | 指定第二维 | 可更改 |
int a[10][10] | a | int (&a)[10][10] | 二维数组的引用 | 指定两个维度 | 可更改 |
int a[10][10] | a | int (*a)[10] | 一维数组指针 | 指定第二维 | 可更改 |
int a[10][10] | (int**)a,m,n | int **a,m,n | 强制转换为指针的指针 | 需要附加传入m行n列 | 可更改 |
(1)参数int a[10][10]
#include <iostream>
using namespace std;
void vex(int a[10][10]){
cout<<a[0][0]<<endl;
//1
a[0][0]=6;
}
int main() {
// your code goes here
int a[10][10];
a[0][0]=1;
vex(a);
cout<<a[0][0]<<endl;
//6
return 0;
}
(2)参数int a[][10]
#include <iostream>
using namespace std;
void vex(int a[][10]){
cout<<a[0][0]<<endl;
//1
a[0][0]=6;
}
int main() {
// your code goes here
int a[10][10];
a[0][0]=1;
vex(a);
cout<<a[0][0]<<endl;
//6
return 0;
}
(3)参数int (*a)[10]
#include <iostream>
using namespace std;
void vex(int (*a)[10]){
cout<<a[0][0]<<endl;
//1
a[0][0]=6;
}
int main() {
// your code goes here
int a[10][10];
a[0][0]=1;
vex(a);
cout<<a[0][0]<<endl;
//6
return 0;
}
(4)参数int (&a)[10][10]
#include <iostream>
using namespace std;
void vex(int (&a)[10][10]){
cout<<a[0][0]<<endl;
//1
a[0][0]=6;
}
int main() {
// your code goes here
int a[10][10];
a[0][0]=1;
vex(a);
cout<<a[0][0]<<endl;
//6
return 0;
}
(5)参数int **a
#include <iostream>
using namespace std;
//m行n列
void vex(int **a,int m,int n) {
//cout << a[0][0] << endl;
//使用int **时,对于a[0][0],编译器不能正常寻址。
cout << *((int *)a+n*1+2) << endl;
//8
//*((int *)a+n*i+j),i行j列
*((int*)a) = 6;
}
int main() {
// your code goes here
int a[2][5] = {1,2,3,4,5,6,7,8,9,10};
//这是强制转化
vex((int**)a, 2, 5);
cout << a[0][0] << endl;
//6
return 0;
}
三、指针数组int *n[5]和数组指针int (*n)[5]
1.int *n[5]是指针数组
int *n[5]:包含5个int *类型的指针的数组,是一个数组。
PS:把类型结合起来看,int *表示指针,[5]表示五个,所以就是5个int *类型的指针的数组。
PS:指针数组-指针的数组
存放在栈中
int a=1,b=2;
int *p[2];
p[0]=&a,p[1]=&b;
cout<<*p[0]<<" "<<*p[1];
//1 2
对于局部变量,标准的编译器会被释放掉的(比如ideone.com),但有些编译器却不会(VScode和Visual Studio2019)。
但对于vector类型,都会被释放掉
#include <iostream>
using namespace std;
int main()
{
int* p[2];
{
int a = 1, b = 2;
p[0] = &a, p[1] = &b;
}
cout << *p[0] << " " << *p[1];
//0 0(ideone)
//1 2(VS和VScode)
return 0;
}
存放在堆中
#include <iostream>
using namespace std;
int main()
{
int* p[2];
p[0] = new int(1);
p[1] = new int(2);
cout << *p[0] << " " << *p[1];
//1 2
return 0;
}
2.int(*n)[5]是数组指针
int (*n)[5]:表示一个指针,该指针指向一个int型有5个元素的数组。
PS:*和n被()包围起来,那么类型就只是int,所以就是一个指向int数组的指针。
PS:数组指针-数组的指针
//int (*b)[5]用来指向列元素个数为5的二维数组
int a[2][5] = { {1,2,3,4,5},{6,7,8,9,10} };
int(*b)[5] = a;
//int (*b)[n]的n是和int a[m][n]的n对应相等。
//a可以理解为两个一位数组嵌套,外层是包含两个元素的一维数组,外层是包含五个元素的一维数组。
cout << *(*(b)) << endl;
//1
cout << *(*(b+1)) << endl;
//6
cout << *(*(b)+1) << endl;
//2
cout << b[0][2] << endl;
//3
四、指针与const
*前面的是对被指向对象的修饰,*后面的是对指针本身的修饰
1.常量指针
格式:int const* p;或 const int* p;
记法:(常量:int const或const int)*指针
又叫常指针,可以理解为常量的指针,指向的是个常量。所以不可以通过指针来修改指向的对象。。
int x=6;
const int* p = &x; //或const int* p;p=&x;
p = &y; //可以,修改指针的指向
*p = 123; //错误,不可以通过指针修改x的值
x = 666; //可以,可以直接修改x的值
2.指针常量
格式:int* const p;
记法:(指针*)常量
修饰的是指针,指针指向不可以改变,说明指针是常量,所以叫指针常量。
不可以修改指针指向,但可以通过指针修改内存空间的值。
int* const p = &x; //必须初始化赋值,int* const p;报错
p = &y; //错误,不可以修改指针的指向
*p = 123; //正确,但可以通过指针修改内存空间的值。
3.const int * const p;
既修饰了指针,也修饰了内存空间,都不可以修改
const int * const pp = &x;
pp = &y; //错误
*pp = 123; //错误
五、动态数组
1.一维动态数组
(1)下标赋值取值
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int* a = new int[n];
for (int i = 0; i < n; i++) {
a[i] = i;
cout << a[i] << ' ';
}
delete a;
return 0;
}
/*
5
0 1 2 3 4
*/
(2)指针赋值取值
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int* a = new int[n];
for (int i = 0; i < n; i++) {
*(a + i) = i;
cout << *(a + i) << ' ';
}
delete a;
return 0;
}
/*
5
0 1 2 3 4
*/
2.二维
https://blog.csdn.net/zhanshen112/article/details/80758850
参考: