EOF,static关键字等,define定义符号与宏,指针

关于EOF(end of file)

1.EOF是文件结束标志,这是C语言中系统定义好的(#define EOF -1),因此本质上是-1。

2.若scanf()读取正常,读到了数据,scanf()返回的是读到的有效数据的个数。

3.若scanf()读取失败,啥也没读到,scanf()返回的是EOF,即-1。

4.那比如说在while循环中,怎么样才能让如:scanf("%d",&a)读取失败呢,理论上来讲只要按一下Ctrl+Z即可,但是由于VS的某种BUG,需要按三下Ctrl+Z才能让其读取失败返回EOF,跳出while循环。如下图:

8cb652f7f1304c8d8b77f8559231f961.pngba55443bd6da480ca71b5e2f05f7e7a1.png

36c0cdfa1c5147859dbfcbf2f48abeb9.png6c7c9b7e5577428691c9e4cac21191ca.png

register关键字

1.Register即为寄存器,是一种存储器。

2.在计算机中,数据都存储在哪里?计算机有金字塔存储结构:

 CPU(中央处理器)用来运算与处理数据,越在金字塔顶端,内存越小(但只要能适配CPU处理即可),读取速度越快,造价也越高。像网盘,虽然内存大,但读取速度慢,并且数据不在电脑上,而在它服务器里面。

CPU从寄存器中获取要处理的数据,与此同时,接下来要处理的数据会在寄存器中排好队等待CPU获取,如果数据不在寄存器中,如在内存里,则会从内存---高速缓存--寄存器这样跑到寄存器里面来(寄存器与内存无关,是独立的存储空间)

00128e6df48c476eb97c94809c654c06.png

3.而Register关键字就是建议编译器把变量直接放到寄存器里面(但现在编译器很聪明,即使不加,一般也会把变量放到寄存器里面)

register int a = 0;

typedef关键字(类型改名关键字)

1.就是将类型重命名,起个名字而已

2.比如说将复杂的类型名称简单化

typedef unsigned int A;//将类型unsigned int(无符号整形)名称重命名为A
int main()
{
    A num=0;
    return 0;
}

static关键字(称为“静态的”)

1.首先得再次强调一下局部变量的作用域,进入作用域生成,然后出作用域就会自动销毁。

2.static有三种用法:一是修饰局部变量,二是修饰全局变量,三是修饰函数。

3.首先先得了解一下内存。内存也是用来存储数据的,内存里面分为三个部分:栈区,堆区和静态区。

524ea6db756b4adfb7eabc67402ec3f4.png

       堆区先知道有这么一回事就ok了,主要是动态内存分配,如malloc,calloc,free,realloc,目前也不懂就了解一下

       栈区里面放局部变量,函数参数等等,反正都是临时的变量,都是进入作用域创建,出了作用域就销毁/释放。

        静态区里面放全局变量与静态变量。放在静态区的数据创建后直到程序结束后才会释放。

4.static修饰局部变量。普通的局部变量是放在栈区上的,这样的话都是进入作用域创建,出了作用域就会销毁/释放/回收。但是当局部变量定义时前面用static修饰,这个局部变量就会被放在内存中的静态区中了(内存中的存储位置改变了),不会放在栈区了。那放在静态区的变量创建好后,直到程序结束才能被回收与释放了。本质上:static修饰改变了局部变量的存储位置,因为存储位置的差异,使得执行效果不同,修饰后出了作用域也不会销毁。

23bf51f950bf43bfbb1277b949220f5f.png0f32dc70a0bb4823aa1cd536a7f2400c.png

 但需要注意说明的是,a还是局部变量a,作用域是仍然不变,即此时被static修饰时不影响作用域,但是相当于把局部变量的生命周期加长了。

5.static修饰全局变量。全局变量的作用域是整个工程,生命周期也是整个程序,如果要在不同的.c文件中使用,需要用extern来声明外部符号,如:

extern int g_val;

同时,也还得了解到,一个工程最终只有一个可执行程序文件(.exe),步骤是这样的,text.c--编译+链接(会从其他.c文件中寻找text.c中没有的符号)--生成一个可执行程序文件。

全局变量本身是具有外部链接属性(内部链接属性肯定有),即在一个.c文件中定义的全局变量在另一个.c文件中也可以通过链接使用。但如果全局变量在定义时前面被static修饰,这个外部链接属性就变成内部链接属性,也就是说外部链接属性没有了,这个全局变量只能在自己所在的源文件中使用,也就是说限制了全局变量的使用范围。本质上:static修饰会将外部链接属性变成内部链接属性,进而使得全局变量的作用域变小了,不在是整个工程了。独享使用,相当于隔离,其他.c文件想要用?没门,就算extern 声明了外部符号也没有用了。

59bc0c8a016640689e0d2c1bcf905e5f.png

 6.static修饰函数与修饰全局变量非常非常相似。与全局变量一样,函数本身也是有外部链接属性,但是在定义函数时被static修饰后,外部链接属性就变成了内部链接属性使得函数也只能在自己所在源文件中使用了,其他源文件中无法使用了。

f06694afe7284ce28f7eea94f8d7bfe5.png

补充:编译器都是对.c文件进行单独编译,不是在一起编译的,这也是为什么要声明外部符号与函数,不然编译器发现在本个,c文件中没见过这个符号与函数就会报错。
#define 定义常量与宏

1.#define可以定义符号,定义符号就是定义一个常量,如:

#define pai  3.14

定义了一个符号pai 的值为3.14,是全局的,但不是全局变量。

同时也要注意#define语句是不需要在后面加上分号,同时定义常量的时候也不需要加等号

2.#define 也可以定义宏,宏是来处理简单逻辑的,类似与精简低配版的函数,与函数用法极其类似。

3.宏是有括号的,并且带有参数(宏参),宏名与宏体。

4.比如说定义一个宏,这个宏的功能就是比较两个数的大小。

# define Elon(x,y)  (x<y?x:y)

5.在代码中碰到宏的时候,编译器会将宏替换成宏体,并且将参数输入。

指针

1. 要想弄懂指针的底层逻辑,就要弄懂内存,在上文已经谈过了一下内存,这里继续详细讲一下。内存是计算机上的一种存储介质,存储空间,比如内存有4G,6G,8G,内存用处:程序运行的时候会载入到内存,程序中如果有数据需要存储,也会开辟/申请一个内存空间用来存储数据。

2.那么还如何有效使用与管理内存呢?先想象一个一个场景:比如说有一栋楼,这栋楼有一个个房间,每个房间都有自己的编号。而事实上计算机内存也差不多,计算机将内存划分为一个个小的内存单元,同时对其进行编号,这样子就能有效管理内存。在空间划分实践中,一个内存单元的大小为1字节,每个内存单元都有编号(内存编号),内存编号也可以称为地址,在C语言中地址也称为指针。                   内存编号=内存单元的地址=指针

3.如果要访问一个内存单元,那么得依托内存编号,那内存编号/内存单元的地址/指针是如何产生的呢?也就是说到底是怎么样来命名这个内存单元编号/地址/指针呢?

以32位机器为例(电脑有32与64位之分),这个物理机器有32根地址线,如果电脑的地址线通电,就会有电信号(高电频或者低电频),这些电信号会转化为数字信号(0/1),因此:一根地址线-----一个电流信号-----一个数字信号(0或1),32根地址线合在一起就会有32比特位的二进制序列,这样子的话电信号转化为数字信号有2^32种二进制序列,由于一个二进制序列为一个内存单元的编号/地址/指针,因此这样下来总共有2^32个地址,就可以管理2^32个内存单元=2^32个字节的内存空间=4GB的内存空间。

6596ab0446524dc3b443b44df4409233.png

例如:

int a = 0;

创建一个整形变量a,由于整形占4个字节,因此会向内存申请四个内存单元,这四个内存单元都会有地址(32位二进制序列),但二进制事实上太麻烦了,于是将32位的二进制序列转化为16进制:一个十六进制位=4个二进制位(比特位),如0010=0x2,1101=0xd。因此一个内存单元原先的地址/指针(32位二进制序列)可以转化为8位十六进制序列。所以地址或者指针无非就是一个8位的十六进制序列而已。

4,但话说回来,这个地址/指针又有什么用呢?这个好比就是门牌号,首先我得先记下来,然后等到寒假的时候给你寄寒假作业。存指针的变量就叫做指针变量,指针变量也是变量,也需要定义,如下:

int * pa = &a;

int 表示指针变量里的地址所对应的变量的类型

*就是来告诉pa是指针变量,指针变量的名字是pa,而不是*pa

&a是取地址(变量占多个内存单元,取的是占第一个内存单元的地址)

%p是专门用来打印地址的

%zd是专门打印sizeof()的返回值的,sizeof返回的单位是字节,返回的是变量所占内存(单元)的大小。

5.指针变量的大小。指针变量是用来存放地址的,地址在32位机器上,是32个bit位,在64位机器上,是64个bit位。因此,在32位机器上,指针变量存放的是32bit的地址,也就是说指针变量大小为4个字节(指针变量大小与内存单元大小是完全不同的概念,不要被搞混了),无论指针指向的对象类型为啥,只要在32位机器上,指针变量大小就为4个字节。

6. 指针有时候在口头上也等于指针变量,但事实上指针是地址。指针变量是存放变量所占内存空间 “首地址” 的变量。

7.对4进行进一步解释,地址/指针最终是为了干什么呢,最终是为了解引用操作,首先要把地址存起来,这就需要定义指针变量来存放地址,有了存放地址的指针变量之后,就可以进行解引用操作。pa与*pa与&pa是有区别的,pa就单是指针变量的名称而已(顺便说一句,指针变量也是变量,也需要开辟一个新的内存空间来存储这个变量),而*pa相当于一根针筒,先插入指针变量里的地址所对应的变量的值,再把那个值给抽出来,而&pa就单纯是取地址而已。

3793db8485d244caa51416e6cee55431.png

 da662e203d384251a8364cc8ee2234f5.png

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

絕知此事要躬行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值