C语言笔记-10-函数空间-概念与规则
文章目录
- C语言笔记-10-函数空间-概念与规则
- 前言
- 一、函数概念
-
-
- 1.传入参数
- 2.返回值
-
- 二、函数参数
- 三、指针函数-函数名指针化
-
-
- 1.指针指向其他函数的函数名(标签)效果
- 2.指针指向其他函数的地址效果
- 3.通过二级指针,将一组函数线性化
-
- 四、函数值传递和址传递
- 五、函数连续空间的传递
-
-
- 1.结构体(变量)
- 2.数组(标签)
- 3.连续空间的只读
-
- 六、函数返回值
- 总结
前言
自学笔记,没有历史知识铺垫(省略百度部分)C语言概念与规则
一、函数概念
函数三要素
int fun(int,int,char){xxx}
- 函数名 (地址)
- 输入参数
- 输出参数
1.传入参数
实参: 调用时传入的具体值
形参: 函数内部接受的变量
2.返回值
返回函数处理的结果数据(另一种方式是函数外部使用址传递参数,来获得函数处理的数据)
二、函数参数
C语言函数传参,实际上就是copy的过程,参数类型的区别在于copy的多少的问题,当然类型不同可能存在丢失部分数据情况(copy不完整)
void printAddress(int a)
{
//printAddress a地址:0xc
printf("printAddress a地址:%p\n",a);
}
int main()
{
int a = 12;
//main a地址:0xc
printf("main a地址:%p\n",a);
printAddress(a);
return 0;
}
void printAddress(int a)
{
//printAddress a地址:0xffffff9b
printf("printAddress a地址:%p\n",a);
}
int main()
{
char a = "ABCDE";
//main a地址:0xffffff9b
printf("main a地址:%p\n",a);
printAddress(a);
return 0;
}
void printAddress(int a)
{
//printAddress a地址:0xeccc1e18
printf("printAddress a地址:%p\n", a);
}
int main()
{
int a = 12;
int *p_a;
p_a = &a;
//main a地址:0x7ffeeccc1e18
printf("main a地址:%p\n", p_a);
printAddress(p_a);
return 0;
}
三、指针函数-函数名指针化
通过函数三要素可以得出,指针也可以表示函数 int (*p)(int,int,char){xxx}
与指针指向二维数组类似,指针必须要加(),来提高程序对他解读的优先级,而不是默认从右往左读
1.指针指向其他函数的函数名(标签)效果
int main()
{
int (*printf2)(const char *,...);
//HelloWOrld
printf("HelloWOrld\n");
printf2 = printf;
//FFFF
printf2("FFFF\n");
return 0;
}
2.指针指向其他函数的地址效果
int main()
{
int (*printf2)(const char *, ...);
//HelloWOrld 0x7fff204b50b8
printf("HelloWOrld %p \n", printf);
printf2 = (int (*)(const char *, ...))0x7fff204b50b8;
//FFFF
printf2("FFFF\n");
return 0;
}
3.通过二级指针,将一组函数线性化
int (*p[5])(int,int);
p[0]=func1;
p[1]=func2;
p[2]=func3;
//使用效果,可以替代switch
p[day](8,9);
四、函数值传递和址传递
值传递:传入数据
void fun1(int a){...}
a
copy到函数中,函数中数据的修改不影响函数外被传入的数据
址传递:
传入数据地址
void func2(*a){...}
copy到函数中,函数中数据的修改是在该地址上修改的,函数外被传入的数据也处在该内存地址上,所以会数据被修改
&a
仅查看时用值传递
读写资源或节省资源时 使用址传递
五、函数连续空间的传递
连续空间传递,一般都会选择使用址传递,使用值传递浪费资源过多
1.结构体(变量)
值传递示例
struct product_t
{
char name[20];
int price;
};
void println(struct product_t product)
{
strncpy(product.name, "牙刷", 20);
product.price = 3;
//println:牙刷
printf("println:%s \n", product.name);
//println:3
printf("println:%d \n", product.price);
}
int main()
{
struct product_t product;
strncpy(product.name, "手机", 20);
product.price = 3666;
println(product);
//main:手机
printf("main:%s \n", product.name);
//main:3666
printf("main:%d \n", product.price);
return 0;
}
址传递示例 (通过指针)
struct product_t
{
char name[20];
int price;
};
void println(struct product_t *product)
{
//product[0]等价于*product此处可以替换,但是需要加()让程序优先识别,即:(*product)
strncpy(product[0].name, "牙刷", 20);
product[0].price = 3;
//println:牙刷
printf("println:%s \n", product[0].name);
//println:3
printf("println:%d \n", product[0].price);
}
int main()
{
struct product_t product;
strncpy(product.name, "手机", 20);
product.price = 3666;
println(&product);
//main:牙刷
printf("main:%s \n", product.name);
//main:3
printf("main:%d \n", product.price);
return 0;
}
2.数组(标签)
数组在定义时,编译器已经知道其首地址被
int names[10];
标签描述,因此数组作为形参时只需要传递数组的标签名和偏移量即可
names
即可
names[10]
数组址传递数据示例
//C语言现在优化允许使用int p[10],便于阅读 实际上效果与int *p一致,都是址传递
void println(int *p)
{
p[0] = 77;
//println:77
printf("println:%d \n", p[0]);
//println:11
printf("println:%d \n", p[1]);
}
int main()
{
int prices[10] = {22, 11, 55};
println(prices);
//main:77
printf("main:%d \n", prices[0]);
//main:11
printf("main:%d \n", prices[1]);
return 0;
}
数组址传递地址示例
//C语言现在优化允许使用int p[10],便于阅读 实际上效果与int *p一致,都是址传递
void println(int *p)
{
p[0] = 77;
//println:0x7ffee8964df0
printf("println:%p \n", &p[0]);
//println:0x7ffee8964df4
printf("println:%p \n", &p[1]);
}
int main()
{
int prices[10] = {22, 11, 55};
println(prices);
//main:0x7ffee8964df0
printf("main:%p \n", &prices[0]);
//main:0x7ffee8964df4
printf("main:%p \n", &prices[1]);
return 0;
}
如上两段代码,数组传递为址传递,数组标签名本身就是地址的标签,与指针非常相似
3.连续空间的只读
定义参数时使用const修饰指针所指的内存地址即可,如
const char *p
,这也是开发时默认的规范
读写函数形参:
只读函数形参:
char *p;
如
const char *p
函数的源码:
strncpy
char *stpncpy(char *dst, const char *src, size_t n)
六、函数返回值
返回值与参数一样,也是copy的原理传递,可以copy值,也可以copy地址
char func1()
{
char s = 'A';
return s;
}
int main()
{
char s= func1();
//41
printf("%X",s);
return 0;
}
注意:指针是C语言中返回空间的唯一类型 (无法返回函数内部创建的变量地址,会被回收:异常) int * func();
char * func1()
{
return "HelloWorld";
}
int main()
{
char *p= func1();
//HelloWorld
printf("%s",p);
return 0;
}
工程中一般不使用上述方案(常量区存储),意义不大,通常使用静态区存储局部变量(程序结束才回收),即如下方法
char * func1()
{
static char abc[] = "HelloWorld";
return abc;
}
int main()
{
char *p= func1();
//HelloWorld
printf("%s",p);
return 0;
}
也可以使用堆区存储函数中创建的变量,注意使用完毕后一定要释放内存(
malloc()
)
free()
char * func1()
{
char *s = (char *)malloc(50);
strncpy(s,"HelloWorld",50);
return s;
}
int main()
{
char *p= func1();
//HelloWorld
printf("%s",p);
free(p);
return 0;
}
总结
本章主要为C语言函数概念和规则