目录
1. 在终端给main传参
2. 文件路径
3. 头文件<>,""
4. 涉及到内存概念
5. 32bit系统地址总线
6.常量和变量
7.命名规则
8. C语言不支持二进制输入
9.计算机区分整数的正负
10. float、double
11. 字符串
12. 头文件路径
13. printf
14. 大端小端
15. 缓冲区
16.变量
17.数组 *( E1 + E2 )
18. * &
19.变量data的本质
20.数值的两个特殊情况
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 00000000 00000000 00000111 1111(原码、反码、补码)
128 →0000 00000000 00000000 00001000 0000(原码、反码、补码)
→ 特殊数值
→ -128
129(B) →0000 00000000 00000000 00001000 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) == E1[E2]
E1[E2] == *(E1+E2) == *(E2+E1) == E2[E1]
18. * &
*操作数 ==> 操作数必须是地址 ==> *地址 可以得到该地址的数据
E1[E2] ==> *(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括号中的表达式是不会实现运算和处理的。