嵌入式面试八股文(三)·野指针产生原因和解决方法、指针函数和函数指针的区别

目录

1.  野指针产生原因和解决方法

1.1  产生的原因

1.1.1  指针未能初始化

1.1.2  指针指向的内存被释放

1.1.3  指针指向的对象被重复释放

1.2  解决方法

1.2.1  初始化指针

1.2.2  指针空置

1.2.3  避免悬挂指针

2.  指针函数和函数指针的区别

2.1  定义不同

2.2  写法不同

 2.3  用法不同

2.3.1  指针函数

2.3.2  函数指针


1.  野指针产生原因和解决方法

        在代码编写的过程中,可能会出现指针指向的位置未知,从而出现程序错误,这种指针统一称作野指针。野指针出现的原因最常见的如下几种:

1.1  产生的原因

1.1.1  指针未能初始化

        如果一个指针变量被声明但没有被初始化,它会包含一个随机的地址,这个地址很可能不指向有效的内存区域。当你尝试访问这个指针所指向的内存时,就会发生未定义行为或者访问非法内存:

#include <stdio.h>

int main()
{
	int* p; // 未初始化的指针
	*p = 20;// 这里会导致未定义行为,因为p并没有指向有效的内存

	return 0;
}

1.1.2  指针指向的内存被释放

        当一个指针指向的内存区域被显式释放(使用 free 函数或者类似的机制)或者超出了其作用域(例如局部变量的指针超出了函数的范围),该指针就成为了野指针。尝试使用或者间接访问这样的指针会导致未定义行为。

int *ptr;
{
    int localVar = 10;
    ptr = &localVar;
} // localVar 超出作用域,ptr 现在是一个野指针

// 尝试访问 *ptr 将导致未定义行为

1.1.3  指针指向的对象被重复释放

        如果一个指针指向的内存已经被释放,但指针本身仍然保持指向已释放的内存,这也会导致野指针的问题。再次使用这个指针可能会导致不可预测的行为或程序崩溃。

int *ptr = malloc(sizeof(int));
free(ptr);
// 现在 ptr 是一个野指针,指向已释放的内存区域

1.2  解决方法

1.2.1  初始化指针

        确保每一个指针在使用前都被正确地初始化。

1.2.2  指针空置

        当指针不再需要时,将其设置为 NULL 或者 nullptr(对于 C++)。

1.2.3  避免悬挂指针

        在超出作用域之前,确保指针不再指向该作用域内的局部变量。

int *ptr = NULL; // 初始化为 NULL

// 使用前检查指针是否为 NULL
if (ptr != NULL) {
    // 只有在 ptr 不为 NULL 时才使用它
}

2.  指针函数和函数指针的区别

2.1  定义不同

指针函数本质是一个函数,其返回值为指针。
函数指针本质是一个指针,其指向一个函数。

2.2  写法不同

        指针函数的*是属于数据类型的,而函数指针的星号是属于函数名的:

指针函数:int* fun(int x,int y);
函数指针:int (*fun)(int x,int y);

        简单点理解就是:函数名带括号的就是函数指针,否则就是指针函数。

 2.3  用法不同

2.3.1  指针函数

        指针函数是一个返回指针的函数。它本质上是一个函数,其返回类型是指针类型。这意味着该函数返回一个指针,指向指定类型的数据。指针函数的声明形式为:

*类型标识符 函数名(参数表)

        举个例子,首先声明一个普通的函数:

int fun(int x,int y);

        我们在声明一个函数,如:

int *fun(int x,int y);

        这和上面那个函数唯一的区别就是在函数名前面多了一个*号,而这个函数就是一个指针函数。其返回值是一个 int 类型的指针,是一个地址。因此想要得到输出值,需要加上解引用运算符*,例如:

#include<stdio.h>

// 定义一个指针函数,返回一个整型指针
int* findMax(int arr[], int size) {
    if (size == 0) 
        return NULL;

    int* max = &arr[0];
    for (int i = 1; i < size; ++i) 
    {
        if (arr[i] > *max) 
        {
            max = &arr[i];
        }
    }
    return max;
}

int main() {
    int numbers[] = { 1, 3, 7, 2, 5 };
    int* maxPtr;

    maxPtr = findMax(numbers, 5); // 调用指针函数

    printf("Max: %d\n", *maxPtr); // 输出最大值
    printf("Max: %p\n", maxPtr);

    return 0;
}

        本函数是一个求数组最大值的函数,若是直接出,则会输出地址,因此需要进行解引用:

        普通函数则可进行直接输出:

#include <stdio.h>

// 定义一个普通函数,返回整型值(最大值)
int findMax(int arr[], int size) {
    if (size == 0)
        return 0; // 如果数组为空,返回一个适当的默认值,这里返回0作为示例

    int max = arr[0];
    for (int i = 1; i < size; ++i) {
        if (arr[i] > max) {
            max = arr[i];
        }
    }
    return max;
}

int main() {
    int numbers[] = { 1, 3, 7, 2, 5 };

    int max = findMax(numbers, 5); // 调用普通函数找到最大值

    printf("Max: %d\n", max); // 输出最大值

    return 0;
}

2.3.2  函数指针

        函数指针是指向函数的指针变量。函数指针存储了函数的地址,可以用来调用该函数。它的声明形式为:

int (*fun)(int x,int y);

        函数指针是需要把一个函数的地址赋值给它,有两种写法:

fun = &Function;
fun = Function;

        取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。

        调用函数指针的方式也有两种:

x = (*fun)();
x = fun();

        我们进行一个简单的运用:

#include<stdio.h>

//函数+
int add(int x, int y) 
{
    return x + y;
}

//函数指针
int (*fun)(int x, int y);

int main() 
{
    int result;

    // 将函数指针 fun 分别指向 add 和 sub 函数
    fun = add;
    result = fun(10, 5); // 调用 add 函数
    printf("Result of add: %d\n", result);

    fun = &add;
    result = fun(10, 5); // 调用 add 函数
    printf("Result of add: %d\n", result);

    fun = add;
    result = (*fun)(10, 5); // 调用 add 函数
    printf("Result of add: %d\n", result);

    fun = &add;
    result = (*fun)(10, 5); // 调用 add 函数
    printf("Result of add: %d\n", result);

    return 0;
}

千题千解·嵌入式工程师八股文详解_时光の尘的博客-CSDN博客

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时光の尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值