[C/C++] 函数
疑问
1、数组指针和指针数组什么意思,具体怎么使用?
2、数组(一维/二维)和指针的关系?数组做函数形参的表达方式有几种?
3、函数结束后,函数栈释放的内容有哪些?
4、通过函数修改形参的值怎么实现?值传递还是引用传递?基本类型、数组、结构体有什么区别?
5、函数内malloc和free内存注意事项有哪些?
6、如果想通过函数对实参进行malloc,为什么必须用二级指针?
数组和指针
函数栈空间
在一个函数执行完毕后其所占用的内存空间(除了静态和全局变量)统统会被释放掉
执行程序有一个栈空间,每一次函数调用都会开辟新的栈空间,完成调用后,新开辟的栈空间被释放
因此如果递归函数没有正确返回的话,程序会出现栈溢出导致程序崩溃
// 代码说明函数栈释放
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
修饰符限定
函数参数(一级指针)相关
内存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);
}