C语言中形参和实参的区别小结
C语言中的形参和实参一、核心定义形参 (Formal Parameter)定义函数声明或定义时括号内的参数内存分配函数调用时在栈上分配内存特点是局部变量只在函数内部有效初始化被实参初始化实参 (Actual Argument)定义函数调用时传入的具体值或表达式特点必须有确定的值位置函数调用时出现在括号内二、基础示例1234567891011121314151617181920212223#include stdio.h// 函数定义 - a, b 是形参intadd(inta,intb) {returna b;}intmain() {intx 5, y 3;// 函数调用 - x, y 是实参intresult add(x, y);printf(结果: %d\n, result);// 输出: 8// 直接使用常量或表达式作为实参result add(10, 20);// 常量实参printf(结果: %d\n, result);// 输出: 30result add(x, y * 2);// 表达式作为实参printf(结果: %d\n, result);// 输出: 11return0;}三、C语言的参数传递机制1.传值调用 (Call by Value)- C语言的默认方式123456789101112131415161718#include stdio.hvoidswap_by_value(inta,intb) {inttemp a;a b;b temp;printf(函数内: a%d, b%d\n, a, b);}intmain() {intx 10, y 20;printf(交换前: x%d, y%d\n, x, y);swap_by_value(x, y);// 只传递值的副本printf(交换后: x%d, y%d\n, x, y);// 原值未改变return0;}输出交换前: x10, y20函数内: a20, b10交换后: x10, y20 // 原值未变2.传址调用 (Call by Address)- 使用指针1234567891011121314151617#include stdio.hvoidswap_by_address(int*a,int*b) {inttemp *a;*a *b;*b temp;}intmain() {intx 10, y 20;printf(交换前: x%d, y%d\n, x, y);swap_by_address(x, y);// 传递地址printf(交换后: x%d, y%d\n, x, y);// 原值改变了return0;}3.数组作为参数- 实际传递的是指针123456789101112131415161718192021222324252627282930#include stdio.h// 数组作为参数实际是指针voidprint_array(intarr[],intsize) {// int arr[] 等价于 int *arrfor(inti 0; i size; i) {printf(%d , arr[i]);}printf(\n);}voidmodify_array(intarr[],intsize) {for(inti 0; i size; i) {arr[i] * 2;// 会修改原数组}}intmain() {intnums[] {1, 2, 3, 4, 5};intsize sizeof(nums) /sizeof(nums[0]);printf(原数组: );print_array(nums, size);modify_array(nums, size);printf(修改后: );print_array(nums, size);// 数组内容已改变return0;}四、不同类型的参数1. 基本数据类型参数123456789#include stdio.h// 各种基本类型参数voidprocess_basic_types(inti,floatf,doubled,charc) {printf(整型: %d\n, i);printf(浮点: %.2f\n, f);printf(双精度: %.4lf\n, d);printf(字符: %c\n, c);}2. 指针参数123456789101112131415161718192021#include stdio.h#include string.h// 字符串处理使用字符指针voidstring_operations(char*str) {printf(字符串: %s\n, str);printf(长度: %zu\n,strlen(str));// 修改字符串内容str[0] toupper(str[0]);}// 多级指针voidallocate_memory(int**ptr,intsize) {*ptr (int*)malloc(size *sizeof(int));if(*ptr ! NULL) {for(inti 0; i size; i) {(*ptr)[i] i * 10;}}}3. 结构体参数12345678910111213141516171819202122232425#include stdio.h// 结构体定义typedefstruct{intx;inty;} Point;// 传值 - 传递整个结构体的副本voidprint_point_by_value(Point p) {printf(点坐标: (%d, %d)\n, p.x, p.y);p.x 100;// 只修改副本}// 传址 - 传递结构体指针voidmodify_point_by_address(Point *p) {p-x 10;p-y 10;}// 返回结构体Point create_point(intx,inty) {Point p {x, y};returnp;}4. 函数指针参数1234567891011121314151617181920212223242526272829#include stdio.h// 回调函数类型定义typedefint(*CompareFunc)(int,int);intmax(inta,intb) {return(a b) ? a : b;}intmin(inta,intb) {return(a b) ? a : b;}// 使用函数指针作为参数intcompare_and_process(inta,intb, CompareFunc func) {returnfunc(a, b);}intmain() {intresult;result compare_and_process(10, 20, max);printf(较大值: %d\n, result);// 20result compare_and_process(10, 20, min);printf(较小值: %d\n, result);// 10return0;}五、参数的高级特性1. const参数保护数据不被修改1234567891011121314151617#include stdio.h// const保护指针指向的数据voidprint_string(constchar*str) {// str[0] A; // 错误不能修改const数据while(*str) {putchar(*str);}}// const保护指针本身voidprocess_array(int*constarr,intsize) {// arr NULL; // 错误不能修改指针本身for(inti 0; i size; i) {arr[i] 1;// 可以修改指向的数据}}2. 可变参数stdarg.h12345678910111213141516171819202122#include stdio.h#include stdarg.h// 可变参数函数intsum_variable_args(intcount, ...) {inttotal 0;va_listargs;// 参数列表va_start(args, count);// 初始化for(inti 0; i count; i) {total va_arg(args,int);// 获取下一个int参数}va_end(args);// 清理returntotal;}intmain() {printf(总和: %d\n, sum_variable_args(3, 10, 20, 30));// 60printf(总和: %d\n, sum_variable_args(5, 1, 2, 3, 4, 5));// 15return0;}3. 参数默认值C语言不支持但可用宏模拟123456789101112// 使用宏模拟默认参数#define PRINT_MESSAGE(msg, count) print_message_impl(msg, count)voidprint_message_impl(constchar*msg,intcount) {for(inti 0; i count; i) {printf(%s\n, msg);}}// 使用重载宏#define PRINT_MESSAGE_1(msg) PRINT_MESSAGE(msg, 1)#define PRINT_MESSAGE_2(msg, count) PRINT_MESSAGE(msg, count)六、重要注意事项1. 数组参数的大小信息丢失1234voidprocess(intarr[]) {// 等价于 int *arr// sizeof(arr) 返回的是指针大小不是数组大小// 必须额外传递数组大小参数}2. 参数的求值顺序12inti 0;printf(%d, %d, %d\n, i, i, i);// 未定义行为不同编译器结果不同3. 寄存器变量参数register关键字1234// 建议编译器将参数放入寄存器C17起已废弃但可了解voidfast_function(registerintx,registerinty) {// 这些参数可能存储在寄存器中访问更快}七、完整示例程序12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849#include stdio.h#include stdlib.h// 结构体定义typedefstruct{charname[50];intage;floatscore;} Student;// 函数声明voidprint_student(constStudent *s);voidupdate_score(Student *s,floatnew_score);Student create_student(constchar*name,intage,floatscore);intmain() {// 创建学生结构体Student stu create_student(张三, 20, 85.5);// 传址调用可以修改原结构体printf(修改前:\n);print_student(stu);update_score(stu, 90.0);printf(\n修改后:\n);print_student(stu);return0;}// 函数定义Student create_student(constchar*name,intage,floatscore) {Student s;snprintf(s.name,sizeof(s.name),%s, name);s.age age;s.score score;returns;// 返回结构体C语言支持结构体返回}voidprint_student(constStudent *s) {printf(姓名: %s\n, s-name);printf(年龄: %d\n, s-age);printf(分数: %.1f\n, s-score);}voidupdate_score(Student *s,floatnew_score) {s-score new_score;// 直接修改原结构体}八、最佳实践总结明确传递意图不需要修改的参数使用const修饰需要修改的参数使用指针传递数组参数总是同时传递数组和大小使用const保护不想被修改的数组结构体参数小结构体传值简单安全大结构体传址高效需要修改的结构体必须传址参数验证1234567voidsafe_divide(intnumerator,intdenominator) {if(denominator 0) {fprintf(stderr,错误分母不能为零\n);return;}// 安全操作...}文档说明1234567/** 函数calculate_average* 参数scores - 分数数组不能为NULL* count - 数组元素个数必须大于0* 返回平均分如果出错返回-1*/floatcalculate_average(constfloat*scores,intcount);理解形参和实参是掌握C语言函数编程的基础特别是理解C语言严格的传值机制和通过指针实现的传址效果这是与许多其他语言的重要区别。