C语言基础语法

71 阅读16分钟

基础语法

一、前言

1.1 概述

1.1.1 学嵌入式用C语言的理由
优势一句话解释
直接控制用指针和位操作直接命令硬件,像操作开关一样精准。
高效精简代码小,速度快,资源占用极低,最适合资源有限的单片机。
通用标准行业“普通话”,所有芯片和官方库都支持,代码可跨平台复用。
生态成熟遇到任何问题,都有海量的现成代码、项目和教程可用。
1.1.2 C语言的标准
标准版本发布年份发布组织主要特点与新增功能
C89 / C901989 / 1990ANSI / ISO奠定基础:确立了第一个官方 C 语言标准,成为通用基石。
C991999ISO/IEC功能扩展
- inline 内联函数
- 变量声明位置更灵活
- 变长数组 (VLA)
C112011ISO/IEC现代化
- 增强与 C++ 的兼容性
- 官方多线程支持 (<threads.h>)
- 泛型表达式 (_Generic)

1.2 编程环境搭建

  • 编译器:gcc

  • 集成开发环境:

(1)Trae

  • 国内首个 AI 原生 IDE,内置豆包 1.5 Pro 和 DeepSeek R1/V3 双模型

(2)Visual Studio​

下载:前往 Visual Studio 官网(visualstudio.microsoft.com/)下载安装程序。在下载… 安装:运行安装程序,在安装选项中,务必勾选 “C++ 桌面开发” 工作负载,因为它包含了 C 语言的编译器等开发工具。安装过程可能需要一些时间,安装完成后启动 Visual Studio。

(3)Visual Studio Code​ 安装:从 Visual Studio Code 官网(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 项目
CygwinPOSIX 模拟环境在 Windows 上模拟 POSIX (类 Linux) 环境需依赖 cygwin1.dllCygwin 项目
MSVCWindows 官方编译器微软官方,与 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 数据类型

<img src="01_基础语法.assets/数据类型.png" alt="数据类型" style="zoom:30%;" /> 在 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字节的大小描述:

十进制数原码
+150000 1111
-151000 1111
+00000 0000
-01000 0000
2.3.2.2 反码
  • 对于正数,反码与原码相同
  • 对于负数,符号位不变,其它部分取反(1变0,0变1)
十进制数反码
+150000 1111
-151111 0000
+00000 0000
-01111 1111
2.3.2.3 补码

在计算机系统中,数值一律用补码来存储。

补码特点:

  • 对于正数,原码、反码、补码相同

  • 对于负数,其补码为它的反码加1

    • 补码符号位不动,其他位求反,最后整个数加1,得到原码
十进制数补码
+150000 1111
-151111 0001
+00000 0000
-00000 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

十进制数原码
+00000 0000
-01000 0000
十进制数反码
+00000 0000
-01111 1111

不管以原码方式存储,还是以反码方式存储,0也有两种表示形式。为什么同样一个0有两种不同的表示方法呢?

但是如果以补码方式存储,补码统一了零的编码:

十进制数补码
+00000 0000
-010000 0000 由于只用8位描述,最高位1丢弃,变为0000 0000

**示例2:**1个字节大小计算9 - 6的结果

以原码方式相加:

十进制数原码
90000 1001
-61000 0110
151000 0011

结果为-15,不正确。

以补码方式相加:

十进制数补码
90000 1001
-61111 1010
310000 0011

最高位的1溢出,剩余8位二进制表示的是3,正确。

三、输出和输入

3.1 输出

格式化占位符

打印格式对应数据类型含义
%cchar字符型,输入的数字按照ASCII码相应转换为对应的字符
%dint接受整数值并将它表示为有符号的十进制整数
%uunsigned int无符号10进制整数
%ldlong接受长整数值并将它表示为有符号的十进制整数
%ffloat单精度浮点数
%lfdouble双精度浮点数
%schar *字符串。输出字符串中的字符直至字符串中的空字符(字符串以'\0‘结尾,这个'\0'即空字符)
%x,%Xunsigned 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,%d1,1
%d %d1 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 + 515
-10 - 55
*10 * 550
/10 / 52
%取模(取余)10 % 31
++前自增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 == 30
!=不等于4 != 31
<小于4 < 30
大于4 > 31
<=小于等于4 <= 30
>=大于等于4 >= 11
#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;
}