一些基础概念
一些建议
学习写代码不要怕出错,有什么想法就大胆写入代码中尝试运行,虚拟机爆了无所谓(重装就好了)
出现报错不要慌,初学者可以先把整条报错直接复制到bing或kimi搜索(不推荐百度),基本可以解决百分之九十的问题。在不断的报错中你会飞速进步,慢慢地就可以自己看懂报错并debug
修改完代码后记得保存并重新gcc编译,这样才能生成修改后的程序
数制是指表示数值的规则和系统。常见的数制有十进制、二进制和十六进制等
数码
数码是构成数的基本单位
在十进制中,数码包括0到9(因为每一位取值只有0到9)
在二进制中,数码只有0和1
基数
基数是指一个数制中使用的数码的数量
十进制的基数为10(0-9)
二进制的基数为2(0和1)
十六进制的基数为16(0-9和A-F)
位权
位权是指在一个数中,各个数码的位置所代表的值
位权从右到左依次为基数的幂
在十进制数123中
1的位权是10^2(即100)
2的位权是10^1(即10)
3的位权是100(即1)
123可以表示为:1×10^2 + 2×10^1 + 3×10^0 = 123
二进制是基数为2的数制,数码只使用0和1。位权依次为2^0,2^1,2^2, 等等
示例:二进制数1011
所以,1011的十进制值为:1×2^3 + 0×2^2 + 1×2^1 + 1×2^0 = 11
十六进制是基数为16的数制,数码包括0-9和A-F
(A代表10,B代表11,依此类推到F代表15)
为方便,十六进制的前缀为0x或0X(大小写不限),即0xC1F表示一个十六进制数,二进制数则不需要前缀,直接写1011即可
示例:十六进制数2A3
所以,2A3的十进制值为:2×16^2 + A×16^1 + 3×16^0 = 1187
二进制转十进制:将每一位乘以对应的位权,然后求和
十进制转二进制:通过除以2并记录余数的方法,不断重复,直到商为0
十六进制转十进制:同样将每一位乘以对应的位权,然后求和
十进制11转二进制:
十进制1187转十六进制:
位 (bit)
位是信息的最小单位,表示二进制数中的一个二进制位(0或1)
因此二进制中的数位又叫比特位
每个位只能存储一个二进制数(0或1)
例子:二进制数1011由4个位组成
字节 (byte)
字节是由8个位组成的数据单位,是计算机存储和处理信息的基本单位
一个字节可以表示256个不同的值(从0到255),因为2^8=256
例子,C语言中int类型需要四个字节的存储空间,即32bits
关系
1byte = 8bits
通常,数据的大小和存储容量常用字节(如KB、MB、GB等)来表示
1K=2^10,1M=2^20,1G=2^30
二进制的有符号数和无符号数是计算机处理中表示数值的两种方式,它们的主要区别在于是否表示正负号。补码和反码是用于表示有符号数的一些方法
无符号数是指只表示非负整数的二进制数。所有的比特位都用来表示数值,没有用于表示符号的位
例如,使用 8 位二进制数:
00000001
表示十进制的 1
11111111
表示十进制的 255
在无符号数中,所有位数用于表示数值,范围是从 0
到 2^n - 1
,其中 n
是位数
有符号数用于表示正数和负数,通常使用一个比特位来表示符号。最高位(最左边的位)称为 符号位:
0
表示正数
1
表示负数
原码表示法使用最高位(符号位)来表示正负,0表示正数,1表示负数。其余位表示数值的大小
正数的原码与其二进制表示相同,最高位符号0
负数的原码是在其绝对值的二进制表示前加一个符号位1
表示范围从 -(2^(n-1) - 1)
到 2^(n-1) - 1
,其中 n
是位数
示例:
+5的原码(假设使用8位表示):0 0000101
-5的原码:1 0000101
反码表示法是对原码的符号位保持不变,数值部分取反(0变1,1变0)
正数的反码与其原码相同
负数的反码是在其原码的基础上取反
表示范围从 -(2^(n-1) - 1)
到 2^(n-1) - 1
,其中 n
是位数
示例:
+5的反码:0 0000101
-5的反码:1 1111010
(取原码1 0000101
的反)
反码有一个问题,即存在 +0 和 -0 两种不同的表示形式(00000000
和 11111111
),因此大多数现代计算机不使用反码表示负数
补码是计算机中表示有符号数的标准方式,负数的表示通过将反码加1来获得
补码的规则是:
最高位是符号位
正数的补码与原码相同
负数的补码是将该数的反码加1
例如,使用 8 位二进制:
+5
的原码和补码都是:0 0000101
-5
的补码是:1 1111011
(在1 1111010
的基础上加1)
补码的好处是避免了+0和-0两种表示形式
补码可以比原码和反码多表示一位,表示范围从 - 2^(n-1)
到 2^(n-1) - 1
,其中 n
是位数
补码运算与无符号数的加减法一致,,使得计算机处理加减法更为简便
即小学一年级的竖式加减法,加法逢2进1,减法借位一次借2
可以自己拿笔尝试分别用原码,补码和反码来进行加减法,减法即加上负数
0
到 255
-128
到 127
(补码表示)下面以 int a = 8
为例,简要说明内存、外存与变量声明的概念
补充说明
CPU(中央处理器)概述:计算机的核心组件,负责执行指令(程序)、处理数据(计算)并协调各个硬件部件(鼠标键盘打印机)的工作
无论内外存,数据都是以二进制01形式存在的
内存是计算机内部用于存储数据的区域,主要分为三类:
主存的大小一般不会很大,在1~16GB
电脑有时间卡就是因为开启过多程序导致主存空间紧张
当CPU向主存中写入或读出数据时,这个数据也被存储进高速缓冲存储器中
当CPU再次需要这些数据时,CPU就从高速缓冲存储器读取数据,而不是访问较慢的主存,当然,如需要的数据在Cache中没有,CPU会再去读取主存中的数据
为了方便,通常内存指的是主存RAM,此后文中所有的内存都指的是主存
外存是指计算机外部的存储设备,如硬盘、固态硬盘、U盘等,用于长期存储数据。外存的数据在计算机关闭后仍然保留。与内存相比,外存的读写速度较慢。
a
的声明和赋值是临时的,只有在程序运行时会存在于内存中;一旦程序结束,变量 a
的值不会保存在外存中,除非明确将数据保存到外存中变量声明是指为变量分配内存空间并定义其数据类型。在 int a = 8;
中:
int
是数据类型,表示变量 a
将存储一个32位整数(int默认无符号)
a
是变量名,可以用于引用这个变量存储的数值
=
是赋值操作符,表示将右边的值(8)存储到左边的变量(a)中
在内存中,int a = 8
声明了一个整型变量 a
,并在内存中分配了4个字节,用于存储数字8。
进一步说,内存空间大小是以字节为单位的,变量声明就是分地盘,例如int a就把一个四字节的内存空间分给了变量a
分了地盘,每个地盘就有一个标识符,也就是内存地址,内存地址一般是32位或64位(这取决于计算机架构,现在一般是64位),内存地址从0开始
关于地址在scanf部分有更多的说明
大小端序(这玩意目前不重要,就是个数据存放顺序问题)
[ASCII 表 | 菜鸟教程 (runoob.com)](https://www.runoob.com/w3cnote/ascii.html) |
printf
是 C 语言中的一个标准输出函数,用于将格式化的字符串输出到控制台。以下是 printf
的用法以及转义符和占位符的介绍:
基本语法:
printf("格式字符串", 参数1, 参数2, ...);
占位符用于指定输出的变量类型和格式。常用的占位符包括:
%d
:输出十进制整数%f
:输出浮点数%c
:输出单个字符%s
:输出字符串%x
:输出十六进制整数%p
:输出指针地址(指针类型以后会讲,现在不必理会)%%
:输出一个百分号转义符用于在字符串中插入特殊字符。常用的转义符包括:
\n
:换行\t
:水平制表符(缩进)\\
:输出一个反斜杠\'
:输出单引号\"
:输出双引号在 C 语言中,scanf
用于从标准输入(就是键盘啦)读取数据并存储到变量中
作用:&
运算符用于获取变量的内存地址。它返回指定变量的地址,以便 scanf
可以将输入的数据存储在这个地址上
示例:
int num;
printf("请输入一个整数: ");
` scanf(“%d”, &num); // &num 获取变量 num 的地址`
在这个例子中,&num
传递给 scanf
,允许它将用户输入的整数直接存储到变量 num
的内存地址中
定义:内存地址是计算机内存中每个变量、数据或指令的唯一标识符,通常以十六进制形式表示
表示方式:可以使用指针来存储内存地址,也可以使用 %p
格式说明符在 printf
中输出地址
示例
printf("num 的地址是: %p\n", (void*)&num);
可以尝试print num和&num来看看差异
其中,num表示变量,&num表示变量在内存中的地址
ls -l # 以详细格式列出文件
ls -a # 列出所有文件,包括隐藏文件
cd:更改当前目录
cd /path/to/directory # 切换到指定目录
cd .. # 返回上一级目录
pwd:显示当前工作目录的路径
pwd
cp:复制文件或目录
cp source.txt destination.txt # 复制文件
cp -r source_directory/ target_directory/ # 递归复制目录
mv:移动或重命名文件或目录
mv oldname.txt newname.txt # 重命名文件
mv file.txt /path/to/destination/ # 移动文件
rm:删除文件或目录
rm file.txt # 删除文件
rm -r directory_name/ # 递归删除目录及其内容
mkdir:创建新目录
mkdir new_directory
rmdir:删除空目录
rmdir empty_directory
man:查看命令的手册页
man ls
echo:输出文本或变量值
echo "Hello, World!" echo $HOME # 输出 HOME 环境变量的值
gcc filename.c -o output_name
这条命令将 filename.c
编译为可执行文件 output_name
调试信息:
gcc -g filename.c -o output_name
生成带有调试信息的可执行文件,方便使用 gdb
调试(gdb之后会再讲)
优化选项:
gcc -O2 filename.c -o output_name
使用优化级别2进行编译,提升程序性能
链接多个源文件:
gcc file1.c file2.c -o output_name
编译为目标文件:
gcc -c filename.c
只编译源文件,不进行链接,生成 .o
目标文件
包含头文件路径:
gcc -I/path/to/include filename.c -o output_name
指定额外的头文件搜索路径
链接库:
gcc filename.c -o output_name -lm # 链接额外的库