C 语言基础语法详解

C 语言是结构化、面向过程的编程语言,语法简洁且贴近底层,是编程入门的经典选择。本文从程序结构、数据类型、变量与常量、运算符、流程控制、函数、数组、指针(基础) 等核心维度,详解 C 语言基础语法,兼顾易懂性和实用性。

一、C 程序的基本结构

一个完整的 C 程序由预处理指令、全局声明、函数(核心) 三部分组成,最基础的 “Hello World” 示例如下:

c

运行

// 1. 预处理指令:引入标准输入输出头文件
#include <stdio.h>  

// 2. 主函数:程序的入口(必须有且仅有一个main函数)
int main() {
    // 语句:输出字符串,以分号结束
    printf("Hello, C Language!\n");  
    // 返回值:0表示程序正常结束
    return 0;  
}

核心说明:

  1. 预处理指令:以#开头,在编译前执行,常见的有#include(引入头文件)、#define(宏定义)、#ifdef(条件编译)等;
  2. 函数:C 程序的执行单元,main()是程序入口,格式为:返回值类型 函数名(参数列表) { 函数体 }
  3. 语句:每个可执行语句以;结尾,\n是换行符;
  4. 注释
    • 单行注释:// 注释内容(C99 标准支持);
    • 多行注释:/* 注释内容 */(不可嵌套)。

二、数据类型

C 语言数据类型分为基本类型、构造类型、指针类型、空类型 四类,基础阶段重点掌握基本类型:

类型分类具体类型关键字占用字节(32/64 位系统)取值范围示例
整型短整型short2-32768 ~ 32767
整型int4-2^31 ~ 2^31-1
长整型long4/8随系统,至少与 int 一致
无符号整型unsigned int40 ~ 2^32-1
浮点型单精度浮点型float4有效数字 6~7 位
双精度浮点型double8有效数字 15~16 位
字符型字符型char1-128 ~ 127(或 0~255,取决于编译器)

补充:

  • 字符型char本质是存储 ASCII 码(如'a'对应 97,'0'对应 48);
  • 浮点型默认是double,定义float需加后缀f(如float f = 3.14f;);
  • 空类型void:用于函数返回值(无返回值)、函数参数(无参数)、指针类型(void*)。

三、变量与常量

1. 变量

变量是程序运行中可修改的存储单元,定义格式:类型名 变量名 [= 初始值];

规则:

  • 变量名由字母、数字、下划线组成,不能以数字开头,区分大小写(如numNum是两个变量);
  • 不能使用 C 语言关键字(如intiffor等)作为变量名;
  • 变量必须先定义后使用,建议初始化(避免随机值)。

示例:

c

运行

#include <stdio.h>
int main() {
    // 整型变量,未初始化
    int age;  
    // 初始化
    age = 20;  
    // 字符变量,直接初始化
    char gender = 'M';  
    // 浮点变量
    float score = 95.5f;  
    printf("年龄:%d,性别:%c,分数:%.1f\n", age, gender, score);
    return 0;
}

2. 常量

常量是程序运行中不可修改的量,分为 4 类:

常量类型示例说明
字面常量100、3.14、’A’、”abc”直接书写的常量值
宏常量#define PI 3.14159预处理阶段替换,无类型检查
枚举常量enum {MON, TUE=2, WED};MON=0,TUE=2,WED=3(默认自增)
常变量const int num = 10;有类型检查,本质是 “只读变量”

示例:

c

运行

#include <stdio.h>
// 宏常量
#define PI 3.14159  
// 枚举常量
enum Week {MON, TUE, WED};  

int main() {
    // 常变量
    const int radius = 5;  
    // 字面常量
    float area = PI * radius * radius;  
    printf("圆面积:%.2f\n", area);
    printf("周二:%d\n", TUE); // 输出1
    return 0;
}

四、运算符

C 语言运算符按功能分为算术、赋值、关系、逻辑、位运算、三目 等,核心如下:

1. 算术运算符

运算符功能示例注意
+、-、*、/加减乘除10/3=3(整型除法取整)除数不能为 0;浮点数除法保留小数
%取模(求余)10%3=1仅适用于整型
++、–自增 / 自减a++(后增)、++a(前增)前增:先加 1 再使用;后增:先使用再加 1

示例:

c

运行

int a = 5;
// 先使用a=5,再a=6
printf("%d\n", a++);  
// 先a=7,再输出7
printf("%d\n", ++a);  

2. 赋值运算符

  • 基本赋值:=(如x = 10;);
  • 复合赋值:+=、-=、*=、/=、%=(如x += 5 等价于 x = x + 5)。

3. 关系运算符(返回 0/1,0 为假,非 0 为真)

运算符功能示例
>、<、>=、<=大于、小于、大于等于、小于等于5>3=1,5<=3=0
==等于5==5=1,5==3=0
!=不等于5!=3=1

4. 逻辑运算符(操作数为 0 / 非 0,返回 0/1)

运算符功能示例短路特性
&&逻辑与(5>3)&&(2<1)=0左假则右不执行
||逻辑或(5>3)||(2<1)=1左真则右不执行
!逻辑非!(5>3)=0

5. 三目运算符(条件运算符)

格式:条件 ? 表达式1 : 表达式2

规则:条件为真执行表达式 1,否则执行表达式 2。

示例:

c

运行

int a = 10, b = 20;
// max=20
int max = (a > b) ? a : b;  

6. 运算符优先级(核心)

从高到低:() > 单目(++、–、!) > 算术(*、/、% > +、-) > 关系 > 逻辑(&& > ||) > 三目 > 赋值。

建议:复杂表达式用()明确优先级,提升可读性。

五、流程控制

C 语言通过顺序、选择、循环 控制程序执行流程,核心是选择和循环。

1. 选择结构

(1)if 语句

格式:

c

运行

// 单分支
if (条件) { 语句块; }

// 双分支
if (条件) { 语句块1; }
else { 语句块2; }

// 多分支
if (条件1) { 语句块1; }
else if (条件2) { 语句块2; }
...
else { 语句块n; }

示例:

c

运行

int score = 85;
if (score >= 90) {
    printf("优秀\n");
} else if (score >= 80) {
    printf("良好\n");
} else {
    printf("及格\n");
}

(2)switch 语句

适用于 “多值匹配” 场景,格式:

c

运行

switch (表达式) {
    case 常量1: 语句块1; break;
    case 常量2: 语句块2; break;
    ...
    default: 语句块n; break;
}

注意:

  • 表达式必须是整型 / 字符型;
  • break用于跳出 switch,否则会 “穿透” 到下一个 case;
  • default可选,匹配不到 case 时执行。

示例:

c

运行

int day = 2;
switch (day) {
    case 1: printf("周一\n"); break;
    case 2: printf("周二\n"); break;
    default: printf("其他\n"); break;
}

2. 循环结构

(1)for 循环(适合已知循环次数)

格式:for (初始化表达式; 条件表达式; 更新表达式) { 循环体; }

执行流程:初始化 → 判断条件 → 执行循环体 → 更新 → 再判断…

示例(输出 1~5):

c

运行

for (int i = 1; i <= 5; i++) {
    printf("%d ", i);
}

(2)while 循环(适合未知循环次数)

格式:while (条件) { 循环体; }

执行流程:先判断条件,为真则执行循环体。

示例(计算 1~100 求和):

c

运行

int i = 1, sum = 0;
while (i <= 100) {
    sum += i;
    i++;
}
printf("sum = %d\n", sum);

(3)do-while 循环(至少执行一次循环体)

格式:do { 循环体; } while (条件);

执行流程:先执行循环体,再判断条件。

示例:

c

运行

int num;
do {
    printf("输入一个正数:");
    scanf("%d", &num);
} while (num <= 0);

(4)循环控制关键字

  • break:跳出当前循环(switch / 循环);
  • continue:跳过本次循环剩余语句,进入下一次循环;
  • goto:无条件跳转(不建议使用,易破坏结构)。

示例(break 跳出循环):

c

运行

for (int i = 1; i <= 5; i++) {
    if (i == 3) break;
    printf("%d ", i); // 输出1 2
}

六、函数

函数是 C 程序的基本模块,实现代码复用,核心要素:定义、声明、调用

1. 函数定义

格式:

c

运行

返回值类型 函数名(参数类型1 参数名1, 参数类型2 参数名2, ...) {
    // 函数体
    语句块;
    // 返回值(void类型无需return)
    return 返回值;  
}

示例(求两数最大值):

c

运行

// 定义函数
int max(int a, int b) {
    return (a > b) ? a : b;
}

2. 函数声明

如果函数定义在调用之后,需先声明(告诉编译器函数的 “接口”):

格式:返回值类型 函数名(参数类型1, 参数类型2, ...);

示例:

c

运行

#include <stdio.h>
// 函数声明
int max(int a, int b);  

int main() {
    // 函数调用
    int res = max(10, 20);  
    printf("最大值:%d\n", res);
    return 0;
}

// 函数定义
int max(int a, int b) {
    return (a > b) ? a : b;
}

3. 函数参数

  • 形参:函数定义时的参数(如max中的ab);
  • 实参:函数调用时传入的参数(如max(10,20)中的 10、20);
  • 传值调用:默认方式,形参是实参的拷贝,修改形参不影响实参;
  • 传址调用:通过指针传递,修改形参指向的内容会影响实参(后续指针部分详解)。

4. 主函数参数(扩展)

main函数支持参数传递(命令行参数),格式:

c

运行

int main(int argc, char *argv[]) {
    // argc:参数个数;argv:参数数组(argv[0]是程序名)
    printf("参数个数:%d\n", argc);
    for (int i = 0; i < argc; i++) {
        printf("argv[%d] = %s\n", i, argv[i]);
    }
    return 0;
}

七、数组(基础)

数组是相同类型数据的有序集合,分为一维数组和二维数组(基础阶段重点)。

1. 一维数组

(1)定义:类型名 数组名[数组长度];

(2)初始化:

c

运行

// 完全初始化
int arr[5] = {1,2,3,4,5};  
// 部分初始化(未初始化的元素为0)
int arr[5] = {1,2};  
// 省略长度(长度由初始化元素个数决定)
int arr[] = {1,2,3};  

(3)访问:数组名[下标](下标从 0 开始)

示例(遍历数组):

c

运行

#include <stdio.h>
int main() {
    int arr[5] = {10,20,30,40,50};
    // 遍历数组
    for (int i = 0; i < 5; i++) {
        printf("arr[%d] = %d\n", i, arr[i]);
    }
    return 0;
}

2. 二维数组

(1)定义:类型名 数组名[行长度][列长度];

(2)初始化:

c

运行

// 完全初始化
int arr[2][3] = {{1,2,3}, {4,5,6}};  
// 部分初始化(未初始化的元素为0)
int arr[2][3] = {{1}, {4}};  
// 省略行长度(列长度不能省)
int arr[][3] = {{1,2}, {3,4}};  

(3)访问:数组名[行下标][列下标]

示例(遍历二维数组):

c

运行

int arr[2][3] = {{1,2,3}, {4,5,6}};
for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 3; j++) {
        printf("%d ", arr[i][j]);
    }
    printf("\n");
}

八、指针(基础)

指针是 C 语言的核心特性,本质是存储内存地址的变量

1. 指针的定义与基本使用

格式:类型名 *指针变量名;

  • &:取地址符(获取变量的内存地址);
  • *:解引用符(通过地址访问变量的值)。

示例:

c

运行

#include <stdio.h>
int main() {
    int a = 10;
    // 定义指针变量p,存储a的地址
    int *p = &a;  
    // 输出a的地址(如0x7ffeefbff5c4)
    printf("a的地址:%p\n", &a);  
    // 输出p的值(与a的地址相同)
    printf("p的值:%p\n", p);  
    // 解引用:输出a的值(10)
    printf("*p的值:%d\n", *p);  
    // 修改a的值为20
    *p = 20;  
    printf("a的值:%d\n", a); // 输出20
    return 0;
}

2. 指针与数组

数组名本质是数组首元素的地址(常量,不可修改),因此可通过指针访问数组:

c

运行

int arr[5] = {1,2,3,4,5};
// p指向数组首元素
int *p = arr;  
for (int i = 0; i < 5; i++) {
    // 等价于arr[i]
    printf("%d ", *(p + i));  
}

九、常见语法注意事项

  1. 分号问题:语句必须以;结尾,if/for/while的条件后不要多加分号(否则循环体为空);
  2. 变量作用域:局部变量(函数 / 块内定义)仅在作用域内有效,全局变量(函数外定义)整个程序有效;
  3. 类型匹配:赋值、函数参数传递时需保证类型匹配,避免隐式转换导致错误;
  4. 数组越界:访问数组时下标不能超出范围,否则会导致内存越界(程序崩溃);
  5. 指针空值:定义指针时建议初始化为NULL(空指针),避免野指针。

总结

C 语言基础语法的核心是 “结构化”:通过变量 / 常量存储数据,运算符处理数据,流程控制组织执行逻辑,函数实现代码复用,数组 / 指针处理批量数据。掌握以上内容后,可进一步学习指针进阶、结构体、文件操作等内容,逐步构建完整的 C 语言知识体系。建议结合实例多写多练,通过调试理解语法细节,是掌握 C 语言的关键。