本篇文章主要记录函数使用、动态内存分配malloc等。c语言是面向过程语言,所以函数在c语言中非常重要。
函数
函数主要考虑几个方面,形参、实参、返回、参数的输入输出
-
函数和变量一样,一定要先声明, 后使用
第一种情况
//函数的声明和定义放在了一起
void testFunction()
{
printf("function inside");
}
int main()
{
//函数的使用
testFunction();
return 0;
}
第二种情况,如果函数的定义在函数调用的后面,需要先声明一下,像下面这样是全局声明
//使用函数前,需要先声明
void testFunction(void);
int main()
{
//函数的使用
testFunction();
return 0;
}
//函数定义
void testFunction()
{
printf("function inside");
}
这里顺便说下变量,变量的使用一样是先声明后使用,但是有时变量的声明和定义不太好区分,一般的做法是给变量的声明添加extern关键字
例如这样, 就很难区分处那些是声明,那些是定义。
注意:定义只能定义一次,但是可以声明多次
int testVar;
int testVar;
int testVar = 10;
int testVar;
正确的做法一般是像下面这样:
//变量的声明, 这个也可以声明在其他的头文件中,这样在使用是,直接引用那个头文件就可以了, 变量的定义放在.c文件中
extern int testVar;
int main()
{
//变量的使用
printf("testVar is %d\n", testVar);
return 0;
}
//变量的定义
int testVar = 10;
- 函数的返回值 函数的返回值只能返回一个值,不能返回多个值,所以这就解释了为什么不能把数组作为返回值,因为数组是多个值,像下面这样,编译是不会通过的。
int [] testFunction()
{
printf("function inside");
}
-
函数的参数问题 这个是函数中最重要的一个方面了。
函数中的参数列表是形参,在调用函数的过程中,会有个实参像形参赋值的过程,形参和实参从内存中来看,是没有关系的两块空间。
//函数定义
void testFunction(int a)
{
// 修改形参
a = 10;
}
int main()
{
//定义一个变量
int a = 100;
//变量的使用
testFunction(a);
printf("a is %d\n", a); // a is 100
return 0;
}
如果想要修改a的值,怎么办呢,那么需要用到指针了。通过给函数传入指针,在函数的内部通过指针直接修改对应的内存空间
//函数定义
void testFunction(int *a)
{
// 修改a指向的内存空间
*a = 10;
}
int main()
{
//定义一个变量
int a = 100;
//变量的使用
testFunction(&a);
printf("a is %d\n", a); // a is 10
return 0;
}
- 参数的作用范围 在函数内部定义的变量是在栈区分配的,当函数运行结束后,栈上的内存就会被释放了,这是如果把这个变量的地址传递给外部的调用函数使用的话,就会发生错误
//函数定义
int * testFunction()
{
// 在栈区定义一个变量
int a = 100;
//返回地址
return &a;
}
int main()
{
//调用函数,获取一个指针
int *a = testFunction();
//打印
//testFunction函数运行结束后,栈内存已释放,会报错
printf("a is %d\n", *a);
return 0;
}
这种情况要怎么处理呢? 正确的做法可以是可以在堆上分配内存,这样调用函数就可以使用了
//函数定义
int * testFunction()
{
// 在堆区定义一个变量
int *a = (int *)malloc(4);
//返回地址
return a;
}
int main()
{
//调用函数,获取一个指针
int *a = testFunction();
//打印
//testFunction函数运行结束后,堆内存不会释放
printf("a is %d\n", *a);
//别忘记释放堆内存
free(a);
return 0;
}
堆上分配内存
之前已经讲过,栈分配内存是有编译器分配,分配与释放都是系统处理的,释放的时机是函数运行结束。这样外部的调用函数就无法操作被调用函数的栈区域,解决这个问题的方法就是被调用函数在堆上分配空间。
堆分配释放操作很简单。简单说一下:
malloc和free函数的使用需要引入stdlib.h头文件
- malloc 通过malloc函数分配内存, 会返回一个相应存储类型的指针
- free 释放堆内存 参数是malloc的返回指针
这里在补充和内存操作相关的两个常用函数 memset memcpy,这两个函数直接操作内存,前置主要做内存的初始化,后者主要功能是复制,可以类比strcpy.