1.数组在函数中的传参
全局数组传递的方式:
复制传递方式
- 实参为数组的指针,形参为数组名(本质上是一个指针变量)
地址传递方式
- 实参为数组的指针,形参为同类型的指针变量。
题目(1):计算一个一维整型数组的所有元素的和
题目(2):删除字符串中的空格
(1):
#include<stdio.h>
int array_sum(int array[],int n); // 函数声明:告诉编译器存在一个叫array_sum的函数,接收整数数组和整数参数,返回整数
int main()
{
int a[]={1,2,3,4,5}; // 定义并初始化整数数组a:元素为1/2/3/4/5,编译器自动计算长度为5(数组下标从0开始)
int sum=0; // 定义整数变量sum并初始化为0:用于存储数组求和结果,初始化0避免随机值影响
int n=sizeof(a)/sizeof(int); // 计算数组长度:总字节数(sizeof(a))÷单个int字节数(sizeof(int))=元素个数(这里结果是5)
sum=array_sum(a,n); // 调用array_sum函数:传入数组a和长度n,将返回的求和结果赋值给sum
printf("sum=%d \n",sum); // 打印结果:按"sum=%d"格式输出sum的值,%d是整数占位符,\n是换行符
return 0;
}
int array_sum(int array[],int n) // 求和函数定义:实现数组求和逻辑,参数为数组array和长度n,返回整数
{ // array_sum函数代码块开始:函数内代码都包含在这个大括号内
int sum = 0; // 定义函数内局部变量sum并初始化为0:用于累加数组元素,和main里的sum不是同一个变量
int i= 0; // 定义循环变量i并初始化为0:用于遍历数组下标(从0开始)
printf("n=%d \n",n); // 打印数组长度n:调试用,验证传入的长度是否正确(这里输出n=5)
for(i=0;i<n;i++) // for循环:遍历数组所有元素,i从0到n-1(共n次循环)
{ // for循环代码块开始:循环体代码包含在此
sum =sum + array[i]; // 累加数组元素:把第i个元素的值加到sum上(最终sum=1+2+3+4+5=15)
} // for循环代码块结束
return sum; // 返回累加结果:将sum的值(15)返回给main函数的调用处
}
(2)
代码:
#include<stdio.h>
void del_space(char*s);
int main()
{
char s[]="A B C D";
puts(s);
del_space(s);
puts(s);
return 0;
}
void del_space(char*s)
{
char *s2=s;
while (*s !='\0')
{
if(*s==' ')
{
s++;
}
else
{
*s2=*s;
s2++;
s++;
}
}
*s2='\0';
}
我们可以从「代码结构、核心函数逻辑、执行流程」三个层面拆解解释,让你清晰理解每一步的作用。
一、代码整体结构
代码分为两部分:
main函数:定义待处理的字符串、打印原始字符串、调用删除空格的函数、打印处理后的字符串。del_space函数:实现 “删除字符串中所有空格” 的核心逻辑。
二、逐行解释(先看 main 函数)
#include<stdio.h>
void del_space(char*s); // 函数声明:告诉编译器有一个名为del_space的函数,接收字符指针参数,无返回值
int main()
{
char s[]="A B C D"; // 定义字符数组s,内容是"A B C D"(包含3个空格),数组末尾自动补'\0'(字符串结束符)
puts(s); // 打印原始字符串,输出:A B C D(换行)
del_space(s); // 调用删除空格的函数,直接修改原字符数组s的内容
puts(s); // 打印处理后的字符串,输出:ABCD(换行)
return 0; // 程序正常结束
}
三、核心:del_space 函数详解
这个函数的核心思路是双指针遍历:用两个指针(s 和 s2)遍历字符串,s 负责 “找非空格字符”,s2 负责 “把非空格字符写回原数组”,最终在新的末尾补结束符。
void del_space(char*s) // s是指向原字符数组的指针(传址,直接修改原数组)
{
char *s2=s; // 定义第二个指针s2,初始和s指向同一个位置(数组起始地址)
while (*s !='\0') // 循环:只要s指向的字符不是结束符'\0',就继续遍历
{
if(*s==' ') // 如果当前字符是空格
{
s++; // s指针后移,跳过这个空格(不处理)
}
else // 如果当前字符不是空格
{
*s2=*s; // 把s指向的非空格字符,赋值给s2指向的位置(覆盖原位置)
s2++; // s2后移,准备接收下一个非空格字符
s++; // s后移,继续找下一个字符
}
}
*s2='\0'; // 遍历结束后,在s2的位置补'\0',作为新字符串的结束符
}
四、关键知识点总结
- 字符串本质:C 语言中字符串是字符数组,以
'\0'结尾,修改数组内容就是修改字符串。 - 传址调用:
del_space接收的是字符指针(数组首地址),因此函数内的修改会直接作用于原数组(而非副本)。 - 双指针技巧:一个指针(s)遍历找有效字符,另一个指针(s2)记录有效字符的存储位置,避免额外开辟数组空间,效率高。
- 结束符补全:遍历结束后必须给
s2赋值'\0',否则字符串会 “越界”(打印到原始的空格 / 字符)。
2.指针函数
指针函数是指一个函数的返回值为地址量的函数。
指针函数的定义的一般形式如下:
<数据类型> * <函数名称> (<参数说明>)
{
语句序列;
}
简单来说,指针函数是一种返回值为内存地址(指针)的函数,它的核心是 “函数返回的不是普通数值,而是一个变量的地址”。
1. 定义形式拆解
<数据类型> * <函数名称> ( <参数说明> )
{ 语句序列; }
<数据类型> *:表示函数返回的是 “该数据类型变量的地址”(比如int *就是返回 int 变量的地址);<函数名称>:是这个指针函数的名字;<参数说明>:函数的输入参数(和普通函数一样)。
2. 举个实际代码例子(C 语言)
比如写一个 “返回数组元素地址” 的指针函数:
#include <stdio.h>
// 指针函数:返回int数组中指定下标的元素地址
int *f(int a[], int i) {
// 返回数组a中第i个元素的地址
return &a[i];
}
int main() {
int n[] = {10, 20, 30}; // 数组n:存储3个整数
int *p = f(n, 1); // 调用指针函数f,接收返回的地址
printf("值:%d\n", *p); // 通过地址访问对应的值
return 0;
}
2. 逐行解释(极简版)
第一步:理解核心符号含义
int *f(...):f是函数名,int *表示函数返回「int 类型变量的地址」(指针);a[]:a是传入的整数数组(可以理解成 “一组整数的集合”);i:i是要找的数组元素的 “位置编号”(下标);&a[i]:&是取地址符号,意思是 “拿到数组 a 中第 i 个元素的内存地址”;*p:*是解引用符号,意思是 “根据 p 里存的地址,找到对应的数值”。
第二步:逐行拆解代码
| 代码行 | 解释 |
|---|---|
int *f(int a[], int i) { return &a[]; } | 定义指针函数f:1. 接收两个参数:整数数组a、位置编号i;2. 功能:找到数组a中第i个元素的地址,然后返回这个地址。 |
int n[] = {10, 20, 30}; | 定义数组n,里面存了 3 个数:10(第 0 位)、20(第 1 位)、30(第 2 位)。 |
int *p = f(n, 1); | 调用函数f,给它传两个值:数组n、位置编号 1;函数f返回 “数组 n 第 1 位元素的地址”,把这个地址存到指针变量p里。 |
printf("值:%d\n", *p); | 根据p里的地址,找到对应的数值(也就是数组 n 第 1 位的 20),打印出来。 |
return 0; | 程序正常结束。 |
3.递归函数
递归函数是指一个函数的函数体中直接或间接调用了该函数自身。
递归函数调用的执行过程分为两个阶段:
递推阶段:从原问题出发,按递归公式递推从未知到已知,最终达到 递归的终止条件
回归阶段:按递归终止条件求出结果,并逐步代入递归公式,回归到原问题求解
例如求n的阶乘:
先补基础:阶乘的定义
阶乘(用 ! 表示)是数学概念,规则如下:
- 0! 和 1! 的结果都是 1(特殊规定);
- 对于大于 1 的整数 n,n! = n × (n-1) × (n-2) × ... × 1;比如 5! = 5×4×3×2×1 = 120,3! = 3×2×1 = 6
代码
#include<stdio.h>
int fac(int n);
int main()
{
int n = 0;
printf("please input;");
scanf("%d",&n);
printf("%d \n",fac(n));
return 0;
}
int fac(int n)
{
if(n==0 || n== 1)
{
return 1;
}
return n*fac(n-1);
}
3.1 代码核心拆解
#include<stdio.h>
int fac(int n); //函数声明
int main() // 程序入口,从这开始执行
{
int n = 0;
printf("please input;"); // 提示输入数字
scanf("%d",&n); // 读取你输入的数字存到n里
printf("%d \n",fac(n)); // 调用fac算n的阶乘,然后输出结果
return 0;
// fac函数:专门算阶乘(递归)
int fac(int n)
{
if(n==0 || n== 1) // 终止条件:0/1的阶乘直接返回1
{
return 1;
}
return n*fac(n-1); // 递推:n! = n × (n-1)!,自己调用自己算n-1的阶乘
}
3. 2关键执行逻辑(以输入 3 为例)
- main 里调用
fac(3),跳去 fac 函数; - fac (3) 发现 n≠0/1,要算
3×fac(2),再跳去算 fac (2); - fac (2) 发现 n≠0/1,要算
2×fac(1),再跳去算 fac (1); - fac (1) 触发终止条件,返回 1;
- 往回算:fac (2)=2×1=2 → fac (3)=3×2=6;
- 回到 main,输出结果 6。
3.3递归核心(就两句话)
- 终止条件:n=0 或 1 时直接返回 1(不然会无限套娃崩溃);
- 递推:算 n! 先算 (n-1)!,再乘以 n,层层拆解后再层层返回结果。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/2501_93772061/article/details/156098782



