C++指针

前言:今天来梳理一下c++的指针吧,哎,我还是更喜欢c#多一点,奈何用c#的太少了,哎。
本文的内容均摘自 primer c++第五版,如果有错的地方那就是我抄错了。

1、指针基础

1.1 基本概念

指针是指向另外一种类型的复合类型。指针专门用来存放地址的。变量的指针就是变量的地址,用来存在变量地址的变量就是指针变量。
指针本身是一个对象,允许对指针赋值和拷贝;指针无需在定义的时候赋值。
除了两种特殊情况,其他的所有指针的类型都要和他指向的对象匹配

int *p1, *p2;  //定义两个指向int类型的指针
double *dp1, *dp2;  //定义两个指向double类型的指针

定义指针变量的时候注意:
(1)在定义指针变量的时候必须制定基类型
(2)不能用一个整数个一个指针变量赋值
(3)一个指针变量只能指向用一类型的变量

1.2 指针操作

获取对象地址,并通过*p访问对象

    int ival=42;
    int *p= &ival;
    cout<<*p<<endl; //42
    cout<<p<<endl;  //0x28ff08

复制,此时p2和p存的都是变量ival的地址

 int *p2= p;
 cout<<*p2<<endl; //42
 cout<<p2<<endl;  //0x28ff08 

改变*p的值

*p=0;
cout<<ival<<endl; //0
cout<<*p<<endl; //0
cout<<p<<endl;  //0x28ff08
cout<<*p2<<endl; //0
cout<<p2<<endl;  //0x28ff08
1.3 使用* &
//(1)当指针在声明的时候初始化
int i=2;
int *p=&i;   //合法,p中存储的是变量i的地址,*p是对p中存放的地址取值,&是对变量i取地址;
int *p = i;  //不合法

//(2)先声明,再赋值
int *p;
p=&i; //也合法
*p=i; //语法合法,但是对*p进行操作之前一定要对p进行赋值(初始化)
*p=&i; //不合法
p=i;//不合法

(3)关于引用
int &r=i; //r是一个引用也是i的别名,改变r也能改变i,改变i也能改变r
int &r=*p;  //也是合法的,可以简单理解为,*对地址取值,&对变量取地址
&r = j; //不合法,引用绑定之后再无法绑定其他对象
cout<<r<<endl;  //4
cout<<&r<<endl;  //0x28ff08

1.4 空指针

空指针不指向任何对象,在试图使用一个指针之前可以检查它是否为空,可以通过以下方式生成空指针

int *p=nullptr ;  //等价于 int *p=0;
int *p2=0; 
//需要首先#include cstdlib
int *p3=NULL; 等价于int *p3=0;

//注意:将int变量赋值给指针是错误的行为,即使变量等于0
int zero=0;
p=zero; //报错

//也可以先声明再赋值
   int *p1;
   p1=0;  //注意此处p1=0和*p1=0的区别
   if(p1==0){
    cout<<"p1被赋值为空指针"<<endl;
   }

 int *p1;
   *p1=0;
   if(p1==0){
    cout<<"p1被赋值为空指针"<<endl;
   }else{
       cout<<"p1不是空指针"<<endl;
   }
   //打印:p1不是空指针
1.5 赋值和指针

可以给指针重新赋值使指针指向一个新的地址,从而指向一个新的对象

int i=42;
int *p1=0; //p1被初始化一个空指针
int *p2=&i;  //p2指向i
int *p3;
p3=p2;  //p3也指向i

p2=0;  //p2称为一个空指针,不指向任何对象
cout<<*p3<<endl; 42
cout<<p2<<endl; 0

*p3=0;  //将地址指向的变量的值变为0
cout<<i<<endl;  //0
cout<<*p3<<endl; //0

1.6 指向指针的指针和指向指针的引用

一般来说声明中修饰符的个数并没有限制。当有多个修饰符的时候,按照逻辑关系解释即可,一般从右边向左边阅读变量的定义,离变量名最近的那个符号对变量的类型是最直接的影响。

(1)指向指针的指针

以指针为例,指针是内存中的对象,像其他对象也有地址,因此允许把指针的地址再存放到另一个指针当中。

通过*的个数可以区分指针的级别,**是指向指针的指针,*** 是指向指针的指针的指针

int i=1024;
int *p=&i; //p指向一个int型的数
int **pp=&p; //pp指向一个int型的指针
cout<<i<<endl;    //1024
cout<<*p<<endl;   //1024
cout<<**p<<endl;  //1024

(2)指向指针的引用

int i = 4;
int *p;  //p是一个int型指针
int *&r=p;  //r是一个对指针p的引用
r=&i; // 等价于p指向i
*r=0; //p指向的对象的值变为0,也就是i的值变为0
1.7 常量指针–指向常量的指针、常指针

(1)常量指针
指向常量的指针不能改变其所指对象的值,想要存放常量对象的地址,只能使用指向常量的指针。

const double pi=3.14;  //声明一个常量,不能改变
double *dp=&pi;  //不合法,必须采用常量指针指向常量
const double *dp=&pi; //合法
*dp=43; //不合法不可以改变值,但是可以改变dp的指向,使其指向别的double类型的对象

(2)常指针
指定指针变量的值是常量,即指针变量的指向不能改变。(感觉不太对啊)

int a=0;
int b=1;
int const *p=&a;
p=&b; //不合法

2. 指针和函数

函数的参数不仅仅可以是整型、浮点型、字符型,还可以是指针类型,它的作用是将一个变量的地址传给被调用的函数的形参。
栗子:(对输入的两个整数按大小输出)

#include<iostream>
using namespace std;
int main(){
	void swap(int *p1, int *p2);
	int a,b,*p1,*p2;
	cin>>a>>b;
	p1=&a;
	p2=&b;
	if(a<b) swap(p1,p2);
	cout<<"max="<<a<<"min="<<b<<endl;
	return 0;
}
void swap(int *p1, int *p2){    //函数的作用是将*p1和*p2的值交换
int temp;   //temp是整型变量而不是指针变量,如果此时定义的*temp,下一句对*temp赋值使危险的。
temp=*p1;
*p1=*p2;
*p2=temp; 
}

3、数组和指针

首先来区分一下指针数组和数组指针。
(1)指针数组:是指一个数组里面装着指针,也即指针数组是一个数组

int *a[10];  //a是含有10个整型指针的数组,也就是数组的元素均为指针,即由指针构成的数组--指针数组

在这里插入图片描述
(2)数组指针:是指一个指向数组的指针,它其实还是一个指针,只不过是指向数组而已(数组元素的地址);

int (*pArr1)[10]=&arr; //pArr1指向一个含有10个整数的数组,pArr1是一个指针,指向一个十个元素的int数组,叫数组指针。

当然 ,对修饰符的数量并没有特殊限制

int *(&array)[10]=ptrs; //arry是数组的引用,该数组中含有10个指针
指针与数组
 string nums[]={"one","two","three"};
 string *p=&nums[0];//p指向nums的第一个元素
 string *p2=nums; //等价于p2=&nums[0]
 
 cout<<*p<<endl;//---------------one
 cout<<p<<endl;  //----------------0x28fecc

 ++p; //p指向nums[1];
 cout<<*p<<endl;//---------------two
 cout<<p<<endl;//---------------0x28fed0
指针运算

给指针加上(减去)某整数的值,结果仍然是指针,新指针指向的元素与原来的指针相比前进(后退了)该整数值个位置。

int arr[5]={1,2,3,4,5};
int *ps=arr;
int *pi=ps+3; //指向arr[4]
int *pend=&arr[4];
int count=pend-ps;
cout<<count<<endl;  //4

下标和指针
int arr[5]={1,2,3,4,5};
int *ps=arr;
int i;
i=*(ps+2);  //相当于i=arr[2];
cout<< i <<endl;

栗子:输出数组的10个元素,三种方法

(1)下标法
#include<iostream>
using namespace std;
int main(){
	int a[10];
	for(int i=0;i<10;i++){
		cin>>a[i];
	}
	cout<<endl;
	for(int j=0;j<10;j++){
		cout<<a[j]<<endl;
	}
	return 0;
}
(2)指针法
把上文中的 cout<<a[j]<<endl; 改成 cout<< *(a+j)<<endl;
(3)指针变量指向数组元素
#include<iostream>
using namespace std;
int main(){
	int a[10];
	int *p;
	p=&a;
	for(int i=0;i<10;i++){
		cin>>*(p+i);
	}
	cout<<endl;
	for(p=a;p<(a+10);p++){
		cout<<*p<<endl;   //p先后指向数组中的10个元素
	}
	return 0;
}

4、字符串和指针

在c++中可以用3种方法访问一个字符串

  1. 用字符数组存放一个字符串
#include<iostream>
using namespace std;
int main(){
	char str[]="I Love China";
	cout<<str<<endl;   
	cout<<str[0]<<endl;
	return 0;
}
/*输出:I Love China 
        I
  */
//str是字符数组名,它代表字符数组的首元素的地址,输出时从str指向的字符开始,逐个输出,直到遇到‘\0’
  1. 用字符串变量存放字符串
#include<iostream>
#include<string>
using namespace std;
int main(){
	string str="I Love China";
	cout<<str<<endl;   
	cout<<str[0]<<endl;
	return 0;
}
/*输出:I Love China 
        I
  */

  1. 用字符指针指向一个字符串
#include <iostream>
using namespace std;

int main()
{
    char *str2="I Love China!";
    cout<<str2<<endl;
    cout<<*(str2)<<endl;
    return 0;
}

利用指针复制字符串

int main()
{
    //复制字符串
    char strA[]="I Love LGJ";
    char strB[20], *p1, *p2;
    p1=strA;
    p2=strB;
    while(*p1!='\0'){
        *p2=*p1;
        p2++;
        p1++;
    }
    *p2='\0';
    p1=strA;
    p2=strB;
    cout<<p1<<endl;
    cout<<p2<<endl;
    return 0;
}

5. 指针与对象

6. 指针小结

6.1 指针数据类型小结

变量定义类型表示含义
int i ;int定义整型变量i
int *pint *定义p为指向整型数据的指针变量
int a[5];int [5]定义整型数组a,它有五个元素
int *p[4] ;int *[4]定义指针数组p,它由4个指向整型数据的指针元素组成
int *p[4] ;int *[4]定义指针数组p,它由4个指向整型数据的指针元素组成
int (*p) [4] ;int (*)[4]定义指针p,指向包含4个元素的一维数组的指针变量
int f() ;int ()f为返回整型函数值的函数
int *p() ;int *()p返回一个指针的函数,该指针指向整型数据
int (*)p()int (*) ()p为指向函数的指针,该函数返回一个整型值
int **p ;int **指向指针的指针
int const *p ;int const *p常指针,其值是固定的,指向不能变
const int *pconst int *p为指向常量的指针变量,不能通过p改变其指向的对象的值
const int const *pconst int const *p为指向常量的常指针,值不能改变,也不能通过p改变其指向的对象的值

6.1 指针运算小结

(1)指针加一个整数,减去一个整数
(2)两个指针变量也可以相减
(3)两个指针的比较
若两个指针指向同一个数组的元素,则可以进行比较,指向前面的元素的指针变量小于指向后面元素的指针变量
(4)对指针变量的赋值应该注意类型的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值