首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C/C++ 学习笔记

C/C++ 学习笔记

作者头像
用户11827960
发布2025-09-09 22:24:46
发布2025-09-09 22:24:46
5800
代码可运行
举报
运行总次数:0
代码可运行

在用C/C++进行开发的时候,记录一下碰到过的问题,希望能够帮助别人

1.Typeof

  typeof是GCC的一个扩展,在linux下可以使用,很多文章说是关键字,这个算是误导吧,起码不是C标准的东西。

  在MingW下,可用decltype代替,这个问题在使用uthash的类库时发现的,在预定义宏里,有TYPEOF的定义,使用过的同学可以看看 : )

   (以下代码在VS2010编译通过)

代码语言:javascript
代码运行次数:0
运行
复制
#if defined __cplusplus
#define TYPEOF(x) (typeof(x))
#else
#define TYPEOF(x)
#endif

  改为

代码语言:javascript
代码运行次数:0
运行
复制
#if defined __cplusplus
#define TYPEOF(x) (decltype(x))
#else
#define TYPEOF(x)
#endif

 2.指针

  因为需要,在C中进行自定义事件系统,就像JAVA或者javascript的一样,当你需要监听一个事件的时候,通常是将处理函数与事件相绑定,那在C/C++中,大家想到的肯定是传递函数指针来进行事件绑定啦,我也是这样做的。

  定义事件监听函数,根据事件名,对事件进行监听

代码语言:javascript
代码运行次数:0
运行
复制
BOOL addEventListener(char* eventName,int (*fun)(EventObject* e));

  其中:

代码语言:javascript
代码运行次数:0
运行
复制
int (*fun)(EventObject* e)

  fun定义的函数指针,int指定了fun指向的函数的返回类型,而EventObject* e 指定了该函数的参数列表。可以这样理解 fun指向了如下格式的函数

代码语言:javascript
代码运行次数:0
运行
复制
int eventListener(EventObject* e){
}

  这样就可以通过函数指针添加事件监听了,不过使用C++的同学要注意了,这里的函数指针,指向的是全局函数,即非对象成员函数。C/C++在定义指针类型的时候,分别定义了4种类型的指针,分别是:变量指针,函数指针,成员变量指针,成员函数指针。不同类型的指针,不能够随意转化。所以说如果使用函数指针来传递一个成员函数的话,编译是会报错的。这里可以采用网上提供的开源类库,不过我并没有深究,有兴趣的同学可以研究一下,欢迎探讨 ^_^!

3.局部变量想要被当作全局变量来使用

  这是我犯得一个错误,在此提醒跟我同样错误的同学,要小心了,先上代码

代码语言:javascript
代码运行次数:0
运行
复制
#include <stdio.h>
struct linkList{
    linkList * prev;
    int number;
    linkList * next;
} ;

linkList * newElement(){
    linkList * temp = new linkList;
    return temp;
}

linkList *  newElement2(){//这个写法是错误的
    linkList temp;
    return &temp;
}

void linkListMain(){
linkList * cur = 0;
    linkList * newLinkList;

    linkList head;
    head.prev = 0;
    head.number = 0;
    head.next = 0;

    cur = &head;
    for(int i = 1 ; i <= 10 ; i++){
        //定义新节点

        newLinkList = newElement();

        newLinkList->prev = cur;//新节点的前一个是当前临时指针
        newLinkList->number = i;//设置number
        newLinkList->next = 0;//下一个为空

        cur->next = newLinkList;//设置临时指针的下一个是当前节点
        cur = newLinkList;//临时指针指向当前节点
    
    }

    

    cur = &head;

    for(int i = 0 ; i < 10 ; i++ ){
        printf("current dataNumber is %d \n",cur->number);
        cur = cur->next;
    }



    getchar();
}

  这里定义了两种获取链表元素的方法,分别是newElement和newElement2,执行结果应该是将链表内保存的数字从头显示到尾,应该是0~9,newElement是对的,newElement2的输出结果全是10,那么这是为什么呢?这里就要说到程序的调用堆栈了。

  一个函数,在其中定义的变量,都会在其调用栈中进行分配内存,那么当这个函数调用完毕后,调用栈弹栈,这其中的变量就会失效。但是如果你在循环内部反复执行一个方法,并且如用其中的局部变量作为返回值,有时你会发现,居然可以当作全局变量使用,并不是调用结束就被销毁,这是为什么呢?这是因为循环执行速度过快,导致内存尚未被释放而又被再次使用(这是我推测的,大家可以验证一下),而且函数内部变量的内存地址,相对函数的内存地址,位移是在程序启动的时候就确定了。假设方法fun1()的内存地址是0x0001 0000,那么其中的变量内存地址应该是0x0001 0010,他们的差值在本次运行过程中,始终是0x10,在你重复快速的访问状态下,或始终更新这个内存地址内的值,也就导致了newElement2的输出结果最终都是9,因为链表中所有的内容指针,都全部指向了函数中的同一个地址,这个地址内容在循环完成后,变成了10,所以显示结果全部是10.

  而newElement采用new的方式分配内存,就把这个变量内存地址创建在了堆中,这并不会因为函数执行完毕,调用栈弹栈导致变量注销而产生问题。

  这两个方法还有一个本质的区别就是返回值的不同,采用new方法分配内存,每次都是新的内存,而在函数内利用声明直接定义变量,则会产生“静态”的效果。

以上内容,都是本人自己的理解,并不保证完全正确,如果大家发现有什么不对的地方,欢迎指出。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档