【REVIEW_C】【持续更新】

目录

[1. 在终端给main传参](#1. 在终端给main传参)

[2. 文件路径](#2. 文件路径)

[3. 头文件<>,""](#3. 头文件<>,"")

[4. 涉及到内存概念](#4. 涉及到内存概念)

[5. 32bit系统地址总线](#5. 32bit系统地址总线)

6.常量和变量

7.命名规则

[8. C语言不支持二进制输入](#8. C语言不支持二进制输入)

9.计算机区分整数的正负

[10. float、double](#10. float、double)

[11. 字符串](#11. 字符串)

[12. 头文件路径](#12. 头文件路径)

[13. printf](#13. printf)

[14. 大端小端](#14. 大端小端)

[15. 缓冲区](#15. 缓冲区)

16.变量

[17.数组 *( E1 + E2 )](#17.数组 *( E1 + E2 ))

[18. * &](#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 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函数就是采用行缓冲。

刷新缓冲区的方法:

  1. 执行过程中遇到换行符"\n"
  2. 程序正常执行结束
  3. 执行过程中出错,程序直接报错 → 无缓冲区
  4. 调用输出刷新函数fflush()
  5. 当前页缓冲区填满
  6. 当前行缓冲区填满

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括号中的表达式是不会实现运算和处理的

相关推荐
Vuji1 小时前
Pi 插件解剖|todo.ts:297 行,拼出工具+命令+状态的完整插件
前端·agent
明月_清风1 小时前
开发者写PPT自救指南:4类对接场景,把技术讲清楚
前端·后端·面试
探索前端1 小时前
3dtiles加载时被地形遮挡问题研究及处理思路
前端·3d·cesium
Htr_1 小时前
Vercel 使用指南:框架、工作流与基础设施一体化的现代 Web 部署平台
前端
皮皮虾❀1 小时前
广州云服务器价格:阿里云代理商折扣报价单指南
运维·服务器·阿里云
一颗烂土豆1 小时前
ECharts 太平面?试试这款 Vue 3D 图表库
前端·vue.js·echarts
金刚钻信息1 小时前
如果服务器坏了,加密文件还能恢复吗?
服务器·网络·加密软件·桌面管理·防泄密
anyup1 小时前
迁移uni-app x,我是如何让 AI 把我一步步搞崩溃的...
前端·uni-app·trae
过去式的美好1 小时前
阿里云 2 核 2G 服务器搭建 AI 知识库:从 0 到可用(附踩坑实录)
服务器·人工智能·阿里云