C - 内联函数、递归函数、指针函数
最编程
2024-03-25 21:30:36
...
1. 前言
这篇文章介绍C语言的内联函数、递归函数、函数指针、指针函数、局部地址、const关键字、extern关键字等知识点;这些知识点在实际项目开发中非常常用,非常重要。
下面就以小章节的流程介绍每个知识点。
2. 函数返回局部空间的地址问题
子函数: 在调用结束后空间会被释放---被系统回收。
总结:子函数不能返回局部变量的地址。
示例1:
#include <stdio.h>
char *func(void);
int main()
{
printf("%s\n",func()); //打印不出来。
return 0;
}
char *func(void)
{
char buff[]="1234567890";
return buff;
}
示例2:
#include <stdio.h>
char *func(char *p);
int main()
{
char buff[]="1234567890";
printf("%s\n",func(buff)); //可以打印
return 0;
}
char *func(char *p)
{
return p;
}
示例3:
#include <stdio.h>
char *func(void);
int main()
{
printf("%s\n",func()); //可以打印
return 0;
}
char *func(void)
{
static char buff[]="1234567890";
return buff;
}
3. const 只读关键字(常量)
(1) const关键字—修饰变量
#include <stdio.h>
int main()
{
//const int a; //初始化不赋值,这行代码就没有意义
const int a=100;
a=200; //错误的代码--无法对常量赋值--只读变量赋值
printf("a=%d\n",a);
return 0;
}
(2) const关键字---修饰指针
#include <stdio.h>
//指针: 数据域、指针(地址)域
int main()
{
int a=100;
int b=200;
//const常用4种修饰指针的方法
const int *p1=&a; //指向空间值无法修改,指向的地址可以改变
int const *p2=&a; //指向空间值无法修改,指向的地址可以改变
int *const p3=&a; //指向空间值可以修改,指向的地址无法改变
const int *const p4=&a; //向空间值无法修改,指向的地址无法改变
//int *p5 const; 语法是错误的
//*p1=666; 错误的
//p1=&b; 正确的
//*p2=666;错误的
//p2=&b;正确的
//*p3=666;正确的
//p3=&b;错误的
//p4=&b;错误的
//*p4=666;错误的
return 0;
}
4. 内联函数
内联函数: 在调用的时候不会进行压栈出栈(不会经历保存地址的过程和恢复地址的过程)。
内联函数相当于一个替换的过程。
内联函数设计要注意:内联函数里只能写简单的代码—不能写复杂代码。
函数里的局部变量存放在栈空间里的。栈空间:是由系统管理的。
#include <stdio.h>
void func(void);
int main()
{
int a;
func();
printf("12345\n");
return 0;
}
//inline 声明-定义内联函数
inline void func(void)
{
printf("hello\n");
}
5. extern 外部引用声明
extern 多用于多文件编程里变量、函数、其他数据类型的引用声明。
外部引用声明的时候,不能赋值。
#include <stdio.h>
//引用声明
extern int a;
extern char buff[];
extern void func();
int main()
{
printf("%d\n",a);
printf("%s\n",buff);
func();
return 0;
}
int a=100;
char buff[]="1234567890";
void func()
{
printf("hello\n");
}
6. 字符串数组和字符串常量定义问题
#include <stdio.h>
int main()
{
//p1指向的字符串是在程序编译的时候赋值
char *p1="1234567890"; //指针指向字符串常量
//p2数组是程序运行的时候赋值
char p2[]="abcdefg";
//p1[0]='A'; 错误的
printf("%s\n",p1);
printf("%s\n",p2);
return 0;
}
示例2:
#include <stdio.h>
int main()
{
//p1指向的字符串是在程序编译的时候赋值
char *p1="1234567890"; //指针指向字符串常量
//p2数组是程序运行的时候赋值
char p2[]="abcdefg";
int a;
int b;
int c;
printf("a=%#x\n",&a);
printf("b=%#x\n",&b);
printf("c=%#x\n",&c);
printf("p1=%#x\n",p1);
printf("p2=%#x\n",p2);
return 0;
}
/*
a=0xbf9f93e0
b=0xbf9f93dc
c=0xbf9f93d8
p1=0x8048524
p2=0xbf9f93e4
*/
7. 标准main函数形参语法
#include <stdio.h>
/*
int argc :传入的参数数量(包括可执行文件本身)
char **p :保存传入的数据地址
main传入的参数数据都是字符串类型。
传参数的方式: ./a.out 123 456 789
*/
int main(int argc,char **p)
//int main(int argc,char *p[]) p[0] p[1] p[2]
{
int i;
for(i=0;i<argc;i++)
{
printf("p[%d]=%s\n",i,p[i]);
}
return 0;
}
8. 指针函数与函数指针
数组指针: 本身是指针,指向二维数组的指针(一维数组指针)。int (*p)[5];
指针数组: 本身是数组,数组里存放的是地址。int *p[5]; (相当于定义了5个指针)
数组的名称本身就是数组元素的首地址---数组名称就是地址。
函数指针: 本身是指针,指向函数的指针。语法:int (*p)(int,int); 不支持++和—运算符。
指针函数: 本身是函数,表示函数的返回值是指针类型。语法: int *func(int a,int b){}
函数名称就是地址。
示例1:
#include <stdio.h>
int func(int a,int b);
int main(int argc,char **argv)
{
int (*p)(int,int); //指向函数的指针
p=func;
printf("%d\n",func(10,20)); //通过函数名称调用函数
printf("%d\n",p(10,20)); //通过指针调用函数--写法1
printf("%d\n",(*p)(10,20)); //通过指针调用函数--写法2
return 0;
}
int func(int a,int b)
{
return a+b;
}
示例2: 函数指针当做函数形参
#include <stdio.h>
int func1(int a,int b);
int func2(int (*p)(int,int),int a,int b);
int main(int argc,char **argv)
{
printf("%d\n",func2(func1,100,200));
return 0;
}
int func1(int a,int b)
{
return a+b;
}
int func2(int (*p)(int,int),int a,int b)
{
return p(a,b);
}
9. 递归函数
什么是递归函数? 子函数直接或者间接的方式调用自己的过程叫做递归。
函数自己调用自己的过程---递归。
递归函数注意事项:必须有终止条件。
示例1:
#include <stdio.h>
int func(int a);
int main(int argc,char **argv)
{
printf("%d\n",func(1)); //10
return 0;
}
int func(int a)
{
a++;
if(a==10)
{
return a;
}
else
{
func(a);
}
}
示例2:计算字符串的长度—使用递归
#include <stdio.h>
int func(char *p);
int main(int argc,char **argv)
{
printf("%d\n",func("1234567890")); //10
return 0;
}
//计算字符串长度
int func(char *p)
{
if(*p=='\0')
{
return 0;
}
return 1+func(p+1);
}
/*
演示递归函数的返回过程:
a(); //3
int a()
{
return 1+b();
}
int b()
{
return 1+c();
}
int c()
{
return 1;
}
*/
推荐阅读
-
[C++] std::distance 函数的详细解析(小白一看就懂哦!!!) - IV.注意事项
-
彭 C 回顾 - 字符函数和字符串函数
-
NX 二次开发--C++ 使用 IDA Pro 反编译 dll,查看内部使用的 API 函数(第 1 部分)
-
正负偏差变量 即 d2+、d2- 分别表示决策值中超出和未达到目标值的部分。而 di+、di- 均大于 0 刚性约束和目标约束(柔性目标约束有偏差) 在多目标规划中,>=/<= 在刚性约束中保持不变。当需要将约束条件转换为柔性约束条件时,需要将 >=/<= 更改为 =(因为已经有 d2+、d2- 用来表示正负偏差),并附加上 (+dii-di+) 注意这里是 +di、-di+!之所以是 +di,-di+,是因为需要将目标还原为最接近的原始刚性约束条件 优先级因素和权重因素 对多个目标进行优先排序和优先排序 目标规划的目标函数 是所有偏差变量的加权和。值得注意的是,这个加权和都取最小值。而 di+ 和 dii- 并不一定要出现在每个不同的需求层次中。具体分析需要具体问题具体分析 下面是一个例子: 题目中说设备 B 既要求充分利用,又要求尽可能不加班,那么列出的时间计量表达式即为:min z = P3 (d3- + d3 +) 使用 + 而不是 -d3 + 的原因是:正负偏差不可能同时存在,必须有 di+di=0 (因为判定值不可能同时大于目标值和小于目标值),而前面是 min,所以只要取 + 并让 di+ 和 dii- 都为正值即可。因此,得出以下规则: 最后,给出示例和相应的解法: 问题:某企业生产 A 和 B 两种产品,需要使用 A、B、C 三种设备。下表显示了与工时和设备使用限制有关的产品利润率。问该企业应如何组织生产以实现下列目标? (1) 力争利润目标不低于 1 500 美元; (2) 考虑到市场需求,A、B 两种产品的生产比例应尽量保持在 1:2; (3)设备 A 是贵重设备,严禁超时使用; (4)设备 C 可以适当加班,但要控制;设备 B 要求充分利用,但尽量不加班。 从重要性来看,设备 B 的重要性是设备 C 的三倍。 建立相应的目标规划模型并求解。 解:设企业生产 A、B 两种产品的件数分别为 x1、x2,并建立相应的目标计划模型: 以下为顺序求解法,利用 LINGO 求解: 1 级目标: 模型。 设置。 variable/1..2/:x;! s_con_num/1...4/:g,dplus,dminus;!所需软约束数量(g=dplus=dminus 数量)及相关参数; s_con(s_con_num);! s_con(s_con_num,variable):c;!软约束系数; 结束集 数据。 g=1500 0 16 15. c=200 300 2 -1 4 0 0 5; 结束数据 min=dminus(1);!第一个目标函数;!对应于 min=z 的第一小部分;! 2*x(1)+2*x(2)<12;!硬约束 @for(s_con_num(i):@sum(variable(j):c(i,j)*x(j))+dminus(i)-dplus(i)=g(i)); !使用设置完成的数据构建软约束表达式; ! !软约束表达式 @for(variable:@gin(x)); !将变量约束为整数; ! 结束 此时,第一级目标的最优值为 0,第一级偏差为 0: 第二级目标: !求 dminus(1)=0,然后求解第二级目标。 模型。 设置。 变量/1..2/:x;!设置:变量/1..2/:x; ! s_con_num/1...4/:g,dplus,dminus;!软约束数量及相关参数; s_con(s_con_num(s_con_num));! s_con(s_con_num,variable):c;! 软约束系数; s_con(s_con_num,variable):c;! 结束集 数据。 g=1500 0 16 15; c=200 300 2 -1 4 0 0 5; 结束数据 min=dminus(2)+dplus(2);!第二个目标函数 2*x(1)+2*x(2)<12;!硬约束 @for(s_con_num(i):@sum(variable(j):c(i,j)*x(j))+dminus(i)-dplus(i)=g(i)); ! 软约束表达式;! dminus(1)=0; !第一个目标结果 @for(variable:@gin(x)); ! 结束 此时,第二个目标的最优值为 0,偏差为 0: 第三目标 !求 dminus(2)=0,然后求解第三个目标。 模型。 设置。 变量/1..2/:x;!设置:变量/1..2/:x; ! s_con_num/1...4/:g,dplus,dminus;!软约束数量及相关参数; s_con(s_con_num(s_con_num));! s_con(s_con_num,variable):c;! 软约束系数; s_con(s_con_num,variable):c;! 结束集 数据。 g=1500 0 16 15; c=200 300 2 -1 4 0 0 5; 结束数据 min=3*dminus(3)+3*dplus(3)+dminus(4);!第三个目标函数。 2*x(1)+2*x(2)<12;!硬约束 @for(s_con_num(i):@sum(variable(j):c(i,j)*x(j))+dminus(i)-dplus(i)=g(i)); ! 软约束表达式;! dminus(1)=0; !第一个目标约束条件; ! dminus(2)+dplus(2)=0; !第二个目标约束条件 @for(variable:@gin(x));! 结束 最终结果为 x1=2,x2=4,dplus(1)=100,最优利润为
-
C++ 入门语法(命名空间、默认函数、函数重载、引用、内联函数和 nullptr)
-
C 语言] printf 函数的使用
-
C 函数声明和调用 - C 语言基础教程
-
指向 c 中函数的指针
-
如何使用 C# 中的 Enum.GetNames 函数获取枚举类型中所有定义的名称
-
C/C++ 不定式函数