[C/C++] 函数

疑问

1、数组指针和指针数组什么意思,具体怎么使用?

2、数组(一维/二维)和指针的关系?数组做函数形参的表达方式有几种?

3、函数结束后,函数栈释放的内容有哪些?

4、通过函数修改形参的值怎么实现?值传递还是引用传递?基本类型、数组、结构体有什么区别?

5、函数内malloc和free内存注意事项有哪些?

6、如果想通过函数对实参进行malloc,为什么必须用二级指针?

数组和指针

image

函数栈空间

在一个函数执行完毕后其所占用的内存空间(除了静态和全局变量)统统会被释放掉

执行程序有一个栈空间,每一次函数调用都会开辟新的栈空间,完成调用后,新开辟的栈空间被释放

因此如果递归函数没有正确返回的话,程序会出现栈溢出导致程序崩溃

// 代码说明函数栈释放
int *func(){
    int x = 10; // 栈空间局部变量,调用结束后被释放
    return &x;
}
// out put: if branch
int main() {
    int *ret = func();
    if (ret == NULL) {
        printf("Address of stack memory associated with local variable is freed after caller end");
    }
}

int *func2(){
    static int x = 10; // 栈空间静态变量,调用结束后没有被释放
    return &x;
}

// out put: else branch
int main() {
    int *ret = func2();
    if (ret == NULL) {
        printf("Address of stack memory associated with local variable is freed after caller end");
    } else {
        printf("x address: %p\n", ret);
        printf("Address of stack memory associated with local variable is not freed after caller end");
    }
}

值传递

C语言所有的函数参数都是“传值引用”,意味着函数将获得该数值的一份拷贝,函数可以放心修改这个拷贝值,而不是修改调用方实际传给它的参数

1、基本数据类型

基本数据类型的数据通过函数修改,都必须传入指针实现,不能直接传入基本类型参数

2、数组类型

数组名的值实际上是一个指针,可以执行访问操作,参数同样是一份拷贝,但在这一份拷贝上执行的间接访问操作的的是原来的数组,和传递指针效果一样

如果不希望在函数内部修改数组的值,可以通过const修饰符限定

函数参数(一级指针)相关

image
image
image

内存malloc

如果想在函数内部动态申请内存,应该怎么实现呢?

有以下两种方式

  • 形参为二级指针,在函数内部分配内存
  • 形参为空,通过指针函数方式分配内存
#include <stdio.h>
#include <stdlib.h>

// CASE 1
void allocateMemory(char** ptr) {
    *ptr = (char*)malloc(10 * sizeof(char));  // 分配内存并将地址存储到ptr所指向的指针中
    strcpy(*ptr, "Hello");
}

int main() {
    char* myString = NULL;
    allocateMemory(&myString);  // 传递myString的地址作为参数
    printf("%s\n", myString);  // 输出动态分配的字符串
    free(myString);  // 释放内存
    return 0;
}

// CASE 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void allocateArray(int** ptr, int size) {
    *ptr = (int*)malloc(size * sizeof(int));  // 分配内存
    for (int i = 0; i < size; i++) {
        (*ptr)[i] = 100;
    }
}

//void copyArray(int* src, int* dest, int size) {
//    for (int i = 0; i < size; i++) {
//        dest[i] = src[i];
//    }
//}

int main() {
    int size = 5;
    int* dynamicArray;
    allocateArray(&dynamicArray, size);  // 动态分配数组
    int staticArray[size];
//    copyArray(dynamicArray, staticArray, size);  // 将动态数组复制到静态数组
    memcpy(staticArray, dynamicArray, size * sizeof(int));
    for (int i = 0; i < size; i++) {
        printf("%d ", staticArray[i]);  // 输出静态数组元素
    }
    printf("\n");
    free(dynamicArray);  // 释放动态分配的内存
    return 0;
}
// CASE 1
#include <stdio.h>
#include <stdlib.h>

char* allocateMemory() {
    char* ptr = (char*)malloc(10 * sizeof(char));  // 分配内存
    strcpy(ptr, "Hello");
    return ptr;  // 返回指向动态分配内存的指针
}

int main() {
    char* myString = allocateMemory();  // 调用指针函数,接收返回的指针
    printf("%s\n", myString);  // 输出动态分配的字符串
    free(myString);  // 释放内存
    return 0;
}

// CASE 2 array
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TYPE int

TYPE *mem_malloc(int len) {
    if (len <= 0) {
        return NULL;
    }
    TYPE *a = NULL;
    a = (TYPE *) malloc(sizeof(TYPE) * len);
    for (int i = 0; i < len; ++i) {
        *(a + i) = 10;
    }
    return a;
}

int main() {
    int size = 10;
    TYPE staticArray[size];
    TYPE *x = mem_malloc(size);
    memcpy(staticArray, x, size * sizeof(TYPE));
    for (int i = 0; i < size; ++i) {
        printf("%d ", *(staticArray + i));
    }
    free(x);
    return 0;
}

回调函数 & 函数指针

以一个客户端、服务端的例子说明回调函数的应用

整体流程说明

  • 服务端提供回调的注册接口和函数指针
  • 客户端注册回调到服务端,客户端修改服务端的data值
  • 服务端demo只支持一个回调函数的注册,后续可以通过表的方式通过消息支持多个回调函数的注册
// client.c
#include <stdio.h>
#include "server.h"

// 回调处理函数
void client_callback_process(int* data) {
    printf("SDK User: Callback function called with data: %d\n", *data);
    // 模拟修改data的操作
    *data = 456;
    printf("SDK User: Modified data: %d\n", *data);
}

int main() {
    registerCallback(client_callback_process);
    server_main_process();
}

// server.h
typedef void (*Callback)(int *);
void registerCallback(Callback callback);
void server_main_process();

// server.c
#include <stdio.h>
#include "server.h"

// 全局变量用于接收回调函数和参数
Callback callbackFunction = NULL;

// 注册回调函数给SDK服务方
void registerCallback(Callback callback) {
    // 模拟注册回调函数的操作
    printf("SDK Provider: Callback function registered.\n");
    // 将回调函数赋值给全局变量
    callbackFunction = callback;
}

// 触发事件,调用客户端注册的回调函数并传递参数
void triggerEvent(int *data) {
    printf("SDK Provider: Event triggered with data: %d\n", *data);

    // 调用客户端注册的回调函数并传递参数
    if (callbackFunction != NULL) {
        callbackFunction(data);
    }
}

// 模拟服务端的处理流程
void server_main_process() {
    int data = 123;
    triggerEvent(&data);
    printf("SDK Provider: Receive data modified by SDK user: %d\n", data);
}
posted @ 2023-07-09 22:17  __Helios  阅读(28)  评论(0编辑  收藏  举报