c 语言 基础
gcc编译器
作用: 将代码文件编译为可执行文件
分类:
一步到位
gcc 要编译的代码文件 -o 生成的可执行文件
注意:
要编译的代码文件可以是多个
-o 生成的可执行文件:可以忽略不写,默认生成a.out文件
分步实现
预编译:头文件展示,宏替换,选择型编译
gcc -E 要编译的代码文件 -o 生成的预编译文件.i
编译:检测代码错误,将预编译文件编译为汇编文件
gcc -S 预编译文件.i -o 生成的汇编文件名.s
汇编:将汇编文件转换为二进制文件
gcc -c 汇编文件名.s -o 生成的二进制文件.o
链接:将二进制文件与使用的三方文件连接生成可执行文件
gcc 二进制文件.o -o 生成的可执行文件名
运行可执行文件
> ./可执行文件名
注意:要切换到可执行文件名所在的文件夹
1 .HelloWorld
步骤:
1,创建一个文件,建议其命名为helloworld
- vim helloworld.c
//1. 创建一个文件后缀名为 helloworld.c 注意文件名不要使用中文或者数字开头。 建议 见名知意
//2. 在文件中编写以下代码
#include <stdio.h>
int main(){
printf("hello world\n");
return 0;
}
// 3. 将该文件 编译为可执行文件 如果代码文件中进行了修改,则需进行从新编译
// 4. 运行可执行文件
- 然后 按 ESC 并输入 wq 保存退出
2 .注释
作用:
1 解释说明
2 注销无用代码
语法:
// 单行注释
/**/ 多行注释 注意 :在多行注释中不能使用多行注释
注意: 注释是不会影响代码的运行
3.输入
作用:
//将控制台中的内容录入到程序
语法:
scanf("占位符",&变量);
使用
键盘录入一个数打印输出 int num = 0; scanf("%d",&num); printf("num = %d\n",num) ;
4. 输出
作用:将内容打印到控制台
语法:
printf("要输出的内容",值....);
注意:
输出的内容中有两种特殊的内容
1,转意字符
2,占位符
后面值的个数由前面内容中占位符的个数决定
输出情况:
行刷新
满刷新
关闭刷新
5.转义字符
有特殊含义的字符为转意字符,以\开始,常用的有
\\ \
\" "
\' '
\t 制表
\n 换行
\a 响铃
\0 字符串结束符
6. 占位符
- 作用:占位
%s:字符串占位符
%c:字符占位符
%d:整数占位符
%f:浮点数占位符
%p:指针占位符
%x:十六进制数占位符
特殊应用:
%3d %03d %-3d %.2f
%3d:要求宽度为 3 位,如果不足 3 位,前面空格补齐;如果足够 3 位,此语句
无效
%03d:要求宽度为 3 位,如果不足 3 位,前面 0 补齐;如果足够 3 位,此语
句无效
%-3d: 要求宽度为 3 位,如果不足 3 位,右对齐后面空格补齐;左对齐前面3位
补空格,如果足够 3 位,此语句无效
%.2f:小数点后只保留 2 位
7.关键字
目的: 明白那些是关键字
含义: 在代码中有特殊含义的单词,这种单词就成为关键字
注意:学习关键字,为了在起标识符时 不要使用。明白关键字的意义。
8. 标识符
作用: 标记的符号 用于变量名 常量名函数名 结构体名称等 只要带名 就是标识符;
规则:
自定义设定
强制规则:
1 不能使用数字开头
2 不能使用关键字
3 不能使用特殊符号 【 _ 与 $ 符号除外】
4 不建议使用中文 也就是可以使用
潜规则::见名知意
1 linux风格[c的常用]
多个单词之间以下划线 _ 连接 例如 hello_world
2 驼峰命名法【java 和 c++常用】
小驼峰
一般应用与变量名,函数名,数组名等,对应C与C++中的变量名,函数名,数组名
大驼峰
每个单词首字母大写
一般应用于类名,枚举名,接口名等可与对应C与C++中的结构体,枚举,类
全大写
所有字母全大写
一般应用于 常量名
全小写
一般应用于
应用于包名对应C与C++中存储代码的文件夹
9. 基本数据类型
分类:
- 基本数据类型
- 引用数据类型
整型
short 2 字节 8位 * 2 -2^15~2^15-1 -32768 ~ 32767 超过32767就存不了了
int 4 字节 8位 * 4=32 -2^31~2^31-1 默认使用
long 8 字节 (64位机)/4(32位机)
定义long型时 需要在定义的数据后面加L 或者小写l
long i = 30000000000L; 只要超过int型存储的数值 后就加L或者l
浮点型
float 占 4 字节 后加F 或f
double 占 8 字节
字符型
char 占 1 字节 1 字节存储 255 位
注意: 单个字符必须使用 '' 包裹
如 'a' 'A' '中' 一个单引号 一个字符
char c1 = 'a';
char c2 = 'A';
char c3 = '\\' # '\\' 这个里面只有一个东西 就是 \ 而不是两个东西
# c c++ 中没有 字符串概念 称为 字符数组 也不是基本数据类型
特殊字符: 转义字符
\\
\'
\"
\n 换行
\a 响铃
\t 制表
\0 字符串结束
最初的计算机 只 有 英文字母 + 阿拉伯数字 + 英文点符号
10. sizeof关键字
作用:
获取数据类型或数据的大小,单位字节
语法:
# sizeof(数据类型或值)
11. 变量
作用:在程序中临时记录一个值可以发生改变的数据
全局变量: 在函数外定义变量 默认值是0
局部变量: 定义在函数中的变量,默认值 随机数 基本是0 使用 auto 修饰
如;
#include <stdio.h>
//函数外
int main()
{
//函数中
return 0;
}
//函数外
注意:
全局变量 可以 与 局部变量名相同
当全局变量与局部变量名相同,优先使用局部变量 【就近原则】
使用:
1. 声明 可有可无
告知编译器有这个变量,但是此时系统并不会为其开辟内存空间
语法:
extern 数据类型 变量名;
2. 定义
告知系统创建该变量,并为其分配内存
语法:
数据类型 变量名;
【注意】
同一个作用域下变量名不能相同;
3. 赋值
变量的第一次赋值称为变量的初始化
语法:
变量名 = 值;
【注意】
一个变量可以赋值多次
等号两边数据类型要相同
4. 使用
直接使用变量名
语法:
变量名
注意:
一个变量可以使用多次
12. 数据类型转换
【小类型转换为大类型】 自动转换
char c = 'a' ; // char 字符型 1 字节
int i; // int 是整型 4 字节
i = c; // 自动转换
语法:
【 大类型变量 = 小类型变量或值; 】
【大类型转换为小类型】 为 强制转换
如:
int i = 97; // int 4b
char c; // char 1b
c = (char) i; // int 转 char 强制转换
语法:
【 小类型变量 = (转换后的小类型) 要转换的大类型变量或值; 】
注意:
可能回出现数据丢失
就类似 小类型变量 为 空水杯
大类型变量 为 水桶
大==》小 也就是 将水桶的水倒进 空水杯中
存在两种情况
1 水桶水刚好或者可以倒进 空水杯中 也就是正常转换
2 水桶水多于空水杯容量 那就会造成 溢满的数据丢失
所以要转换的时候考虑到!!!!!!!
13.存储相关关键字
register
作用: 建议寄存器存储
语法: register 数据类型 变量名; 【不建议使用】
> 寄存器存储优点:
快
> 注意:
寄存器中存储的数据容器较小,所以只会存储高频使用的变量
那么如果我们用register修饰的变量不是高频使用的,那么也有可能被寄存器中移除
volatile
作用:使用该关键字修饰的变量,会强制系统从内存中取值
语法: volatile 数据类型 变量名;
经验: 类似于瓦斯浓度、银行钱等使用该关键字修饰。
auto
作用: 自动
语法:
> auto 数据类型 变量名;
注意:
此时该变量的初始化为随机数
局部变量默认使用auto修饰
extern
作用: 声明,告知编译器存在该变量或函数 没有开辟内存
语法: extern 数据类型 变量名;
14.其他关键字
sizeof
typedef
作用: 给已有数据类型起别名
语法: typedef 已有类型 别名;
15. 进制:
二进制
0 1 10 11 100 101 110 111 1000 1001 1010..... # 计算机中 二进制 的数据以 0b 开头 int i= 0b0001; printf("i = %d\n",i);
八进制
0 1 2 3 4 5 6 7 10 11 12 13.... # 计算机中 八进制 的数据以 0 开头
十进制
00 01 02 03 04 05 06 07 08 09 10 11 12...... printf输出数据输出的就是10进制数 在计算机直接书写的数都是10进制数
十六进制
0 1 2 3 4 5 6 7 8 9 a b c d e f 10 # 计算机中 十六进制 的数据以 0x 开头
16.进制转换
10 to 2
- 技巧:十进制数 除以2 取余 余数倒读
13
2
---------
6 1
2
---------
3 0
2
----------
1 1
2
----------
1
10 to 8
- 技巧:**十进制数除以8 取余 ,余数倒读 **
13
8
---------
1 5
8
---------
1
10 to 16
- 技巧:十进制数除以16 取余,余数倒读
13
16
---------
13
2 to 10
- 技巧: 2进制所在位的数*2^位数-1次幂,相加
0100 1010
1 * 2^6 + 0 * 2^5 + 0 * 2^4 + 1*2^3 + 0*2^2 + 1*2^1 + 0 *2^0
64 + 8 + 2 = 74
8 to 10
- 技巧: 8进制所在位的数*8^位数-1次幂,相加
032
3 * 8^1 + 2 * 8^0
24+ 2
26
16 to 10
- 技巧: 16进制所在位的数*16^位数-1次幂,相加
17.原码反码补码
-
原码:数据对应的 二进制数,称为该数据的原码
-
反码:
正数
三码合一,原码=反码=补码
负数
符号位不动,其他位依次取反【首位不动】
如:
10
源码:0000 0000 0000 0000 0000 0000 0000 1010
反码:0000 0000 0000 0000 0000 0000 0000 1010
-10
源码:1000 0000 0000 0000 0000 0000 0000 1010
反码:1111 1111 1111 1111 1111 1111 1111 0101
- 补码:
正数
补码 = 反码 = 源码 [三码统一]
负数
补码 = 反码 + 1
如:
10
源码:0000 0000 0000 0000 0000 0000 0000 1010
反码:0000 0000 0000 0000 0000 0000 0000 1010
补码:0000 0000 0000 0000 0000 0000 0000 1010
-10
源码:1000 0000 0000 0000 0000 0000 0000 1010
反码:1111 1111 1111 1111 1111 1111 1111 0101
补码:1111 1111 1111 1111 1111 1111 1111 0110
18.补码的意义
意义一: **统一了 0 与 - 0 **
意义二: **将 减法运算 变 为了 加法运算 **
计算机底层以补码的形式存储数据
19.计算机的存和取
存数据: 数据(10进制) -》 原码(二进制) -》 反码 -》补码
取数据: 补码 -》 反码 -》 原码(二进制) -》 数据(10进制)
int x = 0x8000 0001; 1000 0000 0000 0000 0000 0000 0000 0001 1000 0000 0000 0000 0000 0000 0000 0000 1111 1111 1111 1111 1111 1111 1111 1111 printf("x = %d\n",x); 此时我们会发现出现的值为负数与存的值不同
运算符
作用:
运算的符号
算数运算
+ 加 - 减 * 乘 / 除 % 取余 ++ 递增 ++ 在前, 先递增再参与运算 流程: 3步 取值 +1 赋值 int a =1; a++; a=1 a = a+1 a = a; ++ 在后, 先运算后自增 流程: 4步 取值: +1 赋值: 使用取值参与运算 -- 递减 -- 在前, 先自减再运算 -- 在后, 先运算后自减
注意:
- 小类型与小类型运算,结果为小类型
如: 1 / 2 = 0; double c = 1 / 2;
- 小类型与大类型运算,结果为大类型
double c = 1 / 2.0;
赋值运算符
- =
- 作用:将等会右边的值,赋值给左边的变量
复合运算符
+= -= *= /= %=
关系运算符
< 小于 > 大于 <= 小于或等于 >= 大于或等于 == 判断是否相等 'a' == 97 != 判断是否不等 'a' != 97
注意:
- 除0以外都是真
- 0 为 假
位运算符
| 或 有1为1,全0为0 2 | 8 = 10 0010 1000 1010 & 与 全1为1 ,有0为0 2 & 8 = 0 0010 1000 0000 ~ 取反 0变1 , 1变0 ~2 0000 0000 0000 0000 0000 0000 0000 0010 1111 1111 1111 1111 1111 1111 1111 1101 1111 1111 1111 1111 1111 1111 1111 1100 1000 0000 0000 0000 0000 0000 0000 0011 -3 ^ 异或 相同为0 ,不同为1 2 ^ 8 = 10 0010 1000 1010 >> 右移 分类:【取决于计算机】 逻辑右移 高位补0 低位溢出 算数右移 高位补符号位, 低位溢出 4 >> 2 0000 0000 0000 0000 0000 0000 0000 0100 0000 0000 0000 0000 0000 0000 0000 0001 -4 >> 2 1000 0000 0000 0000 0000 0000 0000 0100 逻辑右移: 0010 0000 0000 0000 0000 0000 0000 0001 算数右移: 1110 0000 0000 0000 0000 0000 0000 0001 << 左移 4 << 2 0000 0100 0001 0000 1 << 2; 0000 0001 0000 0100 计算 2^10 1 << 10
逻辑运算符
&& 短路与 同真为真,有假为假 || 短路或 有真为真,同假为假 ! 非 非真为假,非假为真
三目运算符
条件表达式 ?值1:值2 条件表达式:结果为真或假的表达式 关系运算符 逻辑运算符 执行流程: 当条件表达式值为真,取值1,反之取值2
逗号运算符
, 如变量的定义,形参,实参等 如: int a; int b; int c; int a,b,c; 优先级最低
优先级最低
运算符优先级
- 不要将多个运算符在一个表达式中使用,尽量拆开
- 如果非用不可加 ( )
语句分类:
- 顺序语句
- 代码从上向下依次执行
- 分支语句
- 用于判断,使代码在多个之间选择一个执行
- 循环语句
- 用于重复执行
分支语句
作用:
表示判断
分类
- if
- switch
if
1 基本if结构 if(条件表达式) { 当条件表达式为真,执行此处代码 } 2 if else 结构 if(条件表达式) { 当条件表达式为真,执行此处代码 } else { 当条件表达式为假,执行此处代码 } 3 else if 结构 if(条件表达式) { 当条件表达式1为真,执行此处代码 } else if() { 当条件表达式2为真,执行此处代码 } else { 当条件表达式为假,执行此处代码 }
结合:
if(条件表达式1) { 当条件表达式1为真,执行此处代码 } else if(条件表达式2) { 当条件表达式2为真,执行此处代码 } else if(条件表达式3) { 当条件表达式3为真,执行此处代码 } ... else if(条件表达式n) { 当条件表达式n为真,执行此处代码 } else { 当以上条件表达式都为假,执行此处代码 } 注意: if 可以单独存在,一个 if 结构中必须也只能有一个 if else if 不能单独存在,一个 if 结构中可以有多个 else if else 不能单独存在,一个 if 结构中最多只能有一个 else 如果多个条件表达式都为真,只执行最上面的那个
switch
switch(变量) { case 常量1: 代码1:当变量值等于常量1时,执行此处代码 //break; case 常量2: 代码2:当变量值等于常量2时,执行此处代码 break; case 常量3: 代码3:当变量值等于常量3时,执行此处代码 break; ... case 常量n: 代码n:当变量值等于常量n时,执行此处代码 break; default: 代码n+1:当变量值不等于以上所有常量,执行此处代码 break; }
注意:
- 常量值不能相同
- 常量:写死的值或不能修改值的变量称为常量
- break:跳出当前代码块,可有可无,如果没有导致贯穿
- 代码块:一个 { } 就是一个代码块
- default:可有可无,最多只能有一个
- case : 可有可无,可以有多个
随机数
作用:随机获取一个数
步骤:
1 引入头文件
#include <stdib.h> #include <time.h>
2 设置随机数种子
srand(time(NULL)); // 一个程序只需要设置一次
3 获取随机数
rand(); //取值范围就是0 ~ int的最大值
#include <stdio.h> #include <stdlib.h> //引入头文件 #include <time.h> //引入头文件 int main(int argc, char const *argv[]) { srand(time(NULL)); //设置随机数种子 int a = rand(); printf("a = %d\n",a); //随机获取0-10之间随机数 int x = rand()%11; printf("x = %d\n",x); //随机获取0-50之间随机数 int y = rand()%51; printf("y = %d\n",y); //随机获取65-90之间随机数 int z = rand()%26+65; printf("z = %d\n",z); //随机生成一个大写字母 int d = rand()%26+65; char dx = (char)d; printf("dx = %c\n",dx); return 0; }
循环语句
作用:
重复执行一段代码
优点:
降低代码冗余度, 提高代码复用率, 提升开发效率
分类
while do while for
while
语法: while(条件表达式){ 循环体: 重复执行的代码 } 执行流程: 先判断条件表达式是否为真 如果为真,执行循环体中的代码,如果为假结束循环 当循环体中的代码执行完毕后,再次判断条件表达式是否为真 如果为真,执行循环体中的代码,如果为假结束循环 ......
死循环
条件表达式永远为真的循环,称为死循环
while(1) { }
do while
do { 循环体 }while(条件表达式); 执行流程: 先执行一次循环体,在判断条件表达式是否为真 如果为真,再次执行循环体,如果为假,结束循环 当循环体执行完毕后,再次判断条件表达式是否为真 ......
for
for (表达式1;条件表达式2;表达式3) { 循环体4 } 表达式1:初始化变量 条件表达式2:循环条件 表达式3:修改变量 循环体4:重复执行的代码 执行流程: 1 2 4 3 2 4 3 ......2
#include <stdio.h> #include <time.h> #include <stdlib.h> int main(int argc, char const *argv[]) { //生成10个随机数 srand(time(NULL)); for (int i = 0; i < 10; i++){ int x = rand(); printf("%d\n",x); } return 0; }
循环嵌套
在循环语句的循环体中写循环语句,称为循环嵌套。
不建议超过三层
流程控制语句
continue :
跳过本次循环
#include <stdio.h> int main(int argc, char const *argv[]) { for (int i = 0; i < 3; i++) { printf("xxxx\n"); continue; //会跳出本次循环 去执行下一次循环 所以只打印了xxxxx printf("yyyy"); } return 0; }
break
跳出本次循环
goto
跳转至指定位置
#include <stdio.h> int main(int argc, char const *argv[]) { printf("1\n"); goto xx; printf("2\n"); printf("3\n"); printf("4\n"); xx: printf("标签处\n"); return 0; }
return:
-
结束当前函数
return 值或变量;结束当前函数并返回该值或变量,此时这个值或变量就是返回值