目录
[1. 在终端给main传参](#1. 在终端给main传参)
[2. 文件路径](#2. 文件路径)
[3. 头文件<>,""](#3. 头文件<>,"")
[4. 涉及到内存概念](#4. 涉及到内存概念)
[5. 32bit系统地址总线](#5. 32bit系统地址总线)
[8. C语言不支持二进制输入](#8. C语言不支持二进制输入)
[10. float、double](#10. float、double)
[11. 字符串](#11. 字符串)
[12. 头文件路径](#12. 头文件路径)
[13. printf](#13. printf)
[14. 大端小端](#14. 大端小端)
[15. 缓冲区](#15. 缓冲区)
[17.数组 *( E1 + E2 )](#17.数组 *( E1 + E2 ))
[18. * &](#18. * &)
1. 在终端给main传参
在终端的输入,无论是 " ./demo " 还是 " ./xxx " 还是 " ./xxx hello " ,都是字符串。
数组中第一个元素的字符串指的都是程序的名字。

- argc的值是非负整数。
- 数组中的每个元素都是一个指针(char* argv\[\],是个指针数组,数组的每个元素都是一个指针,指针指向的地址下的数据都是字符串char* )。
- 字符串由命令行终端传递给main函数。
- 数组中的第一个元素的字符串,是程序的名字。
- 数组中的第二个元素到最后一个元素,是传递给程序的参数。
2. 文件路径
标准库/第三方库存放在" lib " 中。
头文件存放在" include " 中。
3. 头文件<>,""
官方提供的函数库都已经在系统路径中能够是存在的 ,所以用户需要使用<>包含头文件,就可以让编译器找到对应的函数接口。
< xxx.h > :编译器只去系统指定路径中查找该头文件,如果未找到,则编译器进行错误提示。
" xxx.h " :先去当前路径中查找头文件,未找到再去系统路径中查找,还未找到则报错提示。
4. 涉及到内存概念
Q : 计算机把还未处理的数据以及处理好的数据保存到哪里呢?
A :这些数据都是存储在存储器,
用户通过输入设备(键盘)录入的数据都是先存储在内存中,
然后控制器会把这些数据传递给运算器,
运算器处理完成后传递给控制器,
控制器把数据传递给输出设备(显示器)。

5. 32bit系统地址总线
32bit系统 or 64bit系统 指的是计算机的地址总线的位数,指的是计算机的寻址范围是32bit,存储单元地址:0x00000000~0xFFFFFFFF。
内存属于易失性存储设备,键盘输入的数据是先存储到内存(随机存储器RAM)中,存储器中有n个存储单元,每个在储单元的大小都是1字节。
存储单元大小是1字节,32bit系统的存储单元的地址是4字节,64bit系统的存储单元的地址是8字节。

6.常量和变量
常量:在程序运行期间值不会发生改变的量
变量:在程序运行期间值可能发生变化的量
量:指的是存储器中的存储单元。
常和变:存储器中存储单元里数据的状态。常就是数据的状态不会变;变就是数据的状态会变
7.命名规则
变量和常量也被称为标识符 ,标识符是由字母、数字、下划线以及美元符号$组成 ,并且标识符的第一个字符只能是字母或者下划线。
C语言的标识符是区分大小写
8. C语言不支持二进制输入
但是C语言支持八进制、十进制、十六进制。
规定八进制的前缀以0表示,比如064;
规定十六进制的前缀以0x/0X表示,比如0x64。
9.计算机区分整数的正负
思考:计算机可以区分整数的正负,但是程序最终都会被转换为二进制指令,但是二进制是不分正负的,请问编译器是如何转换数据的?
回答:二进制可以分正负,在二进制数的前面添加1bit,作为符号位,并且bit=0,用于表示二进制数为正数,bit=1,用于表示二进制数为负数。
正数(符号位为0时)的原码和补码是相同的 ,所以负数才需要把原码转换为补码,再进行存储!
127 → ++0000 0000++ ++0000 0000++ ++0000 0000++ 0111 1111(原码、反码、补码)
128 → ++0000 0000++ ++0000 0000++ ++0000 0000++ 1000 0000(原码、反码、补码)
→ 特殊数值
→ -128
129(B) → ++0000 0000++ ++0000 0000++ ++0000 0000++ 1000 0001(原码、反码、补码)
由于是32bit系统,并且129是常量且数值较大,所以操作系统给129的宽度是四字节的int。
129存入四字节的空间为正数 ,正数的原码、反码、补码都是原码本身。
由于赋值给char类型,从低位开始写入,所以只能写入后8位,最高位是"1",cpu就认为这个值是负值,符号位为"1"。
------读出---→ 1000 0001((补码)
→ 1000 0000 (【-1】反码)
→ 1111 1111(原码)
→ -127
先把常量转换为二进制补码,再把二进制补码往存储单元里放。
常数130存入时 ,先转成补码,再存入。
130为正数,原码反码补码都是一样的。
0000_0000 0000_0000 0000_0000 1000_0010
但是char只能取低8bit,
所以存入 1000 0010
读出时,先取出补码,再转成原码。
补码为 1000 0010 ,发现符号位是1,判定他是负数。
反码 1000 0001
原码 1111 1110 ==> -126
按上述计算,常数128经过转补码写入,再读出补码,1000 0000补码 -- 属于数据类型中非常特殊的存在,可以计算是 -0,但是0不分正负,所以 把-0的位置用-128进行替换。
原码首位为标志位,1表示负数,0表示正数。
反码 = 原码的标志位不变,其他取反。
补码 = 反码+1
正整数的原码、反码、补码相同。
cpu将数字常量存储到存储单元中,存储的是数字常量的补码(正数的补码是正数本身,负数的补码要通过计算)
读出数据时,操作系统先读出补码,再把补码换成反码,反码换成原码(-1后,0变1、1变0)
写入:先转再放(先将常量转换为二进制补码,再将二进制补码由低位到高位写入空间中)
读出:先读再转(先将二进制补码读出,再转为十进制数)
10. float、double
关键字float来表示单精度浮点数,float占4字节;
关键字double用来表示双精度浮点数,double占8字节,
C语言也提供了一种类型long double,该类型占16字节。

11. 字符串
字符串在内存是需要一块连续的内存空间进行存储,字符串的结束标志是****'**** \0 '

12. 头文件路径
stdio.h标准输入输出。在linux系统下stdio.h的位置在 /usr/include/stdio.h
13. printf
printf函数的返回值 :被输出的字符的数量(是不包含\0),当错误发生时返回一个负整数
#o可以把八进制的前导符输出
#x可以把十六进制的前导符输出 -- 0x
hh 指的是把整型转为字符型 ,只是针对输出内容而言,数据本身没有受到影响
h 指的是把整型转为短整型 ,只是针对输出内容而言,数据本身没有受到影响



0 :标志(flag),表示当++++输出++++ ++++宽度++++大于实际数字位数时,用零填充左侧空位。
.2 :精度(precision),表示++++至少输出2位数字++++,如果数字位数不足2位,则在左侧补零。
printf("%0.2d", 5); → 输出 05(精度要求两位,补一个零)。
printf("%0.2d", 123); → 输出 123(数字位数已超过精度,原样输出)。
printf("%05.2d", 5); → 输出 00005 (宽度5,精度2,实际输出数字至少两位,再补零到5位)
14. 大端小端
X86架构一般采用小端模式,ARM架构一般采用大端模式

15. 缓冲区
****全缓冲:****指的是当缓冲区被填满就立即把数据冲刷到文件、或者在关闭文件、读取文件内 容以及修改缓冲区类型时也会立即把数据冲刷到文件,一般读写文件的时候会采用
****无缓冲:****指的是没有缓冲区,直接输出,一般linux系统的标准出错stderr就是采用无缓冲, 这样可以把错误信息直接输出。
****行缓冲:****指的是当缓冲区被填满(一般缓冲区为4KB,就是4096字节)或者缓冲区中遇到 换行符'\n'时,或者在关闭文件、读取文件内容以及修改缓冲区类型时也会立即把 数据冲刷到文件中,一般操作IO设备时会采用,比如printf函数就是采用行缓冲。
刷新缓冲区的方法:
- 执行过程中遇到换行符"\n"
- 程序正常执行结束
- 执行过程中出错,程序直接报错 → 无缓冲区
- 调用输出刷新函数fflush()
- 当前页缓冲区填满
- 当前行缓冲区填满
16.变量
变量是在程序中由内核申请的一块内存,允许用户对这块内存进行命名。这样内核就可以把内存地址和变量名称建立映射关系,所以用户可以直接通过名称访问变量。
17.数组 *( E1 + E2 )
& :地址运算符,取地址
* : 间接运算符,间接访问,解引用
*( E1 + E2 )的解释:
- E1是数组对象
- E1是数组名称
C语言标准中规定 : 数组名表示数组中首元素的地址。
==> E1 是数组中首元素的地址,而E2是一个整数
==> E1 + E2 : 从E1这个地址向后偏移E2个元素单位(以元素为单位,需要考虑元素的类型)
==> E1+E2的结果还是一个地址。
*( E1 + E2) 相当于间接访问该地址 ,相当于得到了(E1+E2)这个地址下的值。
总结:*(E1+E2) == E1E2

E1E2 == *(E1+E2) == *(E2+E1) == E2E1
18. * &
*操作数 ==> 操作数必须是地址 ==> *地址 可以得到该地址的数据
E1E2 ==> *(E1+E2)
&(*(E1+E2)) ==> &*互相抵消 ==> (E1+E2)
&操作数 ==> 操作数可以是表达式 ==> &操作数 可以得到该操作数的地址
&*E == E
假设E是一个变量名,*&E ==> &E先结合,得到了变量的地址 , *(&E)可以得到该地址下的值,变量名本身就表示地址下的数值
int a\[\] = { 1, 2,3,4};
printf("%d\n",sizeof(&a)); //32bit系统下为4字节。 &a表示数组本身的地址

19.变量data的本质
//申请内存时可以把操作系统提供的存储单元的编号可以进行命名
int data ;
//对变量赋值。&data 可以得到变量名data对应的存储单元的地址。*(&data)可以得到该地址的值,只不过*&互相抵消
data = 20 ;
*&data = 30 ;

20.数值的两个特殊情况
第一种情况: 当 数组名 和 &地址运算符 一起使用时 ,数组名表示数组本身的地址,所以**+1的动作是向后偏移整个数组的大小。**

第二种情况:当 数组名 和 sizeof()运算符 单独使用的时候,数组名表示数组本身。
注意 sizeof在C语言中是一个操作符,作用是计算数据类型的大小,结果以字节为单位 ,sizeof括号中的表达式是不会实现运算和处理的。
