前言
本篇笔记承接一维字符数组传参内容,梳理指针高阶用法、指针函数 / 函数指针、const 修饰指针四种场景,搭配课后作业实操,适合刚学完数组、函数的 C 语言入门学习者,内容全部来自课堂实操总结,附带易错点、代码练习与课后综合作业,可直接用于复习与面试基础复盘。
一、一维字符型数组传参回顾
字符数组作为函数参数本质是数组名退化为首元素指针,两种传参写法完全等价:
// 写法1:数组形式(可读性高,推荐新手) int fun(char pstr[]); // 写法2:指针形式(底层本质) int fun(char *pstr);遍历字符串两种实现方式:
- 指针自增遍历
char str[32] = "hello c"; char *p = str; while (*p != '\0') { p++; }- 数组下标遍历
char str[32] = "hello c"; int i = 0; while (str[i] != '\0') { i++; }核心结论:str[i]和*(str+i)完全等价,数组下标只是指针运算的语法糖。
二、指针函数 VS 函数指针(极易混淆,重点区分)
2.1 指针函数:返回值是指针的函数
核心概念
主体是函数,只是函数执行完毕后返回一个内存地址(指针类型)。 语法格式:数据类型 *函数名(形参列表);示例:
// 返回int*类型指针 int *fun(int x, int y); // 返回char*字符串指针 char *fun(void);致命易错点
指针函数绝对不能返回局部变量的地址局部变量存储在栈区,函数执行结束后栈空间会被系统回收,返回其地址会产生野指针,访问直接程序崩溃。
合法使用场景
返回全局字符数组、静态 static 数组、字符串常量地址。
2.2 函数指针:指向函数代码段的指针
核心概念
主体是指针变量,专门存放函数在文本区的起始地址,可用来回调函数、实现多态。 基础语法:返回值类型 (*指针名)(参数类型列表);示例(文中未展开,补充基础理解方便后续拓展):
// 定义函数指针pFun,指向无参、int返回值的函数 int (*pFun)(void);三、const 修饰指针的 4 种场景(面试必考)
const含义为只读(readonly),修饰位置不同,限制对象完全不同,分四类对比记忆:
1.const int *p;/int const *p;
二者完全等价:const修饰*p(指针指向的内容)
- 指针变量
p本身可以修改(可重新指向别的变量) *p只读,不能通过指针修改内存中的值
int a = 10, b = 20; const int *p = &a; p = &b; // 合法,修改指针指向 *p = 100; // 非法,无法修改指向内容2.int *const p;
const修饰指针变量p本身
- 指针
p的指向固定,定义时必须初始化,不能重新赋值指向其他变量 - 可以通过
*p修改指向空间的数据
int a = 10; int *const p = &a; p = &b; // 非法,指针指向不可修改 *p = 100; // 合法,修改内存值3.const int *const p;/int const *const p;
双重 const 限制,二者等价:
- 指针
p不能更换指向 - 指针指向的内容也不能修改
- 定义时必须初始化,完全只读,多用于保护常量字符串
int a = 10; const int *const p = &a; p = &b; // 非法 *p = 100; // 非法快速记忆口诀
*左边 const:内容不可改,指针随便指*右边 const:指针不能换,内容随便改- 两边都加 const:指针、内容全只读
四、课后综合作业(配套知识点实操)
作业 1:字符串库函数手动封装(禁用 <string.h> 库函数)
要求封装 4 个自定义函数:mystrlen、mystrcpy、mystrcat、mystrcmp,额外实现字符串倒置函数
- mystrlen:统计字符串有效长度,不含末尾
\0 - mystrcpy:将源字符串完整拷贝到目标字符数组
- mystrcat:拼接两个字符串,在目标数组末尾追加源字符串
- mystrcmp:逐字符比较两个字符串,返回正负 / 0 表示大小相等
- strReverse:将传入字符串原地倒置
作业 2:数字各位求和函数封装
需求:传入任意整数,返回数字每一位相加总和 例:输入 13542,计算 1+3+5+4+2=15,返回 15 解题思路:循环取模 %10 得到个位,再除以 10 去掉个位,直到数字变为 0
作业 3:最大公约数 & 最小公倍数函数封装
需求:终端输入两个整数,封装函数同时算出最大公约数、最小公倍数并打印
作业 4:数组综合处理(冒泡排序专项)
分三个独立函数实现模块化:
InputArray:接收 10 个数字存入数组BubbleSort:冒泡排序升序排列数组OutputArray:遍历打印数组所有元素 函数原型参考:
int InputArray(int *parray, int len); int BubbleSort(int *parray, int len); int OutputArray(int *parray, int len);作业 5:水仙花数判断
水仙花数定义:三位数,每一位数字立方相加等于自身(例:153=1³+5³+3³) 拓展练习:遍历打印全部三位水仙花数;输入数字判断是否为水仙花数
作业 6:分段函数计算
终端输入 i,根据三段公式计算 y 值并打印:
- i < 5:y = 1+2+3+...+i
- 5 ≤ i < 10:y = 100 - (i-1)-(i-2)-...-1
- i ≥ 10:y = i*i
作业 7:不定个数数字求平均值
持续从终端输入数字,输入 - 1 代表结束,计算所有有效数字平均值
作业 8:闰年判断
输入年份,区分普通闰年、世纪闰年规则:
- 普通闰年:能被 4 整除,不能被 100 整除
- 世纪闰年:能被 400 整除 符合任意一条即为闰年,否则平年
作业 9:几何计算(引入 math 数学库)
- 输入圆半径,计算周长、面积
- 输入三角形三边,海伦公式求面积
编译注意:使用 sqrt 开平方函数,gcc 编译必须加
-lm参数 编译指令示例:gcc test.c -o test -lm
作业 10:数字拆分拼接
给定两个两位数 37、64,按规则拼接出新四位数 3476:
- 千位:第一个数十位(37→3)
- 百位:第二个数个位(64→4)
- 十位:第一个数个位(37→7)
- 个位:第二个数十位(64→6) 最终拼接结果:3 4 7 6 → 3476
五、学习易错点总结
- 字符数组传参不要混淆数组与指针,数组名仅在 sizeof、& 操作时代表完整数组,其余场景退化为指针;
- 指针函数严禁返回局部栈变量地址,会产生野指针;
- const 指针区分核心看 const 在
*左右,不要死记硬背,结合代码测试理解; - 字符串操作必须预留
\0结束符,数组空间长度要大于实际字符数量,防止内存越界; - math 库 sqrt 函数编译必须携带 - lm 链接数学库,否则编译报错;
- 数组传递本质传递首地址,函数内修改数组元素会直接影响外部原数组。
结尾
指针是 C 语言的灵魂,指针函数、const 指针更是笔试面试高频考点,建议每道作业独立手写代码运行调试,不要复制粘贴。先吃透字符串手动封装函数,再练习数字、数组相关综合案例,循序渐进夯实指针与函数结合的核心逻辑。