Git与C语言入门实战:从版本控制到编译运行的全流程指南
Git和C语言这两个词对刚踏进计算机圈子的人来说分量都很重。一个是被无数开发者当作“代码后悔药”的版本管理工具一个是号称“编程之根”的系统级语言。最近常有学生私信我一边在跟翁恺老师的C语言课一边被老师要求用Git交作业两样东西都是零基础完全不知道从哪下手。也有人问得更具体——单片机里的C语言到底有没有堆栈VS Code里怎么才能跑通一个C程序Git提交错了怎么改这些问题其实都指向同一个需求把Git和C语言这两样基本功从“听说过”变成“真会用”。这篇文章我就把这两块内容放在一起讲透从安装配置到日常操作从语言特性到项目实战尽量把新手容易卡住的点都照顾到。适合完全没有经验的小白也适合那些写过几段C代码、但一直没搞明白Git工作流的半新手。1. 为什么非要把Git和C语言放在一起学1.1 一个是协作的“轨道”一个是底层开发的“发动机”先想明白一个事情Git和C语言本质上是完全不同的两样东西但它们在实际开发中恰恰是“配套使用”的关系。Git管的是代码的“过程”——谁改了什么、什么时候改的、改错了能不能回到上一版C语言管的是代码的“本质”——怎么让机器真正干活直接控制内存、寄存器、硬件接口。很多高校的数据结构、操作系统、嵌入式课程实验代码基本都是C语言而提交实验报告和源码时又普遍要求走Git流程。所以你会发现这两个东西几乎是同时出现在一个初学者面前的。我经常用一个类比来解释Git它就像游戏里的存档系统。单机游戏打Boss之前你一定会存个档因为你知道可能会死死了还能读档重来。写C语言程序也是一样改一个功能之前先提交一次万一改崩了一条命令就能回到能跑的版本。没有人愿意面对“代码改坏了但回不去了”的尴尬而Git就是专门解决这种问题的。1.2 组合学习能帮你避开“教室与职场脱节”的坑还有一个现实问题很多人在学校写代码写完了往U盘一存、或者微信传给自己就算完事。但真实项目中哪怕是几个人协作一个几千行的作业项目没有版本管理都寸步难行。更别说现在的简历上“熟悉Git”几乎和“熟悉C语言”一样是硬通货。我在带实习生的时候观察到一个规律C语言学得还行、但完全不会用Git的同学进团队头两周基本都在补“怎么交代码”这一课。所以把这两个东西组合起来学等于一次搞定两个基础能力。C语言给你驾驭底层的能力Git给你安全迭代和团队协作的能力。前者让你“能写”后者让你“敢改”。这篇博文想达到的效果是你看完之后能自己装好Git、配好仓库、完成一次从本地到远程的提交流程同时能在自己的电脑上搭好C语言环境写出并运行第一个、第二个、第三个小程序。2. 先认识Git版本控制到底在干嘛2.1 没有Git的时候代码是怎么“烂”在磁盘里的我先描述一个很多新手都经历过的场景课程作业交了三版文件夹里躺着大作业.c、大作业最终版.c、大作业最终版2.c、大作业谁也别想动版.c……最后你自己都分不清哪个是最新版本。更惨的是你把代码改错了想回到上一版结果上一版已经被覆盖了一个字都找不回来。Git解决的就是这一堆问题。它记录每次提交的快照你可以随时查看历史、对比差异、回滚版本。多人合作时它还能让每个人在自己的分支上并行开发最后再把大家的成果合并到一起。这个过程听起来复杂但日常真正高频用到的命令其实不超过十个后面我会逐条演示。2.2 三个核心概念工作区、暂存区、仓库理解Git的关键在三个区域。第一个是工作区working directory就是你电脑上直接看到的那个文件夹文件在这里被编辑和修改。第二个是暂存区staging area / index通俗讲是“准备提交的草稿区”你把想要提交的文件git add进来相当于告诉Git“这些文件我改完了做好准备要存档了”。第三个是仓库repository就是.git这个隐藏目录保存着每一次正式的提交记录相当于游戏的存档本体。这三个区域的关系可以用一个生活类比工作区是你的桌面暂存区是抽屉仓库是保险箱。你在桌面上写文件写完把重要的放进抽屉到了晚上再把抽屉里所有东西一起锁进保险箱。每次锁进保险箱的动作就是一次git commit。摆弄过一遍之后你会发现这个模型比死记命令有用得多。2.3 第一次动手用5个命令走完一次完整提交光说不练没用。我们假设你已经装好了Git安装方法下一章细讲打开终端或者Git Bash进入一个空目录然后按顺序执行git init这会在当前目录初始化一个仓库生成一个隐藏的.git文件夹。接下来创建一个文件比如写一个最简单的C程序echo int main() { return 0; } hello.c git status执行git status你会看到类似输出提示hello.c处于“未跟踪”状态。这说明Git已经看到这个文件但还没纳入版本管理。然后git add hello.c git commit -m first commit: add hello.cgit add把文件放进暂存区git commit生成一个正式存档。再用git log看一下git log --oneline你会看到一条提交记录带着一个由40位十六进制字符缩短而成的提交ID。从这一刻起这个文件的所有后续变化都会在Git的掌控之中。建议你照着敲一遍这个过程比读十篇文章都管用。3. Git安装与配置从“装好”到“真正能用”3.1 三个平台的安装方案Git的安装本身不难但细节决定成败。Windows去Git官网git-scm.com下载安装包一路Next即可。有几个选项要留意一下安装路径建议不要放在C盘系统分区深处避免权限问题“Adjusting your PATH environment”选项保持默认的“Git from the command line and also from 3rd-party software”这样在CMD和PowerShell里也能直接用git命令“Checkout as-is, commit Unix-style line endings”建议保持默认或选core.autocrlftrue对新手来说默认值最省心。macOS推荐用Homebrew安装brew install git装完直接可用。也可以装Xcode自带Git但版本通常会旧一些。LinuxDebian/Ubuntu系sudo apt update sudo apt install git一条命令结束。我个人的建议是Windows用户装完Git后平时练习尽量用Git Bash而不是CMD。因为Git Bash模拟了类Unix终端环境很多命令行为和教程里写的最一致后面学起来不会因为终端差异产生困惑。我自己当年在Windows上踩过坑——同一个命令在CMD里对着教程怎么敲都不对换了Git Bash立刻就好了。3.2 装完以后一定要做的四件事装完之后第一件事不是急着建仓库而是先把“你是谁”告诉Git。因为每一次提交都会记录作者信息不配置的话后面提交会报错或者显示一堆乱码。git config --global user.name Your Name git config --global user.email youexample.com这里的--global表示全局生效配一次就行。接着建议配置换行符和中文显示git config --global core.autocrlf true git config --global core.quotepath false第二个参数core.quotepath false尤其重要。它可以让Git在输出状态信息时正常显示中文文件名而不是显示一堆\344\273\243之类的转义字符。很多人在Windows上看到中文文件名变成乱码就是这个参数没开。最后可以顺手开个颜色显示git config --global color.ui true配置完之后可以用git config --list查看所有配置确认自己的设置生效。这些配置对应保存在用户目录下的.gitconfig文件里你也可以直接用文本编辑器打开看。3.3 连接远程仓库Gitee/GitHub的SSH密钥配置本地仓库用明白了下一步就是和远程仓库比如学校常用的Gitee、国际上用的GitHub对接。先解决免密登录的问题——SSH密钥。打开终端执行ssh-keygen -t ed25519 -C youexample.com一路回车生成密钥对。然后查看公钥cat ~/.ssh/id_ed25519.pub把输出的整段内容复制去Gitee/GitHub的“设置-安全设置-SSH公钥”页面粘贴保存。验证是否连通以Gitee为例ssh -T gitgitee.com看到欢迎信息就说明通了。接下来给本地仓库添加远程地址并推送git remote add origin gitgitee.com:你的用户名/仓库名.git git branch -M main git push -u origin main以后每次推送就是git push拉取就是git pull不再需要输密码。很多新手在配置这一步时容易卡在“Permission denied (publickey)”多半是公钥复制漏了字符或者用的是HTTPS地址而不是SSH地址。这里建议把远程地址用成git开头的SSH格式而不是https://开头的格式否则即使配置了密钥也要输密码。还有一点值得说如果你用过GitHub Desktop可能注意到它在执行操作时会输出一串很长的命令类似git -c diff.mnemonicprefixfalse -c core.quotepathfalse --no-optional-locks ...。这串东西其实就是GUI工具在调用底层Git命令时附加的参数开关。-c diff.mnemonicprefixfalse表示比较差异时不显示a/、b/这类前后缀便于界面阅读-c core.quotepathfalse就是刚才说的中文转义问题--no-optional-locks是防止工具在运行自己逻辑时给仓库加不必要的锁。看到这种命令不用慌它不是奇怪的病毒只是配置参数以命令行形式显式写出来了而已。4. Git命令实操高频命令与进阶技巧4.1 日常开发最常用的命令清单我把日常开发超过九成操作会碰到的命令整理成了表格供你随时查阅。记住这些已经可以撑起基本工作流。命令作用常用参数git init在当前目录初始化仓库git status查看工作区/暂存区状态-s精简显示git add把文件加入暂存区.表示全部git commit提交一份快照-m 说明-a跳过暂存直接提交已跟踪文件git log查看提交历史--oneline--graphgit diff查看工作区与暂存区的差异--staged查看已暂存差异git checkout切换分支/恢复文件-- filename丢弃工作区改动git branch查看/创建分支-b在git checkout里创建并切换git merge合并分支git push推送本地提交到远程-u设置上游git pull拉取远程更新并合并有个习惯值得从一开始就养成每次git commit之前先跑一遍git status看清楚到底哪些文件进了暂存区。我见过太多人一个顺手git add .把莫名其妙的临时文件、编译产物一股脑提交进去了最后仓库里堆了一堆不需要的垃圾.git目录越来越大。4.2 提交已经发出去还能改吗git commit --amend很多新手问git commit --amend怎么用。这个命令的作用是“修改最近一次提交”适合两种场景一是提交说明写错了想改二是漏改了一个文件想把它并进上一次提交而不是再开一个“fix typo”的提交。用法很简单git commit --amend如果只是想改提交信息git commit --amend -m 新的提交说明一步到位。如果想补漏git add 忘记提交的文件.c git commit --amend --no-edit--no-edit表示保持原来的提交信息不变。执行完之后你会发现上一次提交的ID变了因为它本质上是用一个新的提交替掉了旧的提交而不是“修改”。这里有一个重要提醒--amend只适用于还没有推送到远程的提交。如果这个提交已经git push出去了就别再随意amend了否则会制造出本地与远程历史不一致的局面后面再用git pull会非常痛苦。4.3 分支合并merge和rebase怎么选分支是Git最强大的功能之一但也是新手最容易绕晕的地方。我用一个比喻main主分支是一条主干道你开了一条dev分支相当于在路旁修了一条辅路辅路走通了再并回主干道这个“并回”的动作就是git merge dev。实际操作git checkout -b dev # 在dev分支上做修改并提交 git checkout main git merge dev合并过程中如果两边改了同一个文件的同一行Git会提示冲突。这时候打开文件你会看到类似 HEAD、、 dev的标记手动决定保留哪部分、删掉哪部分保存后再git add并git commit即可。那rebase呢它也做合并但会把当前分支的提交“重新敷设”到目标分支的顶端让历史变成一条直线。好处是日志干净坏处是改变了提交时间线同样不适合用来处理已推送的公共分支。我的经验是本地还没推送的杂毛提交用rebase整理多人共享的分支老老实实用merge。新手阶段先把merge用熟就够了rebase以后用到再深究。4.4 一个让无数新手崩溃的报错fatal: not a git repositoryfatal: not a git repository (or any of the parent directories): .git这大概是Git新手遇到频率最高的报错之一。它翻译成大白话就是Git在当前目录以及所有上级目录里都找不到.git文件夹所以你知道这不是一个“仓库”的范围内。原因通常有三种一是在一个没有执行过git init的普通目录里直接敲git commit或git log二是你在仓库的某个角落但当前路径根本不在仓库之内三是你把自己的代码放在一个从别人那儿拷贝的文件夹里但拷的时候没把隐藏的.git目录一起拷过去。排查思路很简单先执行ls -a看看有没有.git目录没有就先git init或者cd回仓库根目录再操作。这个报错虽然吓人但解决起来其实极其容易。5. 重新认识C语言半个世纪了为什么还是“顶流”5.1 C语言到底解决什么问题C语言诞生已经五十多年今天依然活跃在操作系统内核、嵌入式系统、游戏引擎、数据库底层这些“性能敏感”的领域。它不像Python那样写起来轻松但它的价值在于接近硬件——你可以直接操作内存地址、通过指针访问寄存器、用位运算控制硬件状态。这也就是为什么单片机的开发、Linux内核的编写、虚拟存储器管理之类的课程设计全都离不开C语言。新手常常有一个误区觉得C语言太老、太原始学了没用。实际上恰恰相反C的你理解越深越能明白高级语言里那些“自动完成”的事情背后发生了什么。比如Python里一个简单的列表操作底层可能就是C语言在管理内存Java的垃圾回收机制本质上是把C语言里需要手工完成的内存释放工作自动化了。把C学扎实相当于把地基打牢学其他语言都能事半功倍。5.2 从源代码到可执行程序编译四步走在C语言的世界里.c源文件不是直接就能运行的。它要经过“预处理 → 编译 → 汇编 → 链接”四个阶段最终变成机器能执行的文件。平时我们用一条命令完成这一切gcc hello.c -o hellogcc被称为“编译器驱动”它会自动完成整个流水线。这里解释这个流程不是为了应付概念题而是为了让你在遇到问题的时候有排查思路。比如最常见的“未定义的引用undefined reference to xxx”十有八九是链接阶段出了问题——你声明了某个函数但实现它的文件没参与编译或者库没链接上。如果还想看得更细可以用参数分步执行gcc -E hello.c -o hello.i # 只看预处理后的结果 gcc -S hello.c -o hello.s # 生成汇编代码 gcc -c hello.c -o hello.o # 生成目标文件不链接拆开看一圈你就能更清楚地理解编译器每步在做什么。我对学生常说别怕编译输出的一堆英文那其实是编译器在帮你做“代码体检”每一条warning和error都有明确指向养成逐条读报错的习惯比任何奇技淫巧都重要。5.3 变量、数据类型与输入输出几个容易踩的语法坑C语言的基本语法不复杂但有几个点新手几乎必踩。第一个是数据类型和格式化输出的匹配。int对应%dfloat对应%fchar对应%c。写错不会报编译错误但输出的值会莫名其妙。尤其是float在printf时如果用了%d哪怕你刚给这个变量赋过值3.14也可能输出一个天文数字原因是参数传递时浮点数和整数在寄存器里的存储方式不同printf取到的位模式被强制解读成整数了。这个坑我记得特别深当年在OJ上调试半天最后发现是%d和%f写反了。第二个是scanf的地址符。初学者最容易漏掉变量前面的比如int num; scanf(%d, num); // 错误应该写 numscanf需要的是一个“地址”num才是取出变量在内存中的地址。漏了程序大概率直接崩溃。有一个热搜问题问“用%d输入一个字符后的值是多少”其实就是格式控制符和变量类型不匹配带来的未定义行为。比如char c; scanf(%d, c);%d告诉scanf“你要读一个整数并把结果写到对应地址”但c只有一个字节而整数占四个字节写入时会把相邻内存也覆盖掉。这种错误编译器不会报警告运行时也不一定立刻崩但数据已经被破坏了。所以正确的做法是让格式控制符和变量类型严格对应读char就用%c读整数就用%d。6. 搭一个能跑的C语言开发环境VS Code配置实战6.1 编译器选哪个MinGW、GCC还是Clang写C语言编辑器可以选很多种但“编译器”是绕不开的。Windows平台比较推荐MinGW-w64它是一套Windows上可用的GCC工具链Linux原生自带或apt安装的gccmacOS则建议直接用系统自带的clang。很多新手纠结VS Code和CLion选哪个我的观点是如果你还在学习阶段VS Code完全够用而且让你更容易理解“编译”和“运行”是怎么发生的CLion更智能但对机器配置要求高也容易让人忽略底层细节。检查编译器是否装好在终端输入gcc --version如果输出一串版本信息说明已可用。如果提示“不是内部或外部命令”说明GCC不在PATH环境变量里或者还没安装。Windows下安装MinGW后建议把MinGW/bin目录的完整路径加到系统环境变量的Path里然后重开终端生效。6.2 VS Code里写C语言的最小配置VS Code本身只是一个编辑器装好C/C扩展后它也只负责“高亮、提示、跳转”真正编译运行还得依赖系统里的编译器。新建一个.c文件写一个测试程序然后可以按以下方式之一运行。如果装了Code Runner扩展那么右键选择“Run Code”就能直接看到输出。它其实是自动帮你执行了cd到文件目录并调用gcc编译运行的命令适合快速跑通小代码做练习。但要注意Code Runner的默认终端可能不支持交互输入涉及scanf的程序运行时无法正常输入。这时候必须改用终端方式。更正规的方式是配置编译任务。按下CtrlShiftP打开命令面板搜索“Tasks: Configure Default Build Task”选择“C/C: gcc.exe build active file”VS Code会自动生成一个tasks.json定义编译命令类似{ tasks: [ { type: cppbuild, command: gcc, args: [-fdiagnostics-coloralways, -g, ${file}, -o, ${fileDirname}/${fileBasenameNoExtension}.exe], problemMatcher: [$gcc], group: build } ] }配置好之后按CtrlShiftB执行编译再在终端里手动运行生成的.exe。这套方案比Code Runner麻烦一点但能同时看到编译和运行两个阶段长期学习更推荐用这种方式。6.3 命令行直接编译掌握最朴素的运行方式就算配置了VS Code我依然强烈建议你熟悉命令行的编译流程。它最透明、最不容易出意外gcc test.c -o test -Wall ./test-o test是让编译器把输出文件命名为test-Wall是打开所有常用警告。我建议永远带着-Wall编译它会在你写出潜在问题时给出提示。比如变量未赋值就使用、函数声明和定义不一致编译器都会用警告的方式提醒你。很多人写C代码不重视警告觉得“能跑就行”但实际开发中警告往往就是 bug 的头一个信号。如果你跟着教程用VS Code运行C语言代码总是不成功先回到命令行试一次。命令行里能跑通说明是编辑器配置问题命令行里也报错说明是代码或编译器问题。这个排查顺序能帮你快速分清问题出在哪个环节。7. C语言语法进阶指针、字符串、结构体与堆栈7.1 指针别怕它就是门牌号指针是C语言里劝退最多人的概念但捅破窗户纸之后就非常简单。聊到指针我熟悉的画面是你把一个快递地址写在纸上快递员按纸上的地址找到你的门。指针变量就是这么一张纸它存的不是数据本身而是数据所在内存的“门牌号”。int num 42; int *p num; // p 存的是 num 的地址 printf(%d\n, *p); // *p 通过地址访问 num输出 42是取址运算符*在声明中是“我是一个指针类型”在表达式中是“按地址取值”。新手最先要分清的是这两件事。指针的核心价值在于函数传参默认是值传递你没法通过函数修改外部的变量但传指针进去就可以通过地址修改那个位置的数据。类似void add_one(int *x) { (*x); } int main() { int a 1; add_one(a); printf(%d\n, a); // 输出 2 }指针最常见的错误是“野指针”——声明了一个指针变量但没有赋初值就直接对它解引用。这就像一个地址乱写的快递单送达的地方自己都不知道是哪里程序轻则读到垃圾值重则直接段错误崩溃。所以务必养成习惯指针声明时给初值或者置为NULL使用前务必确认它指向的是有效内存。7.2 字符串处理为什么推荐用fgets而不是scanfC语言里没有真正的字符串类型所谓字符串就是一个以\0结尾的char数组。这也是很多初学阶段的bug来源数组开小了或者忘了留结束符的位置。输入字符串时很多教程第一反应是教你用scanf(%s, str)但这个函数有两个毛病一是遇到空格就停止读不了带空格的句子二是它不检查数组长度输入超长时直接把内存写穿。更稳的做法是用fgetschar line[100]; fgets(line, sizeof(line), stdin);fgets会限制最多读取sizeof(line)-1个字符避免越界写而且能读取空格。它把换行符也可能读进来所以有时候需要自己去尾部的\nline[strcspn(line, \n)] \0;一行解决。字符串相关的练习题——比如PTA上的字符串逆序、按空格分割单词——本质上玩的就是数组下标和\0位置的处理。把这些基本功练熟往后写什么字符串处理都不慌。7.3 结构体与“堆栈”问题单片机和PC有什么不同结构体让C语言可以自定义数据类型把多个字段打包成一个整体。比如描述一个学生struct Student { char name[20]; int age; double score; }; struct Student s {Zhang, 18, 89.5};它用的最多的地方是描述复杂数据比如链表节点、文件记录、网络包格式。这一点本身不难真正让新手困惑的是“堆和栈”的问题。有人问“单片机里的C语言没有堆栈吗”答案当然不是没有。任何C程序运行都必须有栈函数调用、局部变量、返回地址都存在栈上。区别在于PC上的程序栈空间很大通常几MB而且由操作系统在进程启动时分配在单片机比如8051上栈空间可能在片内RAM里只有几百字节甚至几十字节需要你在初始化时指定栈顶位置而且栈和堆共用同一片有限内存。这就引出一个实际问题在PC上你写一个int a[1000000]也许能跑要看栈大小一般可能直接栈溢出但在单片机上这么写几乎必死。因为局部大数组放在栈里而栈空间极其有限。解决办法是改成全局变量放在静态存储区或者用malloc从堆里分配。理解这一点你就理解了为什么嵌入式工程师写代码时会特别在意数组大小和递归深度。8. 边学边练四个适合新手的C语言小项目8.1 九九乘法表两分钟写出的经典练习打印九九乘法表是无数C语言课程的入门题目它虽然简单但能把嵌套循环和格式化输出练得明明白白。#include stdio.h int main() { for (int i 1; i 9; i) { for (int j 1; j i; j) { printf(%d*%d%-2d , j, i, i * j); } printf(\n); } return 0; }这里的%-2d表示左对齐、占2个宽度输出表格会更整齐。这个题目适合第一次上手写C的读者没有复杂的指针一轮搞定循环嵌套成就感来得很快。8.2 字符串逆序PTA高频题的标准解法字符串逆序是典型的“看着简单、做起来全是细节”的题目。思路是用两个下标一个从开头走一个从结尾走交换字符直到相遇#include stdio.h #include string.h void reverse(char *s) { int left 0, right strlen(s) - 1; while (left right) { char tmp s[left]; s[left] s[right]; s[right] tmp; left; right--; } }有一点要注意如果题目要求把多个单词按空格分开逆序例如输入“Hello World”输出“World Hello”那就不能简单地整体逆序而是要先反转整个字符串再逐词反转回来。这个“两次反转”的思路在很多面试题里都出现过建议认真理解。8.3 冒泡排序第一堂“算法启蒙课”排序算法是C语言学习绕不开的坎冒泡排序又是其中最直观的一个。它像气泡从水底往上冒一样每一轮把当前未排序部分里最大的数“顶”到最后面void bubble_sort(int arr[], int n) { for (int i 0; i n - 1; i) { int swapped 0; for (int j 0; j n - 1 - i; j) { if (arr[j] arr[j 1]) { int tmp arr[j]; arr[j] arr[j 1]; arr[j 1] tmp; swapped 1; } } if (!swapped) break; // 本轮没有交换说明已经有序 } }这个版本加了一个swapped标志位做优化如果某轮没有任何交换发生说明数组已经有序可以提前退出。写排序题的时候我建议你把每次交换后数组的变化打印出来看一遍亲眼看着数字一步步排好比背十遍算法都深刻。8.4 试着写一个打字小游戏把语法全串起来当基础语法都练过一遍之后可以试一个稍微综合一点的项目——控制台打字游戏。题目可以在屏幕上随机显示一个字符玩家赶紧按对应键程序计时并计分。这里面要综合运用循环、随机数、时间函数还能顺便接触“隐藏光标”之类的控制台技巧。Windows下可以这样隐藏光标#include windows.h void hide_cursor() { CONSOLE_CURSOR_INFO info; info.dwSize 100; info.bVisible FALSE; SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), info); }用到了windows.h库的API这就有点像从“纯C语法”走到“系统调用”的感觉了。如果以后你想研究网络编程还会接触到winsock.h之类的Windows网络库——这些都不是C语言本身的内容而是C语言依赖操作系统接口发挥能力的体现。先从一个几十行的小游戏走到这一步你就已经摸到C语言“能做真东西”的门槛了。9. 常见问题排查与避坑经验速查9.1 C语言里最常踩的报错和坑段错误Segmentation fault核心原因九成是指针越界或数组越界。解决思路是检查所有下标是否在合法范围内嫌疑最大的就是scanf漏了或者数组开小了却强行写入。undefined reference链接错误。点名了“未定义”查一下函数是否写了实现、实现文件是否参与了编译、用到的库有没有用-l参数链接上。编译成功但输出乱码先检查printf的格式符和变量类型是否匹配再检查字符串有没有正常以\0结尾。scanf卡住不读取通常是因为之前输入留下了缓冲区里的换行符scanf(%c)直接读走了换行。解决办法是在读字符前用getchar()清掉残留或者用scanf( %c, ch)格式串里加空格跳过空白字符。9.2 Git日常使用中的几个“隐藏坑”换行符问题Windows上写代码默认是CRLF换行而Linux/macOS上是LF。如果不做配置提交后总是看到整个文件都被标记为修改。解决方式是统一配置core.autocrlf true让Git在提交时自动把CRLF转成LF存储。中文文件名/路径配置core.quotepath false之后中文显示才正常。提交了不该提交的文件尽早使用.gitignore文件把编译产物.o、.exe、编辑器配置、临时文件排除在外。.gitignore需要和代码一起提交这样全团队同享同一套忽略规则。推送被拒绝non-fast-forward说明远程仓库有本地没有的提交这时候先git pull --rebase把远程更新合并下来再重新git push。如果冲突了冷静下来看冲突标记挨个解决别直接删文件。9.3 我长期养成的几个“土办法”最后分享几个我自己在带项目过程中积累下来、又土又实用的习惯。第一个写代码之前先git init。不管写的是课程作业还是练手项目从一开始就纳入版本管理避免“写到一半才想起来没建仓库”的混乱。第二个一次提交只做一件事。改了一个bug、加了一个功能就单独提交别把所有改动混在一起提交这样git log翻历史的时候才看得懂。第三个每次写完一段可运行的东西就提交一次。哪怕当天没写完也留一个“今天进度完成登录模块”的提交记录。第二天接着写心里踏实。这些习惯看着不起眼但在一个月后回看代码时你就会发现它多值钱。我见过太多人把Git用成“保存备份工具”只会add、commit、push三个命令遇到历史记录一团乱麻却不知道怎么理。从入门阶段就保持清晰的提交习惯后面会省下大量时间。如果你现在同时在学C语言和Git我的建议很简单把练习重心放在C语言上每完成一个小程序就顺手用Git提交一次。写九九乘法表→提交写字符串逆序→提交写冒泡排序→提交。等你刷完这些题C语言基本语法掌握了Git的基本操作也无形中熟练了。这两个能力一起长起来之后你会发现后面学数据结构、操作系统、嵌入式都会顺畅很多。别贪快把基础底子夯扎实比什么都重要。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →