如何优雅地传递指针?

今天来讲一个超9成C语言新手使用指针犯过的错误。
实例:写一个函数让输入指针指向一个另一个地址并对指向的内容进行处理

数据定义:

static T_macList macList  = {0};    //全局mac表

T_macList *getMacList(void)
{
    return &macList;
}

传递指针并对指针指向的内容做修改:

void getNoflagNode(T_macList *p)
{
    T_macList *pmaclist = getmaclist();
    T_macList *pNode = NULL;
    list_for_each_entry(pNode, &pmaclist->list, list)
    {
        if(pNode->flag == 0)
        {
            p = pNode;
            return;
        }
    }
}

使用:
T_macList *node = NULL;
getNoflagNode(node);

问题:
使用 node 时,出现了: segmentation fault(段错误)
实际上node依然是指向了NULL,而且使用的时候也没有处理没有返回导致指针依然是NULL的情况

一个改良:

T_macList *getNoflagNode(void)
{
    T_macList *pmaclist = getmaclist();
    T_macList *pNode = NULL;
    list_for_each_entry(pNode, &pmaclist->list, list)
    {
        if(pNode->flag == 0)
        {
            LOG_INFO("p mac is  %s \n", pNode->mac);
            return pNode;//虽然pNode在栈上申请,但是地址已经被改为了堆上的地址,函数结束,pNode也会在栈上被清理掉,但是传递地址的使命已经完成了
        }
    }
    return NULL;
}

使用:
T_macList *node = NULL;
node = getNoflagNode();
if(node == NULL)
    ......
使用node时,pNode已经指向了mac表中没有标记类型的节点了

本质分析:
我的同事经常说函数传参的本质是传递一份拷贝;
我的理解是对待指针参数是使用一个新的临时指针去指向参数,对待非指针变量只是新建一个值相同的变量来供内部使用
所以可以这么理解:
在这里插入图片描述
所以在一开始直接使用双重指针就没事了

void getNoflagNode(T_macList **p)
{
    T_macList *pmaclist = getmaclist();
    T_macList *pNode = NULL;
    list_for_each_entry(pNode, &pmaclist->list, list)
    {
        if(pNode->flag == 0)
        {
            *p = pNode;
            return;
        }
    }
}

使用:
T_macList *node = NULL;
getNoflagNode(&node);    //注意传递的是node的地址
if(node == NULL)
    ......

在这里插入图片描述
如果还不够生动,或者虚拟变量阻碍了理解,那么再来看2个简单的实例:
实例1:修改字符串内容

void change( char *p )
{
    p = "bbb";
    printf("%s\n",p);
}
int main()
{
    char v[4] = "aaa";
    printf("v1=%s\n",v);
	change(v);
	printf("v2=%s\n",v);
}
//结果:
//v1=aaa, p=bbb, v2=aaa

change函数根本不起作用,很多新人会以为 p = “bbb” 是给字符指针变量赋值,实际上是给 p 的地址赋值,赋予了字符串 “bbb” 的地址。
解决方法:
同一开始的案例,使用双重指针可以解决。

void change( char **p )
{
    *p = "bbb";
    printf("%s\n",*p);
}
int main()
{
    char v[] = "aaa";
    printf("v1=%s\n",v);
    change(&v);
    printf("v2=%s\n",v);
}
//结果:
//v1=aaa, p=bbb, v2=bbb

实例2:修改数字指针指向的内容

void change( int *p )
{
	int i = 20;
	p = &i;
}
int main()
{
	int i = 10;
	int *a = &i;
	change( a );
}

这段代码和实例1的第一段代码本质上是一样的,但是这段代码大家都可以看出问题;实例1的第一段代码之所以很多人没有看出问题,是因为把字符串当做了普通的字符变量,而忽略了它的一个本质,传递时是字符串的地址。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值