AutoLeaders控制组 ---指针的学习笔记

关于&的本质

&本质是运算符,是一个取地址符。

以下是有关取地址符的一些运算

#include<stdio.h>
int main(void)
{
	int i=0;
	int p;
	//p=(int)&i;//这一步是强制类型转换,将地址转换成整型,编译器64位架构这样会出现精度丢失报错,无法运行 ;32位架构下可以运行。 
	printf("0x%x\n",&i);//取地址需要明确变量 
	printf("%p\n",&i);//变量分配在堆栈里,地址从高到低分配,先写的分配到高位地址。 
	printf("%p\n",&p);
	printf("%d\n",sizeof(int));//64位架构int4字节,地址8字节;32位架构int4字节,地址也一样。 
	printf("%d\n",sizeof(&i));
	int a[10];
	printf("%p\n",&a);
	printf("%p\n",a);
	printf("%p\n",&a[0]);
	printf("%p\n",&a[1]);
}

以下是运行结果图,我的编译环境是64位架构,从数组的运行结果可知与指针有联系,数组其实是指针变量。
在这里插入图片描述

什么是指针

1.指针就是保存地址的变量,用*来定义。
2.*是单目运算符,可以访问指针变量的值对应的地址所对应的变量。

指针的定义和取地址如下

	int i=2;
	int *p;
	p=&i;//现在p里面保存的就是变量i的地址,或者直接初始化int *p=i也是一样。
	*p=26;//这里通过地址访问i变量的值,并进行修改,可以说*p和i是等价的。
	int ai[]={1,2,3,4,5,6,7,8,9,10};
	int *q=ai;//取指针地址不用加&,因为数组变量是特殊的指针 
	q[1]=5;//[]运算符可以对数组做也可以对指针做,和ai[1]等价

3.指针的运算符&和*是相互反作用的

这里就直接放图片说明请添加图片描述

指针的应用场景

  1. 交换两个变量的值。

用指针交换两个变量的值的好处是,可以在自定义的函数内改变外部函数变量的值,可以将结果带出函数,这就是指针与函数的结合,例如交换两个变量的值。

  1. 要用函数返回多个值

用return只能返回一个值,所以当需要返回多个值时某些值需要通过指针返回。

  1. 通过返回运算状态,而值通过函数返回

参考下图的例子
请添加图片描述
如图是一个做除法的函数,因为分母不能为0,所以当分母为0时我们可以返回0来表示程序出错而不执行判断语句。

指针的常见错误

  • 定义指针变量,还未指向任何变量,就开始使用
int i=2;
int *p;
*p=12;//此时指针未指向变量,内部的指向未知,可能会向不正确的地方写入数据导致程序崩溃

指针与数组

1.传入函数的数组成为了指针。

例如int型数组,用sizeof()函数在main函数里面得到的数组元素个数乘int的字节数,而在自定义函数里得到的是数组的地址,例子如下图
请添加图片描述
由于传入的数组是指针,所以在函数内部改变数组元素的值可以带到函数外,相当于函数的参数a[]和指针是一个东西,所以把a[]改成*a是等价的,一样可以编译成功。
请添加图片描述

2.所以数组变量是特殊的指针

int a[10];
int *p=a;//此处就不需要取地址符&
  • a==&a[0],数组变量的地址和首个单元的地址是一样的。
  • []运算符可以对数组做也可以对指针做

    p[0]<==>a[0],p是指针变量,a是数组变量

    若a是int变量,p[0]会把a当成数组长度为一的数组来运算,但a[0]这种运算就是错误的

  • *运算符可以对指针做也可以对数组做,例如a[10],*a访问的就是数组的第一个单元,因为a的首地址等于&a[0]。
  • 数组变量是const指针,所以不能被赋值

    比如另一个数组等于另外一个数组是不可取的

  1. 指针与const

这里就直接用视频的截图来说明
请添加图片描述
请添加图片描述
主要的标志在于*和const谁前谁后

  • 可以把非const转换成const
void f(const int* x);//这里就保证不能在函数内部通过指针改变变量的值,可以应用于某些场景
  • const数组

    const int a[]={1,2,3,4}//表示每个数组单元都不能被改变,就必须通过初始化赋值。

指针运算

  1. 指针做加法
int ai[]={1,2,3,4,5,6,7,8,9,10};//指针单元的地址规律为每个单元连续加一个单位类型
int *q=ai;
printf("q=%p\n",q);
printf("q+1=%p\n",q+1);//q+1得到的地址为增加一个int型的单位,也就是下一元素的地址
printf("*(q+1)=%d\n",*(q+1));//指针+1可以指向下一数组元素

*p++的运算为地址加一,因为++的优先级高于 *,这常用于对数组的连续操作

  1. 指针相减
//指针相减运算
int ai[]={1,2,3,4,5,6,7,8,9,10};
int *q1=&ai[5];
int *q=ai;
printf("q1=%p\n",q1);
printf("q1-q=%d\n",q1-q);//相减的结果为地址的差除以sizeof的单位,输出结果相当于之间的元素个数
  1. 指针可以进行比较,数组中的单元地址肯定是线性增加的
  2. 注意指针的类型,不同类型的指针不能相互赋值
  3. 0地址请添加图片描述

动态内存分配

malloc函数

用来向电脑申请储存空间,大小以字节为单位

  1. 解决变量不能作为数组长度的问题
int number;
int* a;
int i;
printf("输入数量:");
scanf("%d",&number);
a=(int*)malloc(number*sizeof(int)); //malloc的返回类型不是int所以要类型转换一下
for(i=0;i<number;i++){
	scanf("%d",&a[i]);//a可以完全当成一个数组来用
}
free(a);//用来释放申请的地址
  1. 调用完malloc函数要使用free函数释放申请的空间

系统的空间是有限的,如果程序一直申请而不释放空间,则空间用完时会申请失败返回0,但是只能还原空间即返回首地址,改变地址释放空间就会出错,例如上面返回free(a++)程序就会报错,没有调用malloc函数free也会报错

void *p;
int cnt=0;
while((p=malloc(100*1024*1024))){
cnt++;
} 
printf("分配了%d00MB空间",cnt);//最后得到的是系统能够申请的空间,不同电脑是不一样的

特例:free(NULL)是不会出错,因为free判断为NULL不会进行操作,如果上面的程序运算错误这样可以防止程序崩溃,所以指针未初始化赋值为NULL是个好习惯

int *p=NULL;
free(p);//这样程序就不会因为返回错误的p而崩溃
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值