1.指针的概念
用来存储数据的各个内存位置都有地址,地址给PC硬件提供了引用数据的途径。指针变量存储特定类型的另一个变量的地址。
2.声明指针
指针的声明和变量的声明一样。下面这段代码是指针声明的两种写法。
#include <iostream>
int main()
{
using namespace std;
//第一种
long* num1;
//第二种
long *num2;
return 0;
}
为了良好的 编程习惯我们一般倾向于第一种写法,因为num1是指向long类型的指针。星号离类型近一些意思更加清楚
在看一下下面这段代码:
#include <iostream>
int main()
{
using namespace std;
long* num1,num2;
return 0;
}
这里不要误解为是声明了两个指针,其实num1 是指针,num2只是一个long类型的变量而已。
所以,一般我们把声明指针和声明变量分开成两行写
3.使用指针
3.1为什么要使用指针
1.指针可以直接操作内存中的数据,免除了在大数据块中使用变量操作还得赋值,可以提高效率
2.指针可以解决一个函数只有一个返回值,但我们需要同时又多个值改变等问题
3.2指针的初始化
#include <iostream>
int main()
{
using namespace std;
int num=9;
int* pNum=#
return 0;
}
如上
是指针的初始化操作,采用的是&取址运算符
如果我们不想初始化为具体变量的地址,也可以采用如下方式
#include <iostream>
int main()
{
using namespace std;
int* pNum=nullptr;
if (!pNum)
{
cout<<"num1 does not point to anything"<<endl;
}
return 0;
}
nullptr是C++11中的一个新特性,如果不支持,可以将nullptr改写为NULL或0。
NULL其实是0的一个宏定义,我们知道布尔类型,0即假非0即真 因此 不管是使用NULL 0 还是nullptr都可以隐世转换为bool
为什么会出现nullptr呢?? 因为使用0初始化执行会引起歧义,,到底指针是不是执行0所在的地址,还是指针是空 搞不清
3.3指针的使用
3.3.1 指针的基本使用方法
下面是指针的简单使用方法:
#include <iostream>
int main()
{
using namespace std;
long* pNumber=nullptr;
long number1=55,number2=99;
//将number1的地址赋给pNumber 此时pNumber指向number1
pNumber=&number1;
//*pNumber是55,+11即66,此时*pNumber和number1的值是66
*pNumber+=11;
//输出 number1=66 &number1=其内存地址,这个地址每次运行都会变的
cout<<"number1= "<<number1<<" &number1= "<<pNumber<<endl;
//改变指针的引用 *pNumber=99
pNumber=&number2;
//number1=99*10 即number1=990
number1=*pNumber*10;
//输出 number1=990 &number1=其内存地址 *pNumber=99
cout<<"number1= "<<number1<<" &number1= "<<pNumber<<" *pNumber= "<<*pNumber<<endl;
return 0;
}
3.3.2 指向char类型的指针
<pre name="code" class="cpp">#include <iostream>
int main()
{
using namespace std;
char* pStr="Hello Pointer";
cout<<"pStr="<<pStr<<endl
<<"*(pStr+1)="<<*(pStr+1)<<endl
<<"*pStr="<<*pStr<<endl;
return 0;
}
这里输出的是: pStr=Hello Pointer *(pStr+1)=e *pStr=H
这里的Hello Pointer字符串常量在内存中是以单个字符存放的,最后以\0结束,将它赋值给字符指针,其实是将首字母H的地址赋值给指针
此时指针*pStr就是首字母H 而后*(pStr+1) 等同于 char[1] 即 e pStr就是整个字符串 ,可以把pStr看成是一个字符数组,更容易理解
#include <iostream>
int main()
{
using namespace std;
char pStr[]="Hello Pointer";
cout<<"pStr="<<pStr<<endl
<<"*(pStr+1)="<<*(pStr+1)<<endl
<<"*pStr="<<*pStr<<endl;
return 0;
}
和上面的代码意思一样
#include <iostream>
int main()
{
using namespace std;
char* pStr=new char[];
//pStr="Hello Pointer";
strcpy(pStr,"Hello Pointer");
*pStr='D';
cout<<pStr<<endl;
return 0;
}
第六行和第七行,这里都是将字符串Hello Pointer赋值给指针,
但是,如果使用第六行进行赋值,然后再改变其值,会报错,其实是因为,通常系统将字符串常量存储在内存的一块只读区域,所以不能进行修改
这里还要注意,我们使用了new char[] 这是动态的再内存中分配一块内存区域,然后我们strcpy将字符串拷贝过来,这样才能修改里面的单个字符
还有一个模糊的概念,如下代码:
#include <iostream>
int main()
{
using namespace std;
char* pStr="Hello Pointer";
cout<<sizeof(pStr)<<endl;
cout<<sizeof(*pStr)<<endl;
char arrayStr[]="Hello Pointer";
cout<<sizeof(arrayStr)<<endl;
cout<<sizeof(*arrayStr)<<endl;
return 0;
}
输出:4 1 14 1
先前我们说pStr和ArrayStr的意义是一样的,其实这里还有一个细微的区别,sizeof(pStr)pStr其实也是一个变量,只是他存储的是其他变量的地址而已,所以这里是4
而sizeof(arrayStr) 得出的是数组中所以字符的字节大小总和,这里需要大家区分开来
3.4指针常量和常量指针
#include <iostream>
int main()
{
using namespace std;
int number=10,number2=20;
//常量指针
const int* pNumber=&number;
//*pNumber=20; //错误,常量指针所指向的值是不能修改的
pNumber=&number2; //正确,常量指针可以改变其指向
//指针常量
int* const pNumber1=&number;
*pNumber1=20; //正确,指针常量所指向的值可以修改
//pNumber1=&number2; //错误,指针常量的指向不能改变
return 0;
}
这里有点蒙,我们可以这样记
首先如何区分常量指针和指针常量, 我们可以把const 看做汉字常量 *可以看做指针 那个在前面就先读那个
然后,如何记忆他们之间的区别呢??
总结:
区分是常量指针还是指针常量,就看const 和* 哪个在前哪个在后
区分常量指针和指针常量的区别,把常量看做值,指针看做地址,哪个在前哪个就不能改变
故,const int * pNumber=&number; const在前*在后 常量指针 常量在前 值不能改变
int* const pNumber=&number; *在前 const在后 指针常量 指针在前 地址不能改变
3.5获得字符指针所指向的字符串长度
#include <iostream>
int main()
{
using namespace std;
char* pChar="Hello World";
cout<<strlen(pChar)<<endl;
return 0;
}
这里和数组一样用了strlen,这是C++库函数,它的实现如下代码:
size_t __cdecl strlen (
const char * str
)
{
const char *eos = str;
while( *eos++ ) ;
return( eos - str - 1 );
}
我们还可以采用递归:
#include <iostream>
int mystrlen(const char* temp)
{
if (!temp||*temp=='\0')
{
return 0;
}
return mystrlen(temp+1)+1;
}
int main()
{
using namespace std;
char* pChar="Hello World";
cout<<mystrlen(pChar)<<endl;
return 0;
}