c语言(三)-函数、malloc

490 阅读4分钟

本篇文章主要记录函数使用、动态内存分配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.