总结一下指针与函数的形参设计,首先了解封装函数主函数与指针之间的值传递和地址传递

一、值传递

1.定义

值传递是将变量的值复制一份传递给函数或方法。在函数内部对参数的任何修改不会影响原始变量

2.特点

原始变量的值不会被修改。
函数内部操作的是参数的副本。

3.参数传递指针与形参修改实参的原理

在C语言中,函数传参的传递本质上是值传递(传递副本)。若需要通过形参修改实参的值,必须传递实参的指针(地址),(地址传递将在第二点说),并在函数内通过解引用操作修改指针指向的内存内容 。

例:场景:Operate 函数 实现 求两数和 两数之积

#include <stdio.h>
int Operate(int a,int b)
{
   return a+b,a*b;//逗号表达式
}
int main()
{
    int* p=Operate(1,2);
	return 0;
}

上述代码存在问题,首先是逗号表达式,使得主函数中运用Operate函数时,a+b的结果将会被丢弃,返回a*b的值。第二就是main函数中尝试将Operate的返回值赋值给int*类型的指针p,类型不匹配。

要解决上述问题,解决方案:

①:定义数组,定义一个全局变量int arr[2];来延长数组生存周期

②:延长数组生存周期--static
static修饰局部变量(延长局部变量的生存周期)

③:通过参数带值

④:使用malloc(之后文章总结详细用法)

总结

函数 传参 -->值传递(形参 对实参 值拷贝(副本))
  bool Operate(int a,int b,int* padd,int* pmul)
{
       *padd=a+b;
       * pmul=a*b;
       return ture;
}
int main()
{}

二、地址传递

1.定义

地址传递是将变量的内存地址传递给函数或方法。函数内部通过地址直接操作原始变量,因此对参数的修改会影响原始变量

2.特点

原始变量的值可能被修改。
函数内部操作的是原始变量的地址。

三:地址传参和值传参的区别


地址传参:形参对实参的地址拷贝,形参修改实参,传地址,解引用
          优势:节省内存空间,形参和实参指向同一份地址空间
值传参:形参对实参值拷贝(副本),拷贝完内存独立

四、函数返回

函数 返回值 返回地址称为指针函数
注意:不能返回局部变量的地址

指针函数的定义

指针函数是指返回值为指针类型的函数。这类函数的声明形式为:返回类型 *函数名(参数列表)。例如:

int *getPointer(int value) {
    static int data = value;
    return &data;
}

返回地址的注意事项

不能返回局部变量的地址

这是一个非常重要的限制,因为局部变量在函数执行结束后就会被销毁,其内存空间会被释放。如果返回这样的地址,会导致程序出现未定义行为。例如:

// 错误的示例
int *dangerousFunction() {
    int localVar = 10;
    return &localVar;  // 错误:返回局部变量的地址
}

安全的返回方式

  1. 返回静态变量的地址:静态变量在程序整个运行期间都存在

    int *safeFunction1() {
        static int staticVar;
        return &staticVar;
    }
    
  2. 返回全局变量的地址

    int globalVar;
    int *safeFunction2() {
        return &globalVar;
    }
    
  3. 返回动态分配的内存地址

    int *safeFunction3() {
        int *ptr = (int *)malloc(sizeof(int));
        *ptr = 100;
        return ptr;
    }
    
  4. 返回传入参数的地址

    int *safeFunction4(int *param) {
        *param = 50;
        return param;
    }
    

内存管理注意事项

当返回动态分配的内存时,调用者有责任在不再需要时释放这些内存,否则会导致内存泄漏:

int *ptr = safeFunction3();
// 使用ptr...
free(ptr);  // 必须释放内存

五、空指针和野指针

空指针解引用

空指针是指指向内存地址为0的指针。在大多数操作系统中,地址0是受保护的,不允许用户程序访问。解引用空指针会导致程序崩溃,通常表现为段错误或访问冲突。

空指针解引用的典型场景:

int *ptr = NULL;
int value = *ptr;  // 解引用空指针,导致崩溃

避免空指针解引用的方法是在解引用前检查指针是否为NULL:

if (ptr != NULL) {
    value = *ptr;
} else {
    // 处理空指针情况
}

野指针解引用

野指针是指指向已释放或无效内存地址的指针。解引用野指针的行为是未定义的,可能导致程序崩溃、数据损坏或难以预测的行为。

野指针的常见来源:

int *ptr = (int *)malloc(sizeof(int));
free(ptr);  // 内存释放后,ptr成为野指针
*ptr = 10;   // 解引用野指针,未定义行为

避免野指针的方法包括释放内存后将指针置为NULL,并在解引用前检查指针有效性:

free(ptr);
ptr = NULL;  // 释放后立即置空

if (ptr != NULL) {
    *ptr = 10;
}

指针解引用崩溃的解决方案

使用智能指针(如C++的std::unique_ptrstd::shared_ptr)可以自动管理内存,减少空指针和野指针问题:

std::unique_ptr<int> ptr(new int(42));
if (ptr) {  // 自动检查有效性
    int value = *ptr;
}
Logo

一座年轻的奋斗人之城,一个温馨的开发者之家。在这里,代码改变人生,开发创造未来!

更多推荐