news 2026/6/3 15:38:16

C语言基础入门到进阶:变量、函数、指针与内存管理一文讲透

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C语言基础入门到进阶:变量、函数、指针与内存管理一文讲透

本文是一篇面向零基础读者的 C 语言基础入门教程,系统讲解 C 语言开发环境、编译运行、变量与数据类型、分支循环、函数、数组、字符串、指针和动态内存管理。文章以“概念 + 可运行代码 + 常见错误 + 完整小项目”的方式组织,适合初学者从 0 开始建立 C 语言基础。


0. 学习目标:先知道学完能干什么

学完本文,你应该能做到:

  1. 写出并运行 C 程序

  2. 用分支和循环处理逻辑

  3. 用函数拆分代码

  4. 用数组和字符串处理数据

  5. 理解指针的基本含义

  6. 使用malloc/free管理动态内存

  7. 独立完成一个“成绩统计器”小程序


1. 开发环境与运行方式

Windows

推荐安装:

  • MSYS2 + gcc

  • 或 MinGW-w64

安装后打开终端,输入:

gcc --version

如果能看到版本号,说明编译器可用。

macOS

安装 Xcode Command Line Tools:

xcode-select --install

验证:

gcc --version

macOS 上gcc通常会映射到clang,能正常编译 C 程序即可。

Linux(Ubuntu)

sudo apt update sudo apt install build-essential gcc --version

编译与运行

假设文件名是main.c

gcc main.c -o main ./main

Windows 下可能生成main.exe,可以运行:

main.exe

常见问题:

  • gcc: command not found:没有安装编译器,或环境变量没配置好

  • 找不到文件:终端当前目录不是源码所在目录


2. 第一个 C 程序:先跑起来

#include <stdio.h> int main(void) { printf("Hello, C!\n"); return 0; }

先理解三件事:

  • main是程序入口

  • printf负责输出

  • return 0表示程序正常结束

头文件是什么?

你会经常看到这样的代码:

#include <stdio.h> #include <stdlib.h> #include <string.h>

可以先简单理解为:头文件是在告诉编译器,我接下来要使用哪些现成的函数或类型

常见头文件:

头文件常见用途
stdio.h输入输出,如printfscanffgets
stdlib.h动态内存、程序退出,如mallocfreeexit
string.h字符串处理,如strlenstrcspnstrcmp
stdbool.h布尔类型,如booltruefalse

刚入门不用背全部,先知道:用某个库函数前,通常要包含对应头文件

常见错误:

  • 忘记分号;

  • printf写错

  • 忘记包含stdio.h


3. 变量、常量、基本数据类型

变量可以理解为:给一块内存起名字
数据类型决定这块内存能放什么值。

#include <stdio.h> #include <stdbool.h> int main(void) { int age = 18; double score = 95.5; char grade = 'A'; bool passed = true; const double PI = 3.14159; printf("age=%d\n", age); printf("score=%.1f\n", score); printf("grade=%c\n", grade); printf("passed=%d\n", passed); printf("PI=%.5f\n", PI); return 0; }

C 语言常见基本数据类型

类型含义常见格式符示例
char字符/小整数%cchar c = 'A';
short短整型%hdshort s = 10;
int整型,最常用%dint age = 18;
long长整型%ldlong n = 1000L;
long long更长的整型%lldlong long big = 100000LL;
float单精度小数%ffloat f = 3.14f;
double双精度小数,常用printf%fscanf%lfdouble d = 3.14;
_Bool/bool布尔值%dbool ok = true;

signed 和 unsigned

整数类型还可以分为有符号和无符号:

int a = -10; // 可以表示负数 unsigned int b = 10; // 只表示非负数

注意:unsigned不适合随便用来“防止负数”。它参与运算时可能产生不直观的结果。初学阶段,大多数普通整数先用int即可。

sizeof:查看类型占多少字节

不同平台上类型大小可能不同,可以用sizeof查看:

#include <stdio.h> int main(void) { printf("char: %zu\n", sizeof(char)); printf("int: %zu\n", sizeof(int)); printf("long: %zu\n", sizeof(long)); printf("double: %zu\n", sizeof(double)); return 0; }

sizeof的结果类型是size_t,打印时用%zu

常见错误:

  • 单个字符用单引号:'A'

  • 字符串用双引号:"A"

  • 小数默认是double,写float f = 3.14f;更规范

  • 不要假设int永远是 4 字节,具体大小和平台有关


4. 运算符与判断

#include <stdio.h> int main(void) { int a = 10, b = 3; printf("a+b=%d\n", a + b); printf("a-b=%d\n", a - b); printf("a*b=%d\n", a * b); printf("a/b=%d\n", a / b); printf("a%%b=%d\n", a % b); if (a == b) { printf("equal\n"); } else { printf("not equal\n"); } return 0; }

几个必须分清的符号:

  • =:赋值

  • ==:比较是否相等

  • %:取余

  • &&:并且

  • ||:或者

  • !:取反

常见错误:

if (a = b) { // 错误:这是赋值,不是比较 }

应该写成:

if (a == b) { // 正确:比较是否相等 }

5. 分支与循环

if-else

#include <stdio.h> int main(void) { int score = 78; if (score >= 90) { printf("优秀\n"); } else if (score >= 60) { printf("及格\n"); } else { printf("不及格\n"); } return 0; }

for 循环

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

while 循环

int n = 3; while (n > 0) { printf("n=%d\n", n); n--; }

switch

char grade = 'A'; switch (grade) { case 'A': printf("优秀\n"); break; case 'B': printf("良好\n"); break; default: printf("继续努力\n"); break; }

常见错误:

  • while忘记更新条件,导致死循环

  • switch忘记break,导致继续执行下一个case


6. 函数:代码不再全堆在 main 里

#include <stdio.h> int add(int x, int y) { return x + y; } int main(void) { int result = add(3, 5); printf("result=%d\n", result); return 0; }

函数的好处:

  • 复用逻辑

  • 降低复杂度

  • 更容易调试

  • 让代码结构更清晰

常见错误:

  • 函数有返回值,却忘记return

  • 参数类型和返回值类型写混

  • 函数调用时参数数量不对


7. 输入:scanf 的基础用法

scanf可以从键盘读取输入:

#include <stdio.h> int main(void) { int age; printf("请输入年龄: "); scanf("%d", &age); printf("你的年龄是: %d\n", age); return 0; }

注意这里是&age,不是age

原因是:scanf需要把输入结果写回变量,所以要传入变量的地址。

常见写法:

int n; double score; char ch; scanf("%d", &n); scanf("%lf", &score); scanf(" %c", &ch); // 前面的空格用于跳过换行或空白字符

不过,scanf处理字符串和非法输入时比较容易踩坑。入门阶段可以先用它读数字;读一整行字符串时,更推荐fgets


8. 数组与字符串

8.1 数组

数组用来保存一组相同类型的数据:

#include <stdio.h> int main(void) { int nums[5] = {10, 20, 30, 40, 50}; int sum = 0; for (int i = 0; i < 5; i++) { sum += nums[i]; } printf("sum=%d\n", sum); return 0; }

注意:数组下标从0开始。
nums[0]是第一个元素,nums[4]是第五个元素。

常见错误:

int nums[5]; nums[5] = 100; // 错误:越界

8.2 字符串

C 语言里的字符串,本质是以'\0'结尾的字符数组。

char name[20] = "Tom";

字符串输入推荐使用fgets

#include <stdio.h> #include <string.h> int main(void) { char name[20]; printf("请输入名字: "); if (fgets(name, sizeof(name), stdin) != NULL) { name[strcspn(name, "\n")] = '\0'; // 去掉换行 printf("你好,%s\n", name); } return 0; }

为什么不推荐gets

因为gets不知道数组有多大,容易写越界,已经不应再使用。

常见错误:

  • 字符串数组空间不够

  • 忘记字符串结尾的'\0'

  • ==比较字符串内容

字符串内容比较要用strcmp

#include <string.h> if (strcmp(name, "Tom") == 0) { printf("same\n"); }

9. 指针入门:理解地址与解引用

#include <stdio.h> int main(void) { int num = 100; int *p = &num; printf("num=%d\n", num); printf("address of num=%p\n", (void*)&num); printf("p=%p\n", (void*)p); printf("*p=%d\n", *p); *p = 200; printf("num after *p=200 => %d\n", num); return 0; }

理解三者关系:

  • num:变量本身,里面存的是值

  • &num:变量的地址

  • p:保存地址的变量,也就是指针

  • *p:取出这个地址里存放的值

一句话记忆:

  • &:取地址

  • *p:解引用,取地址里的值

这一节只要求你先理解三件事:地址、指针变量、解引用
二级指针、函数指针、复杂声明可以后面再学,不要一开始就把自己绕进去。

常见错误:

int *p; *p = 10; // 危险:p 没有指向有效地址

指针使用前,必须先指向一个有效对象,或者明确赋值为NULL


10. 动态内存:运行时申请空间

有时候数组长度在程序运行时才知道,这时可以用动态内存。

#include <stdio.h> #include <stdlib.h> int main(void) { int n = 5; int *arr = malloc(n * sizeof *arr); if (arr == NULL) { printf("内存申请失败\n"); return 1; } for (int i = 0; i < n; i++) { arr[i] = i * 10; } for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } printf("\n"); free(arr); arr = NULL; return 0; }

这里使用了:

int *arr = malloc(n * sizeof *arr);

它的好处是:如果以后arr的类型改了,sizeof *arr会自动跟着变,不容易因为手写sizeof(int)而出错。

你也可能看到这种写法:

int *arr = malloc(n * sizeof(int));

它也能用,但前一种更不容易写错。

动态内存黄金法则:

  • malloc后要判断是否为NULL

  • malloc就要有free

  • free后不要继续使用旧指针

  • 谁申请,谁负责释放


11. 完整实战:成绩统计器

需求:

  • 输入 5 个成绩

  • 输出平均分

  • 输出最高分和最低分

  • 对输入做基本校验

#include <stdio.h> #define N 5 double calc_avg(const int arr[], int n) { int sum = 0; for (int i = 0; i < n; i++) { sum += arr[i]; } return (double)sum / n; } int calc_max(const int arr[], int n) { int max = arr[0]; for (int i = 1; i < n; i++) { if (arr[i] > max) { max = arr[i]; } } return max; } int calc_min(const int arr[], int n) { int min = arr[0]; for (int i = 1; i < n; i++) { if (arr[i] < min) { min = arr[i]; } } return min; } int main(void) { int scores[N]; printf("请输入%d个成绩(0-100):\n", N); for (int i = 0; i < N; i++) { while (1) { printf("score[%d] = ", i); if (scanf("%d", &scores[i]) != 1) { while (getchar() != '\n') { // 清理非法输入 } printf("输入无效,请输入整数。\n"); continue; } if (scores[i] < 0 || scores[i] > 100) { printf("范围应在0~100,请重新输入。\n"); continue; } break; } } double avg = calc_avg(scores, N); int max = calc_max(scores, N); int min = calc_min(scores, N); printf("\n平均分:%.2f\n", avg); printf("最高分:%d\n", max); printf("最低分:%d\n", min); return 0; }

这个小程序已经包含了:

  • 输入

  • 校验

  • 数组

  • 循环

  • 函数

  • 计算

  • 输出

这就是一个完整的基础 C 程序闭环。


12. 常见报错与排查

1.expected ';'

通常是上一行漏了分号。

2.undefined reference to ...

可能是:

  • 函数声明了但没有实现

  • 编译多个.c文件时漏了某个源文件

3.Segmentation fault

常见原因:

  • 指针没有初始化

  • 数组越界

  • 访问了已经释放的内存

4. 程序结果不对

建议先检查:

  1. 输入是否符合预期

  2. 循环边界是否正确

  3. 数组下标是否越界

  4. 变量是否初始化


13. 练习题

建议你一定要动手写。

  1. 输入一个整数n,输出1~n的和

  2. 写函数判断一个数是否为素数

  3. 输入一行字符串,统计其中字母个数

  4. 用数组实现“找第二大值”

  5. 用动态内存创建长度为n的数组并求平均值

练习是从“看懂”到“会用”的唯一捷径。


14. 学到这里,你应该会什么

如果你现在能做到下面几点,就算完成了 C 语言的入门到基础阶段:

  • 能写完整main程序并编译运行

  • 能用变量、分支、循环表达基本逻辑

  • 能用函数拆分代码

  • 能用数组和字符串处理数据

  • 能理解指针的地址和解引用

  • 能使用malloc/free做简单动态内存管理

  • 能定位常见编译错误和运行错误

下一步可以继续学习:

  • 结构体

  • 文件读写

  • 枚举

  • 多文件编译

  • 链表、栈、队列等数据结构

C 语言真正的学习方式不是背概念,而是不断写小程序、改错误、看输出。只要你坚持把每个示例都手敲一遍,基础会越来越稳。

相关推荐

C语言基础知识(一)-字节、变量、常量、数据类型以及进制-CSDN博客文章浏览阅读8.5k次,点赞16次,收藏70次。本文深入浅出地介绍了C语言的基础概念,包括字节、位、数据类型、变量、常量等核心内容,并详细讲解了不同进制之间的转换及应用。https://shuaici.blog.csdn.net/article/details/118601915C语言基础知识(二)-输入、输出以及运算符-CSDN博客文章浏览阅读1.2w次,点赞8次,收藏53次。本文详细介绍了C语言中的输入输出函数,包括printf和scanf的使用方法,以及各种格式控制符和标志字符。同时,文章还探讨了算术、关系、逻辑和位运算符,以及赋值运算符和杂项运算符的应用。通过实例代码加深了对这些概念的理解。https://shuaici.blog.csdn.net/article/details/118798852

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/3 15:38:13

自己动手丰衣足食-自己动手修改GBA ROM游戏文件

经过一天的努力终于琢磨出怎么修改GBA的游戏文件也就是俗称的ROM文件&#xff0c;起因是因为偶然看到二手GBM&#xff0c;顿时抑制不住买了一台&#xff0c;可惜买得晚了&#xff0c;完美运行游戏又带金手指功能的烧录卡买不到了。SUPERCARD烧录卡看评论说费电&#xff0c;玩游…

作者头像 李华
网站建设 2026/6/3 15:30:06

凭什么数字攻防岗年薪普遍 60 万?300 万人才空缺,2025 转行优选

当下的数字世界暗流汹涌&#xff0c;“勒索攻击”、“数据泄露”的新闻标题&#xff0c;一次次冲击着企业与个人的神经。 打开新闻或行业论坛&#xff0c;充斥的是企业遭遇攻击后的损失通报&#xff0c;是安全团队彻夜奋战的疲惫身影&#xff0c;是个人隐私泄露后的无奈与愤怒…

作者头像 李华