深入了解指针(1)

这篇博客是我学习指针之后的自我检测,如果你敢兴趣的话,让我们一起来学习吧。

一、内存和地址

 1.内存和指针的联系

指针和内存是不可分割的,因为通过指针可以访问内存空间。

那我们在学习指针之前,就先来了解一下内存,内存就是计算机中用来存储数据的非常大的空间。如果cpu要处理数据的话,得通过数据总线从内存中读取数据。可是内存很大,短时间内找不到要处理的数据,这时就涉及到内存的管理了。

为了快速精确的找到所需要的数据,将内存分为一个个内存单元,大小为一个字节,并将每个内存单元编号,这个编号就是内存单元的地址,在c语言中也叫指针。

## 2.地址

 在计算机中,CPU要从内存中读取数据,先有

由控制总线发出读信号,然后CPU将要读取数据的地址通过地址总线传递给内存,就能准确找到对应的内存空间,最后经数据总线交给CPU。

而CPU处理数据后要返还给内存也一样,由控制总线发出写信号,然后CPU将要读取数据的地址通过地址总线传递给内存,就能准确找到对应的内存空间,最后经数据总线交给内存。

 二、指针变量和地址

 1.分析代码,认识&a,*p和p都代表什么意思。

#include <stdio.h>
int main(){
int a=20;
int *p=&a;
*p=666;
return 0;
}

其中,取地址操作符&a的作用就是取出a的地址。

p就是一个指针变量,用来存放a的地址,指针类型为int*类型。

int*中的*表示p是一个指针变量,int则表示p指向的变量类型是int类型。

解引用操作符*p的作用是通过地址得到p指向的对象。

 2.指针变量的大小。

指针变量的就是用来存放地址的变量,他的大小与存储地址所需要的内存空间大小有关,但是不管指针的类型是什么,他们的地址都只与环境有关。在32位环境下,地址占32bit,指针变量大小为4个字节;相同的,在64位环境下,地址占64bit,指针变量大小为8个字节;

三.指针变量类型的意义

(1)指针变量类型决定了指针解引用时的访问权限(一次可以操作的字节数);

#include <stdio.h>
int main(){
int a=0x11223344;
int* pa=&a;
*pa=0;
return 0;
}

执行*pa=0后:

说明int型指针解引用可以访问4个字节

#include <stdio.h>
int main(){
int a=0x11223344;
char* pb=&a;
*pb=0;
return 0;
}

执行*pb=0

后:

说明char型指针解引用可以访问1个字节

(2)指针变量类型决定了指针加减整数时一次可以跳过的字节数;

#include <stdio.h>
int main(){
int a=10;
int* pa=&a;
char* pb=&a;
printf("&a=%p\n",&a);
printf("&a+1=%p\n",&a+1);
printf("pa=%p\n",pa);
printf("pa+1=%p\n",pa+1);
printf("pb=%p\n",pb);
printf("pb+1=%p\n",pb+1);
return 0;
}

执行后:

说明int*型指针变量+1跳过4个字节,char*型指针变量+1跳过1个字节。结论:pa+n:int*型指针pa跳过n*sizeof(int)个字节;pb+n:char*型指针跳过n*size(char)个字节。

(3)void*型指针这是无具体类型的指针,当不知道某指针用来存放什么类型的地址时用。

int a=10;
char* p=&a;

下面的代码会报警告,因为&a是int*类型的,强行赋给char*型指针就警告了。

四.const修饰变量。

int a=10;
a=20;
printf("%d\n",a);

结果为40.

const int a=20;
a=40;
printf("%d\n",a);

//这段代码错误,因为const修饰的变量具有常属性,是常变量,其值不能改变。

int a=20;
int* p=&a;
*p=40;
printf("%d\n",*p);

结果为40.

const修饰变量。

const修饰*左边,*p即指针指向的对象不能改变,但p即指针的指向(存放的地址不变);

int a=10;
int b=20;
int const * pa=&a;
*pa=15;//error
pa=&pb;//正确

const修饰*右边,*p即指针指向的对象可以改变,但p即指针的指向(存放的地址可以改变);

int a=10;
int b=20;
int * const pa=&a;
*pa=15;//正确
pa=&pb;//error

若是const修饰*两边,则既不能改变*p,也不能改变p;

int a=10;
int b=20;
int const * const pa=&a;
*pa=15;//error
pa=&pb;//error

 五.指针运算。

1、指针加减整数

运用:用指针的方法打印数组

原理:指针解引用和指针加减整数以及数组是连续的一块内存空间。

#include <stdio.h>
#include <string.h>
int main(){
int arr[5]={1,2,3,4,5};
int i=0;
int* p=arr;
int sz=sizeof(arr)/sizeof(arr[0]);
for(i=0;i<sz;i++){
printf("%d ",*(p+i));
}
return 0;
}

#include <stdio.h>
#include <string.h>
int main(){
int arr[5]={1,2,3,4,5};
int i=0;
int* p=arr;
int sz=sizeof(arr)/sizeof(arr[0]);
for(i=0;i<sz;i++){
printf("%d ",*p);
p++;
}
return 0;
}

2.指针减指针

指针减指针的绝对值表示两指针之间整数的数量

运用:写一个函数,计算字符串长度(字符串结束标准是\0)

#include <stdio.h>
#include <string.h>
size_t my_strlen(char* p){
char* start=p;
while(*p!='\0'){
p++;
}
return p-start;
}
int main(){
char arr[]="abcdef";
size_t len=my_strlen(arr);
printf("%zd\n",len);
return 0;
}

3.指针的关系运算

就是进行数组的比较

应用于:打印整形数组

#include <stdio.h>
int main(){
int arr[5]={1,2,3,4,5};
int sz=sizeof(arr)/sizeof(arr[0]);
int * p=arr;
while(p<arr+sz){
printf("%d ",*p);
p++;
}
return 0;
}

 六.野指针

 1.成因:

(1)指针不初始化

int a=10;
int* p=&a;//正确
int*p;//指针未初始化,是野指针
*p=20;//非法访问

可以想作喝醉酒后随便找一个房间就进去住了

(2)指针越界访问

int main(){
int arr[5]={1,2,3,4,5};
int sz=sizeof(arr)/sizeof(arr[0]);
int i=0;
int* p=arr;
for(i=0;i<=sz;i++){ //error,野指针,指针越界访问
printf("%d ",*(p+i);
}
return 0;
}

(3)返回了已经失去访问权限的局部变量的地址

 #include <stdio.h>
 int* test()
 {
 int n = 100;//n是局部变量,只能在该函数范围内使用,出范围就失去了这块内存的访问权限,返还给操作系统
 return &n;
 }
 int main()
 {
 int*p = test();
 printf("%d\n", *p);//p是野指针,非法访问
 return 0;
 }

可以想作昨天晚上去开的酒店房间,退房后今天就不能再住了。

 2.如何避免野指针

(1)指针要初始化

知道指针所指对象的地址就正常初始化,不知道就赋值空指针。

可以想作不初始化的指针是条没有主人的疯狗,用NULL当绳子拴起来。

而且!!!空指针不能使用

(2)指针不要越界访问

(3)指针所指的内存空间不需要使用时,将指针赋值NULL,在使用指针前要判断是否为空指针

(4)避免返回局部变量的地址

七、assert断言

assert()是头文件<assert.h>定义的宏

作用:可以用来判断是否符合assert()里面的表达式(如判断指针是否为空指针),若表达式为真则正常运行,为假就报错,显示error所在的文件名和行号。

优点:不需要修改代码就可以开启或关闭assert();当已经判断代码没有问题,可以在#include <assert.h>前面加上#define NDUG,这样assert()被禁用;

assert()在debug版本下可以使用,但release版本下也被禁用。

八、指针的传值调用和传址调用

区别:传值调用只能使用主调函数传过来的值,没有修改权限,而传址调用可以改变主调函数中的值。

#include <stdio.h>
int add(int x,int y){//x和y是形参,形参是实参的临时拷贝,改变形参,实参不会改变的
return x+y;
}
int main(){
int a=10;
int b=20;
int c=add(a,b);//传值调用
printf("%d\n",c);
return 0;
}
//写一个函数,交换a和b的值
#include <stdio.h>
void swap(int* x,int* y){\\这里虽然也是形参,但是传过来的是实参的地址,通过指针可以找到实参的值并改变
int tem=0;
tem=*x;
*x=*y;
*y=tem;
}
int main(){
int a=10;
int b=20;
printf("交换前a=%d b=%d\n",a,b);
swap(&a,&b);//传址调用
printf("交换后a=%d b=%d\n",a,b);
return 0;
}

Matlab基于粒子群优化算法及鲁棒MPPT控制器提高光伏并网的效率内容概要:本文围绕Matlab在电力系统优化与控制领域的应用展开,重点介绍了基于粒子群优化算法(PSO)和鲁棒MPPT控制器提升光伏并网效率的技术方案。通过Matlab代码实现,结合智能优化算法与先进控制策略,对光伏发电系统的最大功率点跟踪进行优化,有效提高了系统在不同光照条件下的能量转换效率和并网稳定性。同时,文档还涵盖了多种电力系统应用场景,如微电网调度、储能配置、鲁棒控制等,展示了Matlab在科研复现与工程仿真中的强大能力。; 适合人群:具备一定电力系统基础知识和Matlab编程能力的高校研究生、科研人员及从事新能源系统开发的工程师;尤其适合关注光伏并网技术、智能优化算法应用与MPPT控制策略研究的专业人士。; 使用场景及目标:①利用粒子群算法优化光伏系统MPPT控制器参数,提升动态响应速度与稳态精度;②研究鲁棒控制策略在光伏并网系统中的抗干扰能力;③复现已发表的高水平论文(如EI、SCI)中的仿真案例,支撑科研项目与学术写作。; 阅读建议:建议结合文中提供的Matlab代码与Simulink模型进行实践操作,重点关注算法实现细节与系统参数设置,同时参考链接中的完整资源下载以获取更多复现实例,加深对优化算法与控制系统设计的理解。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值