c++ 指针 笔记

指针

指针:数据类型,地址

概念:为了方便访问内存内容,系统给每一个内存单元(字节)编号该编号称为地址。也就是指针

指针定义: 类型 * 指针变量名 (类型:指针变量,保存的地址,所对应的变量的类型)

* 没有实际意义,就是说明定义的是一个指针

内存大小:4个字节

int *p p 类型是int* (int型指针),p指向的类型是int型

int**p p 的类型是int** (int 二级指针),p指向的类型是int * 型

指针变量有自己独立的内存空间,其保存别人的内存地址

指针运算符:& 取地址符 &变量名                          *取内容(解析引用符),取地址中的内容

* 指针变量名 等价于指针指向的变量,读取数据时,读取几个字节,看指针指向的类型

指针变量赋值方式:1.相同类型变量的地址2.相同类型的指针变量3.字符串4.数组名

 p = &a

&p :p自己的地址

p:a的地址

*p 等价于a

直接访问:通过变量名访问, 间接访问:通过地址访问

int a = 10;
cout <<&a <<endl;// 获取a的地址
int * p = &a ; 
cout<< &p <<endl; // 获取指针变量自己的地址
cout<< *p <<endl;//获取指针变量保存的地址 xp = x&a = 10

指针偏移

指针 +/ - 整数

p +1 , p - 1 (1表示1个单位),1个单位占几个字节,看指针类型

int n = 0x01 a1 02 a2;
short *pshort = (short *)&n;
pshort = pshort + 1;// pshort = 偏移2个字节
cout<<*pshort<<endl;//01a1

char c[10] = "abcdef" ;
int *pint = (int *) &c[0];
pint ++; // 指针偏移 (int型偏移4个字节,指到第五个元素地址)
cout<<(char*) pint <<endl;//ef

// 通过指针的偏移,遍历数组
int n[5] = {1,2,3,4,5};
int *p = n;//等价于&n[0];
for (int i =0;i<5 ; i++)
    {
        cout << *(p+i) <<endl;
    }

for (int i =0;i<5 ; i++)
    {
        cout << *p++ <<endl; //++ 优先级大于*
        *n++ // 错误,n为数组名常量
    }
//指针变量通过下标形式防访问数组元素·
for (int i =0;i<5 ; i++)
    {
        cout << p[i] <<endl; //等价于 *(p+i)
    }

void *p void型指针,可以指向任何类型 (*p ,.p +1  不允许)

p = nullptr

int *py = null;

=》 py = 0 =》 py = null; //0地址

0地址中不能存储数据 ,*py 不能使用

指针数组 , 数组指针 ,二级指针

指针数组:数组中每一个元素都是指针类型

数组指针:指向数组的指针

二级指针:指向指针的指针

 

指针数组的定义:定义一个int型的指针数组,有五个元素,每个元素都是int *

int *pn[5]

 

数组指针的定义:指向一个类型是int 大小为5的一维数组

int n[5]

int (*pn)[5] =&n

题例子:

//数组指针:数组类型(*p) 数组大小
short *(*pshort)[3][4][5];
cout << sizeof(pshort) <<endl;//4
cout << pshort + 1 <<endl;//4 *3 * 4 * 5 = 240
cout << sizeof(*pshort) <<endl;//240 三维数组的大小
cout << sizeof(**pshort) <<endl;//4*4*5 =80 二维数组的大小
cout << sizeof(***pshort) <<endl;//4*5 =20 一维数组
cout << sizeof(****pshort) <<endl;//4 元祖大小(short * )
cout << sizeof(*****pshort) <<endl;//2 (short)

double **(**pp[3][4])[5][6][7];
cout << sizeof(pp) <<endl;//4*3*4 = 48 3行4列二维数组,每一个元素是二级指针
cout << sizeof(*pp) <<endl;//4*4 = 16 大小为一的一维数组,每一个元素是二级指针
cout << sizeof(**pp) <<endl;//4 二级指针
cout << sizeof(***pp) <<endl;//4 一级指针(数组指针)
cout << sizeof(****pp) <<endl;//4*5*6*7 =840 指向数组的大小(三维数组,每个元素2级指针))
cout << sizeof(*****pp) <<endl;//4*6*7 =168 二维数组
cout << sizeof(******pp) <<endl;//4*7 =28 一维数组
cout << sizeof(*******pp) <<endl;//4 double ** 
cout << sizeof(********pp) <<endl;//4 double *
cout << sizeof(*********pp) <<endl;//8 double 

 指针 与 const

const 修饰的变量必须初始化

指针常量:Const 修饰指针本身const 在* 后

1.必须初始化

2.指针不能改变指向

3.可以通过指针修改指向内存中的内容

 

常量指针:const 修饰指针指向的类型 const在* 前

1.可以不初始化

2.可以改变指向,并且可以指向普通类型(没有const 修饰)的变量

3.不能通过指针修改指针指向的内存中的内容

 

只读类型指针常量

1.必须初始化

2.指针不能改变指向

3.不能通过指针修改指针指向的内存中的内容

例子:

//只读类型的变量n
const int n = 100;
int const m = 10;
//const 修饰的指针指向的内容 *p ,常量指针(只读类型的指针)
const int *p;
int const *p1;
//const 修饰的指针变量本身 p2指针常量
int x =100 ;
int * const p2 = &x;
p = &m;
p = &x;//常量指针可以改变指向,并且可以指向普通变量
 // *p  = 100; 错误,不能通过常量指针修改指向内存中的内容
x = 200;
// p2 = &x; 错误,指针常量,不能改变指针指向
*p2 = 100;
//只读类型的指针(说白了就是把常量指针,和指针常量结合在一起使用)
const int * const p3 = &x;

指针与内存 

作用域:当前语块, 文件作用域,项目作用域

内存区域的划分:1.静态全局区,2.栈区(stack)3.堆区(head)4.常量区

1.静态全局区:静态变量和全局变量 。编译时由系统自动分配内存(并且默认的初始值,只初始化一次),程序结束后由系统自动回收

2.栈区:普通局部变量。函数调用时,系统临时分配内存,函数调用结束后,系统自动回收内存

3.堆区:有程序员自己手动申请(c语言:malloc ,c++:new) 由程序自动释放 (c:free,c++ delete)

4.常量区:字符串,不能修改

 

静态变量:定义时static 修饰变量

全局变量:定义在函数外变量

局部变量:定义函数内的变量

-----------------------------------------------------------------------------------------------------

静态局部变量 和 普通局部变量的异同

1.作用域范围相同,当前语块

2.生存周期不相同,静态局部变量在 静态全局区,普通局部变量在栈区

 

静态全局变量 和 普通全局变量的异同

1.生存周期相同,都在静态全局区

2.作用域范围不同,普通全局变量是项目作用域(在其他文件使用时,必须先声明 extarn),静态全局变量是文件作用域

 

堆区:内存泄漏:申请的内存,没有释放。(结果死机,蓝屏)

 

野指针:内存释放后,指针没有置空,再去操作该内存时,该指针为野指针,(结果:程序崩溃)

 

c++ 引用 :数据地址

引用:数据类型 ,给变量取别名

类型& 引用名 = 变量名 必须初始化

 

指针与引用的区别:

1.引用必须初始化。指针可以不初始化

2.指针可以为空,引用不能为空

3.指针有自己独立的内存空间,引用和引用变量内存相同

4.指针可以改变指向,引用不能改变被引用变量

 

typedef 类型名 , 新名字 给类型取别名

 

typedef int INT; 

int main  (INT a;)// 定义一个int型变量a

 

指针注意事项:

1.定义指针时最好初始化,如果不能明确指针指向,指向0地址

2.使用指针时,先判断是否为空

int*p = nullptr

if(p != nullptr) {*p = 100}

3.使用数组时,注意数组越界

4.堆区申请内存,必须先释放,再置空。

 

函数

函数 : 定义,声明,调用

void test (int n) {return n;}//定义

int main(){test} // 调用

 

函数参数

参数缺省:声明或定义函数可以给形参一个缺省值

缺省顺序:从右往左,传参顺序是从左往右

c++ 函数重载:函数名相同,参数不同(个数,类型,顺序)《c语言函数名字必须不一样》

 

二义性:1.参数类型不匹配:解决:明确实参类型

2.参数缺省,解决:参数不缺省

3.继承时,产生二义性:通过类名加以限定

 

参数传参的方式:1.值传递,2址传递,3.引用传递

assert(),断言,用于错误检测

数组作为函数参数

1.数组名(形实)2.数组的元素(实参)

当数组名作为形参时,弱化成指针类型,必须添加一个形参表表示数组大小

void printArray (int n[4][5])

宏定义

宏定义:宏替换

#define 宏名

#define PI 3.14;// 预编译处理

int main{printf(pI*2)}

带参宏 #define M(x) x*x;

c语言:函数代码少,使用比较频繁,使用宏定义

c++ inline 内联函数(不能使用条件:函数代码过长,函数代码中有循环或递归)

 

递归

递归,函数直接或间接调用自己

1.规律2.找出跳出条件

1.1到n递增
int sum(int n)
{
int s =0 ;
if (1==n)
{
s = 1;
}else
{
s = sum(n-1)+n
}
return s;
}

 

未完》》》》

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值