【C语言】指针(1):入门理解篇

目录

一、内存和地址

1.1内存

1.2 深入理解计算机编址

 二、指针变量和地址

2.1 取地址操作符(&)

2.2 指针变量和解应用操作符

2.2.1 指针变量

2.2.2 解引用操作符

2.3指针变量的大小

三、指针变量类型的意义

 3.1 指针的解引用

3.1指针+-整数

3.3void*:无具体类型的指针

四、const修饰变量

   4.1 const修饰指针

4.2 const修饰指针变量

 五、指针运算

5.1 指针+-整数 运算

5.2 指针-指针       

5.3 指针的关系运算

六、野指针

6.1.野指针产生原因

6.1.1 指针未初始化

6.1.2 指针越界访问​编辑

6.1.3 指针指向的空间释放

6.2 如何规避野指针

6.2.1 指针初始化

6.2.2 避免越界访问   

6.2.3 当指针不再使用时,即使置NULL,指针使用前检查有效性

6.2.4 避免返回局部变量的地址     

七、assert断言     

八、理解传值调用和传址调用     

 

一、内存和地址

1.1内存

只要讲指针就离不开内存

因为指针就是访问内存的

计算上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数
据也会放回内存中,那我们买电脑的时候,电脑上内存是8GB/16GB/32GB等,那这些内存空间如何高效的管理呢?
其实也是把内存划分为⼀个个的内存单元,每个内存单元的大小取1个字节

计算机常见单位

bit - ⽐特位
byte - 字节
KB
MB
GB
TB
PB1byte = 8bit
1KB = 1024byte
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB
1PB = 1024TB

 内存单元编号==地址==指针

1.2 深入理解计算机编址


CPU访问内存中的某个字节空间,必须知道这个字节空间在内存的什么位置,⽽因为内存中字节很多,所以需要给内存进⾏编址(就如同宿舍很多,需要给宿舍编号⼀样)。计算机中的编址,并不是把每个字节的地址记录下来,⽽是通过硬件设计完成的。

⾸先,必须理解,计算机内是有很多的硬件单元,⽽硬件单元是要互相协同⼯作的。所谓的协同,⾄少相互之间要能够进⾏数据传递。但是硬件与硬件之间是互相独⽴的,那么如何通信呢?答案很简单,⽤"线"连起来。⽽CPU和内存之间也是有⼤量的数据交互的,所以,两者必须也⽤线连起来。不过,我们今天关⼼⼀组线,叫做地址总线

32位机器有32根地址总线, 每根线只有两态,表⽰0,1【电脉冲有⽆】,那么 ⼀根线,就能表⽰2种含义,2根线就能表⽰4种含义,依次类推。32根地址线,就能表⽰2^32种含义,每⼀种含义都代表⼀个地址。地址信息被下达给内存,在内存上,就可以找到该地址对应的数据,将数据在通过数据总线传⼊CPU内寄存器。

int main()
{
int a = 10;//创建变量的本质是向内存申请一块空间,为a申请4个字节的空间return 0;
}

 

 对于地址总线、数据总线、控制总线可以这样理解的:

控制总线:相当于一个控制台,传递指令。

数据总线:相当于内存数据传输的通道。

地址总线:相当于一个内存仓库。

 

 二、指针变量和地址

2.1 取地址操作符(&)

int main()
{int a = 10;//&a --- &取地址操作符//& 单目操作符printf("%p\n",&a);return 0;
}

 

      对int a=10来说,创建了四个字节的空间,通过调试发现这四个字节都是有地址的,当我们通过&取地址符来得到a的地址(%p是专门用来取地址的占位符)时,实际上取出的时a所占4个字节中地址较小的字节的地址。虽然整形变量占了4个字节,但是只要知道了第1个字节的地址,顺藤摸瓜就可以访问到4个字节的数据。

2.2 指针变量和解应用操作符

2.2.1 指针变量

       通过2.1我们通过&取地址符拿到了地址,这个地址是一个数值,而将这个数值存储起来方便后期使用,就需要我们把地址值存在指针变量里。

int main()
{int a = 10;//&a --- &取地址操作符//& 单目操作符printf("%p\n",&a);return 0;
}

2.2.2 解引用操作符


      通过2.2.1,我们学会了怎么将地址保存起来,那未来我们也要有方法去取用他,就跟我们生活中我们找到一个房间,我们希望可以在这个房间里存放或者取走物品,同理,我们通过了指针变量存储的地址,通过地址找到了该地址指向的空间,这里就需要用到解引用操作符*,来取用空间里数据。

//指针--地址
//指针变量--存放地址的变量int main()
{int a = 10;//&a --- &取地址操作符//& 单目操作符//printf("%p\n",&a);int* p = &a;//p是一个变量(指针变量),是一块空间//编号-地址-指针//int说明p指向对象是int类型的//*在说明p是指针变量
return 0;
}
int main()
{char ch = 'w';char* pc = &ch;return 0;
}
int main()
{int a =10;int * p= &a;*p =0;//* -解引用操作符(间接访问操作符)//a =0;】//*&a = 0;//a = 0
printf("%d",a);//0?return 0;
}

2.3指针变量的大小

32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后是1或者0,那我们把32根地址线产⽣的2进制序列当做⼀个地址,那么⼀个地址就是32个bit位,需要4 个字节才能存储。

如果指针变量是⽤来存放地址的,那么指针变的⼤⼩就得是4个字节的空间才可以。同理64位器,假设有64根地址线,⼀个地址就是64个⼆进制位组成的⼆进制序列,存储起来就需要8个字节的空间,指针变的⼤⼩就是8个字节。

指针的变量大小与类型是无关的,只要是指针类型的变量,在相同的平台下,大小都是一样的(32位平台指针大小是4个字节,64位平台下指针大小是8个字节)

指针变量 - 存放地址的
                  地址产生:地址线上传输的
                   32根地址线 ——>地址是:32个0/1组成的二进制序列
                   要储存这样的地址:32bit位的空间 ==4个字节

int main(){printf("%zd\n", sizeof(char *));printf("%zd\n", sizeof(short *));printf("%zd\n", sizeof(int *));printf("%zd\n", sizeof(double *));return 0;}

32位:4 4 4 4

64位:8 8 8 8 

结论:
• 32位平台下地址是32个bit位,指针变量⼤⼩是4个字节
• 64位平台下地址是64个bit位,指针变量⼤⼩是8个字节
• 注意指针变量的⼤⼩和类型是⽆关的,只要指针类型的变量,在相同的平台下,⼤⼩都是相同的。

 

三、指针变量类型的意义

指针类型决定了指针进行解应用操作符的时候访问几个字节,也就是决定指针的权限

 3.1 指针的解引用

int main()
{ int a = 0x11223344;int * pa = &a;*pa =0;return 0;
}

//代码1
#include <stdio.h>
int main()
{int n = 0x11223344;int *pi = &n; *pi = 0; return 0;//代码2
#include <stdio.h>
int main()
{int n = 0x11223344;char *pc = (char *)&n;*pc = 0;return 0;
}

调试我们可以看到,代码1会将n的4个字节全部改为0,但是代码2只是将n的第⼀个字节改为0。

结论:指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作⼏个字节)。
⽐如: char* 的指针解引⽤就只能访问⼀个字节,⽽ int* 的指针的解引⽤就能访问四个字节。

3.1指针+-整数

int main()
{int a =10;int *pa = &a;char* pc = &a;printf("pa=%p\n",pa);printf("pa+1 = %p\n",pa+1);printf("pc = %p\n",pc);printf("pc+1 = %p\n",pc+1);return 0;
}

指针类型决定了指针进行+1,-1的时候,一次走远的距离

int * +1 --->走4个字节(整型大小)

char* +1--->走了1个字节(字符大小)

3.3void*:无具体类型的指针

指针类型:

char*:指向字符的指针

short*:指向短整型的指针

int*:指向整型的指针

float*:指向单精度浮点型的指针

........

void*:无具体类型的指针,这类指针可以用来接受任意类型的地址,但是也有局限性,就是void*不能直接进行指针的+-整数和解引用运算。

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

 上面这个代码我们可以证实这个结论, 我们可以把void*想象成一个垃圾桶,可以收集任意类型数据的指针,但是无法直接去运用(解引用和+-运算)。其实void*的设计可以实现泛型编程的效果,使得一个函数可以处理多种类型的数据。

#include<stdio.h>
int main()
{int a = 0;float f = 0.0f;void* p = &a;//int*p = &f;//float*return 0;
}
#include<stdio.h>
{int a =10;void* p = &a;//*p = 20;//err//p = p +1;//errreutrn 0;
}

 

四、const修饰变量

   4.1 const修饰指针

int main()
{const int a 10;//a 具有了常属性(不能被修改了)
//a是不是常量?虽然a是不能被修改的,但是本质上还是变量
//常变量
//
//a = 20;
//在C++中const修饰的变量就是常量
//int arr[a] ;printf("%d\n",a);retrun 0;
}
int main()
{const int a = 10;
//a = 20;//err
int* p = &a;
*p = 0;
ptintf("a = %d\n",a);return 0;
}

4.2 const修饰指针变量


   创建指针变量p(int*p=&a)之前,我们首先要知道3点含义。

1.p内部存放的是a的地址,*p可以通过这个地址访问到a。

2.p本身也是变量,他有自己的地址。

3.*p是p指向的空间,也可以理解成解引用p,改变*p其实就是改变a。

int main()
{int a = 10;//&a--0x0012ff40int b = 20;//&b--0x0012ff44int * const p =&a;//0x0012ff40//p = &b;//err*p = 100;//const 修饰指针变量的时候。放*右边//const 限制的是指针变量本身,指针变量不能再指向其他变量了//但是可以通过指针变量,修改指针变量指向的内容return 0;
}
int main()
{int a = 10;int b = 20;int const * p =&a;//p = &b;//OK//*p = 100;//err//const 修饰指针变量的时候。放*左边,限制的是:指针指向的内容,不能通过指针来修改指向的内容//const 限制的是指针变量本身,指针变量不能再指向其他变量了//但是可以修改指针变量本身的值(修改的指针变量的指向)return 0;
}
int main()
{int a = 10;int b = 100;int const * const p =&a;//p = &b;//err//*p = 0;//errreturn 0;
}

const结论:

1.const如果在*左边,const修饰的是*p,也就是修饰指针指向的内容,保证指针指向的内容不能通过指针来改变,但是指针变量p本身的内容是可以改变的。

2.const如果在*右边,const修饰的是p本身,保证指针变量p的内容不能被修改,但是指针指向的内容是可以改变的。

3.如果*的两边都有const,则const不仅修饰了*p,也修饰了p本身,所以无论是指针指针指向的内容,还是指针变量本身,都是不可以被改变的。

 

 五、指针运算

5.1 指针+-整数 运算

int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};int i = 0;int sz = sizeof(arr) / sizeof(arr[0])\;for (i = 0; i < sz;i++){printf("%d",arr[i]);}return 0;
}int main()
{int arr[10];int i = 0;for (i = 0; i < 10; i++){arr[i] = i + 1;//数组内10个元素分别为1 2 3 4 5 6 7 8 9 10}//通过指针来访问并打印这个数组int sz = sizeof(arr) / sizeof(arr[0]);//sz为数组元素个数//我们需要知道arr的首地址,再通过+-运算顺藤摸瓜找到后面所有元素int* p = &arr;//数组名代表数组首元素的地址for (i = 0; i < sz; i++)//如果我想访问1-10{printf("%d ", *p);p++;} //如果想访问1 3 5 7 9,则改成p+=2即可return 0;
}

5.2 指针-指针
       

通过5.1,我们知道指针+整数=指针。所以指针-指针得到的是一个整数。

       可以模拟实现strlen函数来观察指针的减法,strlen函数本质是字符串/0前面出现的元素个数,其实strlen函数传入的是字串串首元素的地址,如何通过该地址顺藤摸瓜地寻找后面的元素,知道遇到/0。

int my_strlen(char* s)
{char* p = s;while (*p != '\0')//这里也可以写成*p,因为'\0'的ascii值是0p++;//p加1一次就往后移动4个字节return p - s;//指针-指针得到的绝对值是指针之间的元素个数(前提条件:两个指针指向同一块空间。)
}
int main()
{int ret = my_strlen("abc");printf("%d", ret);return 0;
}

   指针-指针得到的是一个整数,而这个整数其实就是指针与指针之间的元素个数,但是有个前提条件就是两个指针必须指向同一块空间(比如arr[0]-crr[1]就不行)。

5.3 指针的关系运算

     指针的关系运算就是指针比较大小,可以通过运用该知识来访问数组。

int main()
{int arr[10];int i = 0;for (i = 0; i < 10; i++){arr[i] = i + 1;//数组内10个元素分别为1 2 3 4 5 6 7 8 9 10}//通过指针来访问并打印这个数组int sz = sizeof(arr) / sizeof(arr[0]);//sz为数组元素个数//我们需要知道arr的首地址,再通过+-运算顺藤摸瓜找到后面所有元素int* p = &arr;//数组名代表数组首元素的地址while (p < arr + sz){printf("%d  ", *p);p++;}return 0;
}

 p接收的是arr的首地址,而sz是元素个数,所以通过p++,p会无限接近arr最后一个元素arr[sz-1],直到打印出来之后,while循环结束。

六、野指针

概念:野指针就是指针指向的位置是不可知的

6.1.野指针产生原因

6.1.1 指针未初始化

      未初始化的变量(int *p),变量的值是随机的,无法访问(此时写*p=20会报错)

6.1.2 指针越界访问

将for循环中的i<10改成i<20,此时出现越界访问。

      当指针指向的返回超出数组的范围,就是越界访问,此时p是野指针。

6.1.3 指针指向的空间释放

上面这段代码中,调用test函数,test函数的返回值是一个局部变量,test运行后已经被释放了,但是第一张图运行还是可以运行出10这个数据,原因是我们理解的销毁其实时空间所有权被释放,当其他函数执行需要开栈帧时,会把这里给占用,但是第一张图运行时还没有函数来占用,所以10这个数据被保存了下来,而第二张图在调用test函数后面又加了一段打印hehe的代码,此时printf的调用占用了这块空间,此时再去访问得到的就是一个随机值。

      当指针指向的空间已经被释放(常见的就是调用的函数的返回值是一个局部变量,函数一调用结束该变量立刻被销毁。),p指向一块无法访问的内容,此时p是野指针。

6.2 如何规避野指针


6.2.1 指针初始化


     在指针变量创建的时候就要进行初始化,如果不知道指针应该指向哪里,那么可以将指针赋值给NULL,NULL是C函数中定义的一个标识符常量,他的值是0,地址也是0,所以读取该地址时程序会报错,相当于程序会提醒你这是个野指针,不要去使用。

6.2.2 避免越界访问
   

比如程序向内存申请了一个存放arr数组的空间,那么指针也只能访问这些空间,一定不要超出这个范围去访问。

6.2.3 当指针不再使用时,即使置NULL,指针使用前检查有效性


     当我们后期不需要使用这个指针去访问空间时,即使内置NULL,因为将指针变量设置成NULL,一旦误用后系统就会报错,这样可以把野指针暂时管理起来。

      另一方面,当我们书写了大量代码后,可能会没有及时发现野指针的出现,这时候我们可以在使用前判断是否是NULL,根据情况决定是否继续使用这个指针

6.2.4 避免返回局部变量的地址
     

局部变量在函数执行完,空间所有权就会被释放,一但其他函数执行需要开栈帧,就会占用该空间。

七、assert断言
     

assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报 错终⽌运⾏。这个宏常常被称为“断⾔”。

     assert() 宏接受⼀个表达式作为参数。如果该表达式为真(返回值⾮零), assert() 不会产⽣ 任何作⽤,程序继续运⾏。如果该表达式为假(返回值为零), assert() 就会报错,在标准错误 流 stderr 中写⼊⼀条错误信息,显⽰没有通过的表达式,以及包含这个表达式的⽂件名和⾏号。

 assert() 的好处:

1.⾃动标识⽂件和 出问题的⾏号

2.⽆需更改代码就能开启或关闭 assert() 的机制。如果已经确认程序没有问 题,不需要再做断⾔,就在 #include 语句的前⾯,定义⼀个宏 NDEBUG (#define NDEBUG)。

assert() 的坏处:

1.因为引入了额外的检查,增加了程序的运行时间。

2.release版本中需要确保代码没问题的情况下禁用assert操作,确保影响用户使用程序的效率。(一些编译器的release需要禁用,但是vs这样的集成开发环境直接就是优化掉了)

八、理解传值调用和传址调用
     

 传值调用和传址调用本质区别就是有无用到指针,指针-指针运算模拟strlen函数的实现,其实就是传址调用的一种方法,其实有一些问题的解决不使用指针是无法解决的,比方说下面模拟swap函数的实现。

       swap函数,即通过这个函数交换两个整型变量的值。在没学习指针前,我会这样写----

 但是没有产生我们想要的效果,原因是实参传递给形参时,形参会单独创建一份临时空间来接受实参,对形参的修改不会影响到实参的值,x和y确实接收到了a和b的值,不过x的地址和a不一样,y的地址和b不一样,所以在swap函数内部去交换x和y的值,本质上不会影响到a和b,说明swap函数是失败的,这种函数调用方法在学习函数的时候就已经了解了,就是传值调用,其特点就是对形参的改变不会影响实参的数据。

     所以我们想要实现swap函数,就需要使用传址调用,让swap函数可以通过地址间接操作main函数中的a和b,达到交换的效果。

void swap2(int* px, int* py)
{int temp = *px;*px = *py;*py = temp;
}
int main()
{int a = 10;int b = 20;printf("交换前:a=%d  b=%d\n", a, b);swap2(&a, &b);printf("交换前:a=%d  b=%d\n", a, b);
}

       通过传址调用,swap函数成功了,我们可以总结出以下结论:传址调用可以让函数和主调函数之间建立真正的联系,在函数内部可以修改主调函数中的变量,所以未来我们仅仅只是需要主调函数中的变量值来进行计算而不改变变量值,那么可以采用传值调用,如果函数内部要修改主调函数中变量的值,那么就需要传址调用。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/41952.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Micron近期发布了32Gb DDR5 DRAM

Micron Technology近期发布了一项内存技术的重大突破——一款32Gb DDR5 DRAM芯片&#xff0c;这项创新不仅将存储容量翻倍&#xff0c;还显著提升了针对人工智能&#xff08;AI&#xff09;、机器学习&#xff08;ML&#xff09;、高性能计算&#xff08;HPC&#xff09;以及数…

2024年最新运维面试题(附答案)

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 公众号&#xff1a;网络豆云计算学堂 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a; 网络豆的主页​​​​​ 一&#xff0e;选择题 1.HTTP协议默认使用哪个端口…

科普文:构建可扩展的微服务架构设计方案

前言 微服务架构是一种新兴的软件架构风格&#xff0c;它将单个应用程序拆分成多个小的服务&#xff0c;每个服务都运行在自己的进程中&#xff0c;这些服务通过网络进行通信。这种架构的优势在于它可以提高应用程序的可扩展性、可维护性和可靠性。 在传统的应用程序架构中&…

高效管理个人日程,智慧校园行政办公全指南

在智慧校园的行政办公体系里&#xff0c;个人日程管理功能担当起协调与优化每位教职员工日常安排的角色&#xff0c;它像一位贴心的时间助理&#xff0c;确保工作与私人生活的和谐并进。这一功能设计得既直观又灵活&#xff0c;让使用者能以自己偏好的视角审视时间规划&#xf…

创新配置,秒级采集,火爆短视频评论抓取

快速采集评论数据的好处 快速采集评论数据是在当今数字信息时代的市场趋势分析和用户反馈分析中至关重要的环节。通过准确获取并分析大量用户评论&#xff0c;您将能够更好地了解消费者的需求、情感和偏好。集蜂云采集平台提供了一种简单配置的方法&#xff0c;使您能够快速采…

Deep Filtered Back Projection for CT Reconstruction

CT重建中的深度滤波反投影 论文链接&#xff1a;https://ieeexplore.ieee.org/document/10411896 项目链接&#xff1a; ABSTRACT 滤波反投影(FBP)是一种经典的计算机断层扫描(CT)重建解析算法&#xff0c;具有很高的计算效率。然而&#xff0c;用FBP重建的图像往往存在过多…

NATAPP内网穿透使用

1. natapp能干嘛 可以将本地的内网ip映射到外网上&#xff0c;远程访问该连接&#xff0c;实现外网展示网站。平时做的应用开发都只能在局域网本地访问&#xff0c;通过内网穿透&#xff0c;可以通过外网进行访问。 2. 注册用户 网址&#xff1a;https://natapp.cn/自行完成…

什么是 Elasticsearch 数据预热?

引言&#xff1a;在现代的信息检索和数据分析领域&#xff0c;Elasticsearch 已经成为一个广泛应用的分布式搜索和分析引擎。作为开源项目的一部分&#xff0c;Elasticsearch 提供了强大的实时搜索和分析能力&#xff0c;使得处理大规模数据变得更加高效和可靠。然而&#xff0…

Canary,三种优雅姿势绕过

Canary&#xff08;金丝雀&#xff09;&#xff0c;栈溢出保护 canary保护是防止栈溢出的一种措施&#xff0c;其在调用函数时&#xff0c;在栈帧的上方放入一个随机值 &#xff0c;绕过canary时首先需要泄漏这个随机值&#xff0c;然后再钩爪ROP链时将其作为垃圾数据写入&…

对接海康sdk-linux下复制jar包中resource目录的文件夹

背景 在集成海康sdk时,需要将一些组件放到项目中作为静态资源,并且海康的sdk初始化也需要加载这些静态资源,在windows下,使用一些File路径的方式是可以正确加载的,但是在linux上就会加载失败。 首先我是将海康的sdk组件放到resource下的,并且按照windows和linux设置了两…

轻松快速上手Thekey库,实现数据加密无忧

Thekey的概述&#xff1a; Thekey库是一个Python库,旨在简化数据加密、解密、签名和验证的过程。它提供了一套简洁易用的接口,用于处理各种加密任务,适合需要在应用程序中实现安全数据处理的开发人员. 安装Thekey库 pip install thekey使用Thekey库进行基本加密和解密操作的…

【笔记】TimEP Safety Mechanisms方法论

1.TimEPM Overview 三大监控方法: Alive Supervision 实时监督Logical Supervision 逻辑监督Deadline Supervision 限时监督相关模块框图: 相关模块调用框图: 每个MCU核开启内狗(1核1狗),内狗用于监控相应核的TASK超时,超时后软reset MCU内狗时钟需要独立于OS时钟,两…

C++下Protobuf学习

C下Protobuf简单学习 Protobuf&#xff08;Protocol Buffers&#xff09;协议是一种由 Google 开发的高效的、跨语言的、平台无关的数据序列化协议&#xff0c;提供二进制序列化格式和相关的技术&#xff0c;它用于高效地序列化和反序列化结构化数据&#xff0c;通常用于网络通…

DDR3(三)

目录 1 预取1.1 什么是预取1.2 预取有哪些好处1.3 结构框图1.4 总结 2 突发2.1 什么是突发2.2 突发与预取 本文讲解DDR中常见的两个术语&#xff1a;预取和突发&#xff0c;对这两个概念理解的关键在于地址线的低位是否参与译码&#xff0c;具体内容请继续往下看。 1 预取 1.1…

JDBC【封装工具类、SQL注入问题】

day54 JDBC 封装工具类01 创建配置文件 DBConfig.properties driverNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/qnz01?characterEncodingutf8&serverTimezoneUTC usernameroot passwordroot新建配置文件&#xff0c;不用写后缀名 创建工具类 将变…

C++笔试强训2

文章目录 一、选择题二、编程题 一、选择题 和笔试强训1的知识点考的一样&#xff0c;因为输出的是double类型所以后缀为f,m.n对其30个字符所以m是30&#xff0c;精度是4所以n是4&#xff0c;不加符号默认是右对齐&#xff0c;左对齐的话前面加-号&#xff0c;所以答案是-30.4f…

推荐Bulk Image Downloader插件下载网页中图片链接很好用

推荐&#xff1a;Bulk Image Downloader chome浏览器插件下载图片链接&#xff0c;很好用。 有个网页&#xff0c;上面放了数千的gif的电路图&#xff0c;手工下载会累瘫了不可。想找一个工具分析它的静态链接并下载&#xff0c;找了很多推荐的下载工具&#xff0c;都是不能分…

vue2 data内对象引用另一个data对象无法使用this的解决办法

背景&#xff1a;data内有一复杂对象&#xff0c;并且内部一属性经常修改&#xff0c;每次修改的话属性.属性会很长&#xff0c;所以希望引用另一简单对象&#xff0c;但data内this用不了。(集合数组是地址引用&#xff0c;基本数据类型这么操作没意义) 如&#xff1a; 解决办法…

数字信号处理及MATLAB仿真(3)——采样与量化

今天写主要来编的程序就是咱们AD变换的两个步骤。一个是采样&#xff0c;还有一个是量化。大家可以先看看&#xff0c;这一过程当中的信号是如何变化的。信号的变换图如下。 先说说采样&#xff0c;采样是将连续时间信号转换为离散时间信号的过程。在采样过程中&#xff0c;连续…

进程的控制-孤儿进程和僵尸进程

孤儿进程 &#xff1a; 一个父进程退出&#xff0c;而它的一个或多个子进程还在运行&#xff0c;那么那些子进程将成为孤儿进程。孤儿进程将被 init 进程( 进程号为 1) 所收养&#xff0c;并由 init 进程对它们完成状态收集工作 为了释放子进程的占用的系统资源&#xff1a; …