一.指针
#include<iostream>
using namespace std;
#define pi 3.14159//定义常量
int main(){
cout<<pi<<endl;
int a=10;
int *p=NULL;//定义指针
p=&a;
cout<<"a的地址为:"<<p<<endl;
cout<<"a="<<*p<<endl;
return 0;
}
1.指针的作用
通过指针可以间接访问内存
- 内存编号是从0开始记录的,一般用十六进制数字表示。
- 可以利用指针变量保存地址。
2.指针的定义与使用
语法:数据类型 * 变量名。 int *p;
(1)一级指针:
<1>.定义,赋值与输出:
#include<iostream>
using namespace std;
int main()
{
int a=10,b=11;
int *p=&a;
int *t=NULL;//定义一个指针
t=&b;//&取地址
cout<<"指针t:"<<*t<<endl<<"b的地址:"<<&b<<endl<<"b="<<b<<endl;
return 0;
}
(2)二级指针
<1>.二级指针的定义,赋值与输出
#include<iostream>
using namespace std;
int main()
{
int a=10;
int *p=&a;
int **pp=&p;
cout<<"*p:"<<*p<<endl<<"&a:"<<&a<<endl<<"a:"<<a<<endl<<"**pp:"<<**pp<<endl<<"&pp:"<<&pp<<endl<<"&p:"<<&p;
return 0;
}
*p:10
&a:0x6ffdfc
a:10
**pp:10
&pp:0x6ffde8
&p:0x6ffdf0
#include <iostream>
using namespace std;
int main()
{
int i = 9, t = 10, k = 11;
int *p = &i;
int *m = &i; // 一级指针p,m
int **pp = &p;
int **mm = &m; // 二级指针pp,mm
cout << "一级指针*p=" << *p << endl
<< "二级指针**pp=" << **pp << endl;
cout << "一级指针*m=" << *m << endl
<< "二级指针**mm=" << **mm << endl;
cout << "修改一级指针的内容后:" << endl;
*p = t;
cout << "一级指针*p=" << *p<< endl
<< "二级指针**pp=" << **pp << endl;
cout << "修改一级指针的指向后:" << endl;
*mm=&k;
cout << "一级指针*m=" << *m << endl
<< "二级指针**mm=" << **mm << endl;
return 0;
}
<2>.二级指针的步长:
所有类型的二级指针,由于均指向一级指针类型,并且所有一级指针类型大小是 4,
所以二级指针的步长也是 4。
<3>.改变n-1级指针的指向:
可以通过一级指针,修改 零级指针(变量)的内容。
可以通过二级指针,修改一级指针的指向。
可以通过三级指针,修改二级指针的指向。可以通过四级指针,修改三级指针的指向。
·····
可以通过修改 n 级指针,从而间接修改 n-1 级指针的指向。
3.空指针与野指针
空指针: 指针变量指向内存中编号为0的空间
用途: 初始化指针变量
注意: 空指针指向的内存是不可以访问的
int *p = NULL;//初始化指针,NULL为0
//空指针不可访问
//0~255之间的内存编号是系统占用的,不允许用户访问
cout << *p << endl;// 引发了异常: 读取访问权限冲突。p 是 nullptr。
野指针: 指针变量指向非法的内存空间
4.关键字new与delete【动态内存管理】⭐️
(1)作用:
使用new与delete管理对象,new分配内存,delete释放内存。
在C++提供关键字new来创建对象,delete释放对象,但释放数组需要加上[]。
(类似于:在C语言是用库函数malloc来申请内存,free来释放内存)。
动态管理内存的入口 | |
malloc, free | new, delete |
C/C++标准库的函数 | C++操作符 |
只是动态分配内存空间/释放空间 | 除了分配空间还会调用构造函数和析构函数进行初始化与清理(清理成员) |
需要手动计算类型大小且返回值w为void | 可自动计算类型的大小,返回对应类型的指针。 |
管理内存失败会返回0 | 方式管理内存失败会抛出异常 |
#include<iostream>
using namespace std;
int main(){
int *p1=new int;
*p1=99;
cout<<"sizeof *p1="<<sizeof(*p1)<<endl;
cout<<"*p1="<<*p1<<endl;
cout<<"p1="<<p1<<endl;
delete p1;//释放p1指向的内存
return 0;
}
这将释放p指向的内存,但不会删除指针p本身。例如,可以将p重新指向另一个新分配的内存块。
一定要配对地使用new和 delete;否则将发生内存泄漏(memory leak),也就是说,被分配的内存再也无法使用了。如果内存泄漏严重,则程序将由于不断寻找更多内存而终止。
(2)使用:
<1>int *p1 = new int[10];
返回一个指向int型的指针int*
<2> int (*p2)[10] = new int[2][10];
返回一个,指向int[10]这样的一维数组的,指针int (*)[10]
<3> int (*p3)[2][10] = new int[5][2][10];
返回一个指向二维数组int[2][10]这种类型的指针int (*)[2][10]
#include<iostream>
using namespace std;
int mian(){
//定义一个指针:
int *p1=new int;//动态分配指针
*p1=3;//单独赋值
int *p2=new int(8);//初始化,在new后面直接赋值
//定义一个数组时,同样用一个指针指向数组的首地址
int *p3=new int[5];//动态分配指针数组
for(int i=0;i<5;i++)p3[i]=i;
delete p1;
delete p2;
delete[] p3;
return 0;
}
5.指针与数组
a[3]={1,2,3};
指针指向数组: int *p=a;
(1)普通遍历数组:
int i, a[9];
for(int i=0;i<9;i++)
a[i]= i;
for (i = 0; i <= 9; i++)
{
std::cout << a[i]<< std::endl;
}
(2)用指针遍历数组:
int i, a[9];
for(int i=0;i<9;i++)
a[i]= i;
for (i = 0; i <= 9; i++)
{
std::cout << *(a+i)<<std::endl;
}
(3)用指针访问遍历数组:
int i, a[9],*pa; for(int i=0;i<9;i++)a[i]= i; pa=a; for (i = 0; i <= 9; i++) { std::cout << pa[i]<<std::endl; }
#include<iostream> using namespace std; int main(){ int i=0,a[4],*pa; for(i=0;i<4;i++)a[i]=i; pa=a; for(i=0;i<4;i++)cout<<*pa++<<endl; return 0; }
6.指针数组
指针数组:char *pa[10];
#include <iostream>
using namespace std;
int main()
{
char * pArray[] ={"apple","pear","banana","orange","grape"};
for(int i=0; i<sizeof(pArray)/sizeof(*pArray); i++)
cout << pArray[i] << endl;
return 0;
}
二.函数
#include<iostream>
using namespace std;
void max(int p,int t);//函数声明
int main(){
int a=9,b=10;
cout<<a<<b<<endl;
max(a,b);//函数调用,实参列表
return 0;
}
void max(int p,int t){//函数定义,形参列表
int u=p>t?p:t;
cout<<u<<endl;
}
形参与实参的关系:
两者是在调用的时候进行结合的,通常实参会取值传递给形参,形参之后进行函数过程运算,然后可能将某些值经过参数或函数符号返回给调用者。"值传递"是单向传递,由实参传向形参,如果形参发生改变,不会影响实参。
1.文件包含
文件包含是指将一些头文件或其他源文件包含到本文件中,一个文件被包含后该文件的所有内容就被包含进来了。
#include<文件名>
#include"文件名"
尖括号< >和双引号" "的区别:
- 用尖括号时,称为标准模式,系统直接到存放c/c++库函数的文件中查找要包含的文件。
- 用双引号的时候,系统优先在当前目录中查找要包含的头文件,若找不到,再按标准模式查找。
一般来说,使用库函数的时候用< >,使用用户自定义的头文件时用" ";
2.指针作为函数形参
实参会地址传递给形参
”地址传“: 指针作为形式参数,可以接受实参传来的值,同时可以修改实参的值。
(地址传递中形参改变,对应的实参也会发生改变。)
#include <iostream>
using namespace std;
void swap(int *p,int *t){
int temp=*p;
*p=*t;
*t=temp;
}
int main()
{
int a=10,b=20;
swap(&a,&b);
cout<<a<<endl<<b;
return 0;
}
3.指针函数
(1)指针函数的定义
“指针函数”的定义: 一个返回类型为指针的函数。
注:
- 指针函数的本质是函数。
- 只是其返回值是一个某某类型的指针,是一个地址。
(2)指针函数的声明
#include<iostream>
using namespace std;
int *pfun(int a,int b);//声明指针函数pfun
int main(){
int *p=NULL;
p=pfun(5,3);//调用指针函数
cout<<*p<<endl;
free(p);
return 0;
}
int *pfun(int a,int b){//指针函数
int *p=(int *)malloc(sizeof(int));
*p=a-b;
return p;
}
输出:2
4.函数指针
(1)函数指针的定义
”函数指针“的定义:是一个指向函数的指针变量。
注:
- ”函数指针“本质上是一个指针变量。
- 函数指针就指向函数的入口地址,可以通过函数指针来调用函数。(C语言中每一个函数都有一个入口地址)
(2)函数指针的声明方法
int FUNC(int x); //声明一个函数FUNC
int (*fun)(int x,int y); //声明一个函数指针
fun = FUNC; // 将FUNC函数的首地址赋给指针fun
fun=&FUNC//将函数地址赋值给函数指针