资讯详情 秋招冲刺C语言Day7:数组、字符串与指针入门实战
📅 2026/10/20 16:17:08
1. 为什么秋招前还在硬啃C语言基础“秋招”这个词对每个准备找工作的同学来说都是一场心理和体力的双重考验。有人刷了几百道算法题有人准备了三份实习经历而我——一个自称“菜鸟”的选手选择在秋招冲刺阶段自学C语言第7天。很多朋友可能会问都这时候了学C语言还来得及吗我的回答是来得及而且非常值得。C语言是几乎所有计算机相关岗位笔试面试的基础语言无论是后端开发、嵌入式、还是客户端方向C语言的身影几乎无处不在。哪怕你投递的是Java岗面试官也可能在一面中抛出一道C语言指针题来考察你的基本功。所以第7天的学习目标不是“成为C语言专家”而是“把地基打牢能在笔试和面试中不露怯”。Day7是个很特别的节点。经过前6天的学习你已经掌握了变量、数据类型、运算符、流程控制if、switch、循环甚至接触了函数的基本用法。这个阶段最尴尬的事情是感觉自己啥都看过但真正做题时脑子里一片空白。这是所有自学者的必经之路不用慌第7天我们要做的是“把知识串起来开始动手解决实际问题”。这篇文章我会完整记录这一天的学习路线、踩过的坑、以及和秋招笔试面试直接相关的经验总结。如果你也在自学C语言、准备秋招这篇文章完全是为你准备的。2. 第7天核心任务数组、字符串与指针入门前面6天学的东西都是零散的“积木块”比如if判断是“选择走哪条路”for循环是“重复做某件事”。但从Day7开始我们要学习如何把这些积木块组合起来。今天的三块核心内容分别是数组、字符串和指针的初步认识。数组解决的是“如何管理一堆同类型数据”的问题。字符串本质上不过是一个字符数组。而指针是C语言区别于Java、Python等语言的最重要特征也是秋招笔试面试的必考内容。如果你想顺利通过秋招的技术面指针这一关必须过。2.1 数组的本质连续内存的“格子铺”学习数组可以把它想象成在一排连续的格子柜里存东西。每个格子编号从0开始。比如声明一个int类型的数组int scores[5] {88, 76, 92, 65, 81};这行代码告诉你我们在内存中申请了5个连续的int大小的空间每个int是4个字节在大多数平台上所以这5个格子占用了从某个起始地址开始的连续20个字节。数组名scores代表的是这组连续内存空间的起始地址也就是第一个格子scores[0]的地址。这个理解非常关键因为后续学指针时你会发现数组名和指针有着千丝万缕的关系。评论区总有人说“数组不过是个语法糖”但在C语言里数组远不止语法糖这么简单。它直接对应了内存中的真实布局。你在Java里可能不用担心int占用几个字节但在C语言里面对的是内存分配、字节对齐、存储边界等底层问题。实操中数组常见的两个值得留意的点。第一个是数组下标越界问题。C语言不像Java那样会自动做数组越界检查编译器也不一定会报错。你访问scores[5]、scores[10]甚至scores[-1]程序可能在运行时直接崩溃也可能给你返回一个随机的脏数据。这种错误在秋招笔试里非常常见面试官最喜欢问“下面的代码会有什么问题”然后甩给你一段越界访问的代码。第二个点在于传数组给函数的时候它不会把整个数组的值复制过去而是把数组的首地址传给函数。这也是“数组作为函数参数会退化成指针”的原因。比如下面的代码void print_scores(int arr[], int n) { for (int i 0; i n; i) { printf(%d , arr[i]); } } int main() { int scores[5] {88, 76, 92, 65, 81}; print_scores(scores, 5); return 0; }这里的int arr[]和int *arr本质上是等价的。你可能会想为什么函数参数里不直接传“整个数组”因为复制整个数组的性能开销太大了。想象一下你有一万个元素的数组每次调用都复制一遍太浪费了。传地址指针就能轻松解决这个效率问题。2.2 字符串数组的“特殊形态”C语言里没有独立的字符串类型。你写下的hello其实是存放了6个字符的字符数组h、e、l、l、o、\0。注意最后一个\0这是字符串结束标记是所有字符串操作函数的判断依据非常重要。很多人刚开始学C语言用strlen、strcpy这类函数时没搞懂为什么要传数组名其实说白了就是传字符串的首地址起点有了终点靠\0来检测。字符串初始化的正确姿势char str1[] hello; // 自动在末尾补一个\0占据6个字节 char str2[] {h, e, l, l, o, \0}; // 手动加\0和上面完全等价可能有人已经踩过类似这样的坑写了char str[5] hello;然后发现打印结果不对甚至程序崩溃这就是没给\0留位置的经典错误。hello需要6个字节你只给了5个把\0挤到内存的其他地方去了。Day7学习字符串重点是掌握几个核心函数的手动实现逻辑。一个合格的求职者就算背不出标准库的实现也应该能手写一个简单的字符串长度计算逻辑int my_strlen(const char *s) { int len 0; while (*s ! \0) { len; s; } return len; }这段代码虽然简单但它完美展示了“用指针遍历字符数组直到\0”这个核心思路。面试现场让你手写C语言字符串函数是秋招里日常操作这个必须烂熟于心。2.3 指针初探内存地址的“导航系统”终于到了C语言学习的重头戏指针。指针本身并不神秘它就是个变量只不过这个变量存的不是普通数值而是内存地址。你可以把指针想象成手机的导航系统。你在导航里输入一个地址导航就能带你去到那个具体地点。指针变量存储某个变量的地址通过解引用操作*ptr就能访问和修改该地址上的数据。最经典的入门代码int a 10; int *p a; // a 是取a的地址p存储了这个地址 printf(%d\n, *p); // *p 是解引用访问p指向的内存输出10 *p 20; // 修改p指向的内存a的值也跟着变成20 printf(%d\n, a); // 输出20关键点在于理解p存放的是“a住在哪”*p则是“在a的地址上进行操作”。这两者语义完全不同。指针为什么让很多人脑袋爆炸因为它有两个方向的混淆一个是“指针的类型”int *、char *、double *一个是“指针指向的数据类型”。int *p意味着p指向的数据是int类型那么p在进行加减运算时步长是sizeof(int)个字节。这也是指针运算的核心特性。int arr[5] {1, 2, 3, 4, 5}; int *p arr; // p指向数组首元素 p; // 指针前进一个int的距离即4个字节 printf(%d\n, *p); // 输出2已经指向了第二个元素注意p不是地址加1而是加了一个int的大小。以这个逻辑学下去后面你会用到“指针数组”、“数组指针”、“函数指针”、“二级指针”等更复杂的概念。Day7的定位是先搞懂指针的基础用法能把数组、字符串和指针串起来使用。3. 从语法到题目Day7的实战敲码记录光看不练假把式。Day7我给自己安排了两个实战题目一个线性查找一个冒泡排序。这两个题目并不难但是能很好地把数组、循环、函数这几个知识点串起来而且它们也是秋招笔试的入门级热身体。3.1 题目1用线性查找找出某个值的下标任务描述给定一个整数数组和一个目标值如果目标值存在于数组中返回它的下标否则返回-1。我的第一版代码#include stdio.h int linear_search(int arr[], int n, int target) { for (int i 0; i n; i) { if (arr[i] target) { return i; } } return -1; } int main() { int nums[] {34, 67, 12, 89, 45, 23}; int target 89; int n sizeof(nums) / sizeof(nums[0]); int idx linear_search(nums, n, target); if (idx ! -1) { printf(找到了下标是%d\n, idx); } else { printf(未找到该元素\n); } return 0; }这是典型的线性查找时间复杂度O(n)也就是最坏情况下要遍历所有元素才能找到目标。笔试中这道题基本属于送分题但要注意几个细节第一sizeof(nums) / sizeof(nums[0])这种求数组长度的方法只能在数组定义的同一作用域内使用。一旦数组被当作参数传给函数就只能在main函数里算好长度再传进去。在函数内部对指针参数使用sizeof得到的只是指针本身的大小在64位机器上通常是8字节不是数组长度。这是初级选手最容易遗漏的点。第二为什么返回值用-1表示“未找到”因为数组下标最小是0用-1可以避免和二义性冲突。这是C语言编程中的一个通用约定。3.2 题目2用冒泡排序实现数组的升序排列任务描述给数组{34, 67, 12, 89, 45, 23}实现升序排列。冒泡排序的基本想法是每一轮把“最大的元素”像气泡一样冒到最后面。我的实现#include stdio.h void bubble_sort(int arr[], int n) { for (int i 0; i n - 1; i) { // 每一轮把最大的元素冒泡到末尾 for (int j 0; j n - 1 - i; j) { if (arr[j] arr[j 1]) { // 交换两个元素 int temp arr[j]; arr[j] arr[j 1]; arr[j 1] temp; } } } } int main() { int nums[] {34, 67, 12, 89, 45, 23}; int n sizeof(nums) / sizeof(nums[0]); bubble_sort(nums, n); printf(排序结果); for (int i 0; i n; i) { printf(%d , nums[i]); } printf(\n); return 0; }这段代码的思考要点是为什么内层循环要写n - 1 - i因为经过i轮排序最后i个元素已经有序不需要再参与比较了这样可以减少无意义的比较次数。实测运行结果如下排序结果12 23 34 45 67 89冒泡排序的时间复杂度是O(n²)面试时通常会问有没有更高效的排序方法这就是引申到快速排序的考点。但在Day7阶段先把冒泡排序稳稳拿捏住快速排序可以放到后面再去突破。3.3 调试过程的真实记录在写这些代码的过程中我还真踩过一个比较低级的错误。第一次运行程序时输出结果不对排序后的数组没有任何变化。我重新审视代码发现问题出在我把数组长度n算错了——我直接在main函数里写了n 5但这个数组明明有6个元素。所以内层循环次数不够最后一个元素根本没参与排序。这种错误在真实开发中非常常见尤其是手写代码时经常会出现数字计算不细心的情况。我的排查习惯是在关键循环处用printf打印中间结果// 调试代码片段 printf(第%d轮排序后, i 1); for (int k 0; k n; k) { printf(%d , arr[k]); } printf(\n);打印后能非常直观地看到每一轮数组的变化情况一眼就能判断排序逻辑是否正确。这个小技巧在我后续刷题的过程中帮了大忙建议养成习惯。4. 秋招视角这些基础知识到底怎么考很多自学编程的菜鸟都有一个困惑我学了这么多基础语法秋招笔试面试真的会考这玩意吗答案是不仅考而且考得相当细。4.1 笔试环节的常见出题方式秋招笔试的C语言部分选择题是主要形式而且特别喜欢考细节题。我整理了三个Day7知识点直接对应的常见出题方向第一类是数组相关的陷阱题。比如给出如下代码问输出是什么int a[5] {1, 2, 3, 4, 5}; printf(%d\n, a[5]);答案是不确定甚至可能直接报错。因为a[5]已经越界访问了访问的是数组最后一个元素后面那个未知内存区域。这种题考察的就是你是否清楚数组下标的边界。第二类是指针与数组结合的题目。比如int a[5] {1, 2, 3, 4, 5}; int *p a; printf(%d\n, *(p 3));答案是4。这里的p 3不是地址值加3而是指向数组第4个元素。记住指针加n是加n个元素的大小不是加n个字节。第三类是关于字符串结束符的题目。比如char str[] abc; printf(%d\n, sizeof(str));答案是4因为abc实际占用了4个字节包含\0。但如果把sizeof换成strlen答案是3。这两种函数的区别必须刻在脑子里。sizeof是运算符它在编译时就能确定结果strlen是函数它会在运行时从首地址一直数到\0才停下。4.2 面试现场的C语言考察点面试和笔试不同面试官更倾向于让你“手写代码”或者“讲讲某个知识点”。Day7对应的知识点在面试中常被问到的是“请说一下数组名和指针的区别。”这是一道经典面试题也是用来区分新手和老手的问题。标准的思路是数组名本质上是地址常量它不能被重新赋值也不能进行自增操作。而指针是变量可以重新指向新的地址。举个具体例子int a[5] {1, 2, 3, 4, 5}; int *p a; a; // 编译错误数组名不是左值 p; // 合法指针可以移动这个题目看起来很基础但很多候选人回答得七零八落。回答的关键在于说清楚“数组名在表达式中会被隐式转换为指向首元素的指针”同时“数组名本身不是一个可修改的指针变量”。“请手写一个字符串拷贝函数。”很多同学在笔试或者面试中遇到这道题直接写一个循环遍历源字符串然后一个字符一个字符地赋给目标字符串。基础写法没毛病但有个经典优化可以借用指针简洁地写成这样void my_strcpy(char *dest, const char *src) { while (*dest *src); }面试官看到这种写法至少能确认两点你对指针运算非常熟练而且你了解字符串是以\0结尾的——当*src等于\0时赋值表达式的值也为0循环自然终止。这种写法看起来简单但踩满了很多基本功的考点。写完之后面试官可能会追问“这个函数如果src和dest指向同一块内存会怎么样”如果你能答出“会导致未定义行为需要先存原始数据或用memmove这类函数来处理重叠”那这轮面试基本稳了。“你能说说什么是野指针吗”野指针指的是指向“已经释放的内存”或者“无效内存地址”的指针。在秋招面试中这个问题非常高频。回答思路是指针变量定义后如果没给初始值它可能指向内存中任意一个不确定的位置当你通过这个指针去修改数据时会导致程序无法预料的崩溃。正确的做法是定义指针时初始化通常初始化为NULL或者指向合法的内存地址。4.3 从“菜鸟”到“能聊”的差距在哪“能聊”和“会做题”之间有一条巨大的鸿沟。Day7这个阶段我建议你主动做一些面试模拟题来检验自己是否真的理解。特别是下面这种综合题void func(char str[]) { printf(%d\n, sizeof(str)); } int main() { char str[] hello; printf(%d\n, sizeof(str)); func(str); return 0; }主函数输出的结果是6hello加\0而func函数里输出的结果却是8在64位机器上指针的大小是8字节。这就是“数组传参退化为指针”的经典考法。如果你能一眼看出这两处输出的差别并解释原因说明对数组和指针的关系已经有了比较扎实的理解。如果现在你还不能完全理解也先不用着急。秋招冲刺阶段最重要的是持续积累和复利效应。Day7能做到“看得懂、能复现、能解释”这些核心概念已经比昨天前进了一大步。5. 常见问题与避坑速查这段时间在自学和答疑群里我看到了很多同学问的高频问题。这里整理一份“Day7阶段常见问题速查表”全部基于真实踩坑经历可以帮你少走很多弯路。问题错误示范正确姿势原因分析数组下标越界访问a[5]当数组长度为5合法范围是a[0]到a[4]C语言不检查边界属于未定义行为字符串空间不足char s[5] hello;char s[6] hello;必须为末尾\0预留空间未初始化指针int *p; *p 10;int a 10; int *p a;野指针指向未知内存赋值会崩溃指针步长理解错p 1以为加了1字节int型指针p1是加4字节指针运算的步长是sizeof(指向类型)函数内用sizeof求长度void f(int arr[]) { int n sizeof(arr)/sizeof(arr[0]); }函数外算好长度传进来函数参数中数组退化为指针sizeof得到的是指针大小除开表中列出的偏基础的问题还有几个在实际秋招笔试现场很容易出现的坑。第一个“坑”是关于运算符优先级。比如p到底先执行p还是先执行p按照C语言运算符优先级的优先级高于*所以p等价于(p)即先取出当前指针指向的值然后指针向后移动。这个细节在笔试选择题中反复出现。如果不确定建议用括号明确表达意图代码可读性也会更好。第二个“坑”是函数返回局部数组的问题。比如int *get_array() { int arr[3] {1, 2, 3}; return arr; // 危险 }局部数组在函数返回后内存空间被释放返回的指针就成了野指针。正确做法是用malloc动态分配内存或者通过参数把数组传进去填充内容和配套的长度指标。第三个“坑”是字符串比较的问题。很多人会写if (str1 str2)这是在比较两个指针地址是否相同不是在比较字符串内容。需要老老实实用strcmp函数。这个问题在面试手写代码时几乎必被追问。6. 给同是“菜鸟”的你一点私房建议学到这里我已经可以明确告诉你Day7是自学的第一个分水岭。前6天学的是“认识语法”从今天开始我们进入“用语法解决问题”的阶段。这个转变过程并不轻松我在写冒泡排序时都会卡壳更别说指针了。对于同样处于菜鸟阶段、正在准备秋招的你这里有几个掏心窝的建议第一不要追求一次性看懂所有理论。我当时学指针第一遍看视频时完全看不懂甚至怀疑是不是自己智商有问题。后来发现更实际的做法是先把代码抄一遍跑起来然后修改几个参数看看输出变化。实操能够帮你建立那种“哦原来如此”的感觉。第二把每个小知识点都当成一个“面试题”来对待。学完数组问自己“如果面试官让我说说数组名和指针的区别我能答几秒”学完字符串问自己“如果让我手写strlen我能写出来吗”这种“以考代练”的模式效率高得惊人。第三建议用点时间整理自己写过的代码形成“代码笔记”。不需要多花哨GitHub仓库也好本地文件夹也行把题目、代码、错误记录放到一起。秋招笔试前翻一遍自己的笔记比临时翻阅教材要高效得多。如果你能看到这里说明你大概率也是那个正在默默加练的菜鸟。自学这条路最大的挑战从来不是知识的难度而是日复一日的坚持。第7天的你可能依然觉得C语言很陌生但比起第1天的“一脸懵”你已经学会了用循环让计算机做重复的事用数组管理一组数据甚至开始触碰C语言最核心的指针。后面还有更硬核的内容等着你函数指针、结构体、动态内存分配、文件操作、链表……哪一个都能让你在秋招的考卷上多拿几分。今天结束之前把代码再敲一遍逻辑走不通就打印中间结果多调试几次这就是学习C语言的日常。保持这种节奏秋招考场上你会感谢现在这个没有放弃的自己。