基础语法
@[toc]
一、前言
1.1 概述
1.1.1 学嵌入式用C语言的理由
优势 | 一句话解释 |
---|---|
直接控制 | 用指针和位操作直接命令硬件,像操作开关一样精准。 |
高效精简 | 代码小,速度快,资源占用极低,最适合资源有限的单片机。 |
通用标准 | 行业“普通话”,所有芯片和官方库都支持,代码可跨平台复用。 |
生态成熟 | 遇到任何问题,都有海量的现成代码、项目和教程可用。 |
1.1.2 C语言的标准
标准版本 | 发布年份 | 发布组织 | 主要特点与新增功能 |
---|---|---|---|
C89 / C90 | 1989 / 1990 | ANSI / ISO | • 奠定基础:确立了第一个官方 C 语言标准,成为通用基石。 |
C99 | 1999 | ISO/IEC | • 功能扩展: - inline 内联函数 - 变量声明位置更灵活 - 变长数组 (VLA) |
C11 | 2011 | ISO/IEC | • 现代化: - 增强与 C++ 的兼容性 - 官方多线程支持 (<threads.h>) - 泛型表达式 (_Generic) |
1.2 编程环境搭建
-
编译器:gcc
-
集成开发环境:
(1)Trae
- 国内首个 AI 原生 IDE,内置豆包 1.5 Pro 和 DeepSeek R1/V3 双模型
(2)Visual Studio
下载:前往 Visual Studio 官网(https://visualstudio.microsoft.com/)下载安装程序。在下载时,可根据需求选择不同版本,如社区版(免费用于个人、开源及小型团队开发)。
安装:运行安装程序,在安装选项中,务必勾选 “C++ 桌面开发” 工作负载,因为它包含了 C 语言的编译器等开发工具。安装过程可能需要一些时间,安装完成后启动 Visual Studio。
(3)Visual Studio Code
安装:从 Visual Studio Code 官网(https://code.visualstudio.com/)下载并安装。
配置 C/C++ 插件:打开 VS Code,点击左侧的扩展图标,搜索 “C/C++” 插件,选择由 Microsoft 官方发布的进行安装。安装完成后,VS Code 会自动检测已安装的 GCC 编译器(前提是环境变量配置正确),即可用于 C 语言开发。它具有智能代码补全、语法高亮、代码导航、调试支持等强大功能。
1.3 语言分类介绍
- 编译型语言:C、C++
- 解释型语言:Python、JS
1.4 C语言编译器介绍
版本 | 核心本质 | 目标与特点 | 产物依赖 | 来源 |
---|---|---|---|---|
GCC | 跨平台编译器 | 跨平台的标准编译器 | 标准库 | GNU 项目 |
MinGW | 原生Windows移植版 | 轻量级,编译原生 Windows 程序 | Windows API (msvcrt.dll) | MinGW 项目 |
Cygwin | POSIX 模拟环境 | 在 Windows 上模拟 POSIX (类 Linux) 环境 | 需依赖 cygwin1.dll | Cygwin 项目 |
MSVC | Windows 官方编译器 | 微软官方,与 Visual Studio 深度集成 | MSVC 运行时库 (VCRUNTIME) | 微软 |
二、基础语法
2.1 第一个C语言程序
(注释掉后,注释部分程序就不会运行)
- 行注释 //
- 快键键 ctrl+/
- 块注释 /**/
- 快捷键 shift+alt+a
#include <stdio.h>//头文件
int main() //主函数
{
printf("hello world\n");//打印输出
return 0;
}
这是一个最基本的c语言程序,可以先看着自己多打几遍,然后确保不看能完整写出来。
2.2 数据类型
在 C 语言中,数据类型是程序设计的基础,它定义了变量或表达式可以存储的数据种类、范围的范围以及可进行的操作。数据类型的核心作用和意义主要体现在以下几个方面:
(1)内存管理
不同数据类型占用的内存空间不同(如char占 1 字节,int通常占 4 字节)。编译器根据数据类型分配相应大小的内存,避免内存浪费或不足。例如:
char c; // 分配1字节内存
int i; // 分配4字节内存
(2)限定数据范围与精度
数据类型决定了变量能表示的数值范围或数据形式:
整数类型(short、int、long)有不同的取值范围
浮点类型(float、double)区分精度(float约 6-7 位有效数字,double约 15-17 位)
字符类型(char)专门用于存储 ASCII 字符
2.2.1 变量的语法
-
变量在使用前必须先定义,定义变量前必须有相应的数据类型;
-
在程序运行过程中,其值可以改变;
-
#include <stdio.h>
int main()
{
//const修饰常变量
const int a = 10;//const修饰a后,a变为常变量,不可再赋值改变,但本质仍然是变量
//int arr[a] = { 0 };//数组内需要使用常量
//#define 定义的标识符常量
#define max 100 //#define 定义的标识符常量,定义max等价于值100
#define abd "hmj" //#define 定义的标识符常量,定义abc等价于字符串hmj
int b = max;//给b赋值100
printf("%d\n",b );//会输出100
printf("%s\n",abd);//会输出hmj
//枚举常量
enum color
{
ren,blue,green
};
enum corol c = ren;
enum corol d = green;;
printf("%d\n",c);//枚举常量数值默认是从0开始
printf("%d\n",d);
return 0;
}
2.2.2 命名规则和规范
标识符是用户编程时使用的名字, 用于给变量、 函数、 结构体等命名
-
命名规则
-
规则:规则是一定要遵循,不遵循就报错
-
由数字, 字母, 下划线_组成
-
不能使用数字开头
-
不能使用关键字
-
严格区分大小写
-
-
关键字(这个不用记):已经占用的名字,用户起名不能和关键字重名
-
-
命名规范:可以不遵循,只是一个建议,建议英文的见名知意
- 大驼峰:每个单词首字母大写, 例如: MyFirstName
- 小驼峰:第二个单词开始首字母大写, 例如: myFirstName
- 下划线命名:每个单词之间使用下划线连接, 例如: my_first_name
2.2.3 char类型
- char的本质就是一个1字节大小的整型,一个字符对应一个ASCII 编码数字
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main()
{
char hmj = 'a';//字符类型char,定义hmj为字符’a‘
char arr1[] = "humengjie";//在字符串humengjie后面有个\0结束标志,长度为10
char arr2[] = { 'h','u','m','e','n','g','j','i','e' };//长度为9,但是由于没有\0结束标志,输出时,会有乱码
char arr3[] = { 'h','u','m','e','n','g','j','i','e','\0'}; //长度为10
printf("%s\n", arr1);//输出humengjie
printf("%s\n", arr2);//输出humengjie烫烫烫乱码
printf("%s\n", arr3); //有结束标志'/0',输出humengjie
printf("%d\n", sizeof(arr1));//arr1长度为10
printf("%d\n", sizeof(arr2));//arr2长度为9
printf("%d\n", sizeof(arr3));//arr3长度为10
printf("%d\n", strlen(arr1));//sizeof:关注内存占用,包含终止符,编译时确定。
//strlen:关注字符串内容,不含终止符,运行时遍历。
printf("%d\n", strlen(arr2));
return 0;
}
2.2.4 bool类型
- 早期C语言没有布尔类型数据,以0代表逻辑假,非0代表逻辑真
- C99标准定义了新的关键字_Bool,提供了布尔类型,或者也可以使用
#include <stdio.h>
#include <stdbool.h>
int main() {
bool flag=true;//bool类型只有0和1
printf("%d\n",flag);
flag=false;
printf("%d\n",flag);
printf("%d\n",(bool)-100);// ‘(bool)转换类容’,,非0为true,0为false
return 0;
}
`
2.2.5 数据类型长度(大小)
-
数据类型的作用:编译器预算数据分配的内存空间大小。
-
通俗理解为:数据类型是用来规范内存的开销,约定数据在内存中的格式,便于存储。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
//sizeof(数据类型)可以用于获得类型长度
printf("%d\n", sizeof(int)); //4
printf("%d\n", sizeof(char)); //1
printf("%d\n", sizeof(long)); //4
printf("%d\n", sizeof(long long));//8
printf("%d\n", sizeof(float)); //4
printf("%d\n", sizeof(double)); //8
return 0;
}
-
bit(比特)
- 一个二进制代表一位,一个位只能表示0或1两种状态。
-
Byte(字节)
- 一个字节为8个二进制,称为8位,计算机中存储的最小单位是字节。
-
使用sizeof查看数据长度
○ 长度在不同平台是不一样。 -
数据溢出
#include <stdio.h>
int main() {
char temp1;//有符号取值范围为-128-127
unsigned char temp2;//无符号取值范围为0-255
temp1=128;//超出范围后会从头计算,数据溢出
temp2=256;
//%d默认四字节打印
printf("%d\n",(char)temp1);
//%u无字符打印输出
printf("%u\n",(unsigned char)temp2);
return 0;
}
2.2.6 可移植的类型
-
为了更好的兼容不同平台,在使用数据类型时会采用可移植的类型,这些类型可以确保在不同的平台下稳定的运行。
-
C语言在可移植类型 stdint.h 和 inttype.h 中规定了精确宽度整数类型,以确保C语言的类型在各系统内功能相同。
2.2.7 常量
-
与变量不同,常量的值在程序运行时不会改变
分类 举例 整型常量 100,200,-100,0 实型常量 3.14 , 0.125,-3.123 字符型常量 ‘a’, ‘b’, ‘1’ 字符串常量 “a”, “ab”,“12356”
- 自定义常量
#include <stdio.h>
#include <stdint.h>
#define max 200 // 宏定义,将max定义为100,后面出现的max都将替换为100
int main()
{
uint8_t a; // 8位 等价于 unsigned char
int8_t; // 等价于 char
uint32_t a; // 32位 等价于 unsigned int
int32_t; // 等价于 int
int temp = max;
printf("temp=%d\n", temp);
const int h = 100;
// a=200;//const修饰后为只读,不能改变
return 0;
}
- 宏替换
#include <stdio.h>
#define temp a
#define abc int
int main() {
int a=10;
temp=123;//相当于a=123
printf("%d\n",a);
abc b=20;//相当于int b=20
printf("%d",b);
return 0;
}
2.3 数值表示
2.3.1 C语言表示进制数
进制 | 描述 |
---|---|
十进制 | 以正常数字1-9开头,如15 |
八进制 | 以数字0开头,如017 |
十六进制 | 以0x或0X开头,如0xf |
二进制 | 以0b或0B开头,如0b1111 |
#include <stdio.h>
#include <stdint.h>
int main()
{
uint8_t a, b, c, d;
a = 15; //十进制表示15
b = 017; //八进制表示15
c = 0xf; //十六进制表示15
d = 0b1111;//二进制表示15
printf("10进制数表示:%d,%d,%d,%d\n", a, b, c, d);
printf("8进制数表示:%o,%o,%o,%o\n", a, b, c, d);
printf("16进制数表示:%x,%x,%x,%x\n", a, b, c, d);
printf("16进制数表示:%X,%X,%X,%X\n", a, b, c, d);
printf("16进制数表示:%#x,%#x,%#x,%#x\n", a, b, c, d);
return 0;
}
2.3.2 数值存储方式(了解)
计算机底层都是存储数据都是采用二进制,但二进制也有几种,比如:原码、反码、补码。
2.3.2.1 原码
一个数的原码(原始的二进制码)有如下特点:
-
最高位做为符号位,0表示正,为1表示负
-
其它数值部分就是数值本身绝对值的二进制数
-
负数的原码是在其绝对值的基础上,最高位变为1
下面数值以1字节的大小描述:
十进制数 | 原码 |
---|---|
+15 | 0000 1111 |
-15 | 1000 1111 |
+0 | 0000 0000 |
-0 | 1000 0000 |
2.3.2.2 反码
- 对于正数,反码与原码相同
- 对于负数,符号位不变,其它部分取反(1变0,0变1)
十进制数 | 反码 |
---|---|
+15 | 0000 1111 |
-15 | 1111 0000 |
+0 | 0000 0000 |
-0 | 1111 1111 |
2.3.2.3 补码
在计算机系统中,数值一律用补码来存储。
补码特点:
-
对于正数,原码、反码、补码相同
-
对于负数,其补码为它的反码加1
- 补码符号位不动,其他位求反,最后整个数加1,得到原码
十进制数 | 补码 |
---|---|
+15 | 0000 1111 |
-15 | 1111 0001 |
+0 | 0000 0000 |
-0 | 0000 0000 |
#include <stdio.h>
int main()
{
// int大小为4字节,32位
int a = -15;
printf("%x\n", a);
//结果为 fffffff1 补码
//fffffff1对应的二进制:1111 1111 1111 1111 1111 1111 1111 0001 补码
//符号位不变,其它取反:1000 0000 0000 0000 0000 0000 0000 1110 反码
//上面加1:1000 0000 0000 0000 0000 0000 0000 1111 最高位1代表负数,就是-15 原码
return 0;
}
2.3.2.4 补码的意义
在计算机系统中,数值一律用补码来存储,主要原因是:
- 统一零的编码
- 将减法运算转变为加法运算
示例1:用8位二进制数分别表示+0和-0
十进制数 | 原码 |
---|---|
+0 | 0000 0000 |
-0 | 1000 0000 |
十进制数 | 反码 |
---|---|
+0 | 0000 0000 |
-0 | 1111 1111 |
不管以原码方式存储,还是以反码方式存储,0也有两种表示形式。为什么同样一个0有两种不同的表示方法呢?
但是如果以补码方式存储,补码统一了零的编码:
十进制数 | 补码 |
---|---|
+0 | 0000 0000 |
-0 | 10000 0000 由于只用8位描述,最高位1丢弃,变为0000 0000 |
**示例2:**1个字节大小计算9 - 6的结果
以原码方式相加:
十进制数 | 原码 |
---|---|
9 | 0000 1001 |
-6 | 1000 0110 |
15 | 1000 0011 |
结果为-15,不正确。
以补码方式相加:
十进制数 | 补码 |
---|---|
9 | 0000 1001 |
-6 | 1111 1010 |
3 | 10000 0011 |
最高位的1溢出,剩余8位二进制表示的是3,正确。
三、输出和输入
3.1 输出
格式化占位符
打印格式 | 对应数据类型 | 含义 |
---|---|---|
%c | char | 字符型,输入的数字按照ASCII码相应转换为对应的字符 |
%d | int | 接受整数值并将它表示为有符号的十进制整数 |
%u | unsigned int | 无符号10进制整数 |
%ld | long | 接受长整数值并将它表示为有符号的十进制整数 |
%f | float | 单精度浮点数 |
%lf | double | 双精度浮点数 |
%s | char * | 字符串。输出字符串中的字符直至字符串中的空字符(字符串以’\0‘结尾,这个’\0’即空字符) |
%x,%X | unsigned int | 无符号16进制整数,x对应的是abcdef,X对应的是ABCDEF |
#include <stdio.h>
int main()
{
char ch = 'a';//1字节
printf("%c\n", ch);
short a = 12;//2字节
printf("%hd\n", a);
int b = 123;//4字节
printf("%d\n", b);
unsigned int c = 155;
printf("%u\n", c);
long d = 1345;
printf("%ld\n", d);
float pi1 = 3.14;
double pi2 = 3.14159;
printf("%f\n", pi1);//默认输出小数点后6位
printf("%lf\n", pi2);
printf("%.2f\n", pi1);//%.2表示在小数点后面保留两位数字
printf("%.5lf\n", pi2);//%.5表示在小数点后面保留五位数字
return 0;
}
3.2 输入
#include <stdio.h>
int main() {
int a,b,c;
printf("请输入:");
//scanf主要作用是从标准输入设备(通常是键盘)读取数据,并按照指定的格式将数据存储到变量中
scanf("%d,%d",&a,&b);
//第一个是格式控制字符串,指定了输入数据的类型和格式(如 %d 表示整数,%f 表示浮点数)。
//后续参数是要存储输入数据的变量地址(需使用 & 取地址符,指针变量除外)。
printf("c的值为%d\n",a+b);
return 0;
}
注意:在终端输入数据时需要和(scanf("%d,%d",&a,&b);)中%d,%d格式一样,比如:
函数 | 终端 |
---|---|
%d,%d | 1,1 |
%d %d | 1 1 |
3.3 案例
-
从键盘输入一个圆形的半径,输出圆的周长和面积
-
思路步骤
1.定义常量pi
2.定义半径变量r
3.输入半径
4.求周长和面积, * 为乘以运算符
5.输出周长和面积
#include <stdio.h>
#define pi 3.14
int main() {
float r;
printf("请输入半径:");
scanf("%f",&r);
//周长
double len=r*pi*2;
//面积
double area=r*r*pi;
printf("周长为:%.2lf,面积为:%.2lf",len,area);
return 0;
}
四、运算符
- 运算符就是在各种运算中起到特定作用的符号
- 一般情况下, 用哪个运算符, 现查现用即可
4.1 算术运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
+ | 加 | 10 + 5 | 15 |
- | 减 | 10 - 5 | 5 |
* | 乘 | 10 * 5 | 50 |
/ | 除 | 10 / 5 | 2 |
% | 取模(取余) | 10 % 3 | 1 |
++ | 前自增 | a=2; b=++a; | a=3; b=3; |
++ | 后自增 | a=2; b=a++; | a=3; b=2; |
– | 前自减 | a=2; b=–a; | a=1; b=1; |
– | 后自减 | a=2; b=a–; | a=1; b=2; |
#include <stdio.h>
int main() {
printf("5+2=%d\n",5+2);
printf("5-2=%d\n",5-2);
printf("5*2=%d\n",5*2);
printf("5/2=%d\n",5/2);//两个整数相除,只会输出整数部分
printf("5.0/2=%.2f\n",5.0/2);//要想输出小数部分,两个数至少要有一个小数
printf("5%%2=%d\n",5%2);
printf("==============================\n");
int a,b;
int num1,num2;
a=b=0;
num1=a++;//先赋值,a再加1
num2=++b;
printf("++前置: num2=%d,b=%d\n",num2,b);
printf("++后置: num1=%d,a=%d\n",num1,a);
return 0;
}
4.2 赋值运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
= | 赋值 | a=2; b=3; | a=2; b=3; |
+= | 加等于 | a=0; a+=2;等同于 a = a + 2; | a=2; |
-= | 减等于 | a=5; a-=3;等同于 a = a - 3; | a=2; |
*= | 乘等于 | a=2; a*=2;等同于 a = a * 2; | a=4; |
/= | 除等于 | a=4; a/=2;等同于 a = a / 2; | a=2; |
%= | 模等于 | a=3; a%=2;等同于 a = a % 2; | a=1; |
4.3 比较运算符
C 语言的比较运算中, “真”用数字“1”来表示, “假”用数字“0”来表示
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
== | 相等于 | 4 == 3 | 0 |
!= | 不等于 | 4 != 3 | 1 |
< | 小于 | 4 < 3 | 0 |
> | 大于 | 4 > 3 | 1 |
<= | 小于等于 | 4 <= 3 | 0 |
>= | 大于等于 | 4 >= 1 | 1 |
#include <stdio.h>
int main() {
printf("1==1:%d\n",1==1);
printf("1!=1:%d\n",1!=1);
printf("1>0:%d\n",1>0);
printf("1<0:%d\n",1<0);
return 0;
}
4.4 逻辑运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
! | 非 | !a | 如果a为假,则!a为真;如果a为真,则!a为假。 |
&& | 与 | a && b | 如果a和b都为真,则结果为真,否则为假。 |
|| | 或 | a || b | 如果a和b有一个为真,则结果为真,二者都为假时,结果为假。 |
#include <stdio.h>
int main()
{
printf("%d\n", 2 > 1 && 3 > 2);//输出1 &&为与门,两个为真才为真
printf("%d\n", 2 > 1 && 3 < 2);//输出0
printf("%d\n", 2 > 1 || 3 > 2);//输出1 ||为或门,一个为真就为真
printf("%d\n", 2 < 1 || 3 >2);//输出1
printf("%d\n", !(2 > 1 && 3 > 2));//输出0 本来为1,!取反后为0
return 0;
}
共同學(xué)習(xí),寫下你的評論
評論加載中...
作者其他優(yōu)質(zhì)文章