编程疑难点

1、事件、消息机制

2、回调、钩子函数


3、二级及多级指针

下面的博文对于理解参数的传递和二级指针有帮助
http://www.cnblogs.com/chinacloud/archive/2011/09/02/2163377.html
自己补充一部分:

void change_val(char *p) 
{ 
printf("fun: address of p : 0x%x\n",p);
char new_val[3] = {2, 3, 4}; // [2] 
p = new_val; //[3] 此处发生参数拷贝,用p_copy代替p,即用p_copy指针指向了new_val,为改变p所指向的值
printf("fun: address of p : 0x%x, content of p: %d \n",p,*p);
return; // [4] 
} 

void change_val2(char *p)
{
printf("fun: address of p : 0x%x, content of p: %d \n",p,*p);
char new_val[3] = {2, 3, 4}; // [2] 
memcpy(p, new_val, 3); //此处未发生参数拷贝,而是内存拷贝
printf("fun: address of p : 0x%x, content of p: %d \n",p,*p);
return;
}
void change_val(char **p)  
{  
    static char new_val[3] = {2, 3, 4}; // [2]  
    * p = new_val;    //*p == *(&q),即&q所指向的值,即q的地址所指向的值,即q本身。
//**p == *q
    return;             // [3]  
}  
char val[3] = {1, 2, 3};  
char *p = val;              // [1]  
change_val(&p);  

ex:
char c = a; //一个字符型变量
char *p; //p是一个指向char类型的指针
p=& c; //现在p里存的是c的地址
char **q; //q是一个二级指针
q=& p; //q里存的是p的地址(p如前所述是个整数,所以p占有内存的一块空间,现在q就是指向这个空间的开始)
printf(“%p”,q); //p的地址
printf(“%p”,*q); //c的地址
printf(“%c”,**q); //a
++++++++++++++++++++++++++++++++++++++++++++++++++++
address | content
0x0010 : a(0x61) | c char c
0x0020 : 0x0010 | p = &c char *p
0x0030 : 0x0020 | q = &p char **q
q: p的地址: 0x0020,即q的内容
*q: q(0x0020)所指向的内容,即p(p的内容),0x0010
**q: *q(0x0010)所指向的内容,即p所指向的内容,即a
指针的值(p)等于数据的存放地址(内存的地址都是一样的,32位机器上都是是4字节长度),那么给指针赋值的时候就需要进行数据的取地址操作:
char * p = & c;
void指针实际上的意思是指向任意类型的指针。任意类型的指针都可以直接赋给void指针,而不需要进行强制转换。
++++++++++++++++++++++++++++++++++++++++++++++++++++
int B[100][100]; //B就是一个int **型的指针

void F(int **p);

你可以这样调用F
F(B);
int * 是指向int类型的指针;
int *,也即(int ) ,是指向int 类型的指针,也就是指向指针的指针;
int ,也即(int ) ,是指向int**类型的指针,也就是指向指针的指针的指针;
struct xxx *,是指向struct xxx类型的指针;
其实,说这么多,只是希望大家在看到指针的时候,不要被int *这样的东西吓到,就像前面说的,指针就是指向某种类型的指针,我们只看最后一个*号,前面的只不过是type类型罢了。


4、函数的形参和实参

http://blog.chinaunix.net/uid-27645052-id-3337748.html
函数在传参过程中,是一个内容的拷贝过程,而每个函数都会有自己的栈空间来存放局部变量,所以,形参和实参是不同的内存单元。通俗点讲,就是,你改变他们其中一个的值,另一个的值不会改变。
传递的参数是个指针的时候,就可以改变实参的值。当传递到形参时,进行指针拷贝,不管指针怎么拷贝,只要操作指针所指向的值,那么实参都会被改变。(形参就是指针所指向的值)。

void change_val(char **p)  
{  
    static char new_val[3] = {2, 3, 4}; 
    *p = new_val;  
    return;             
}  
char val[3] = {1, 2, 3};  
char *p = val;              
change_val(&p); 

p是指针,我现在要改变p所指向的内存的值,那么我应该传入p的地址进行操作。而且需要操作p本身,即操作传入的p的地址所指向的内容,即*p。

void change_val(int *p,int *q)
{
    int temp;

    temp = *p;
    *p = *q; 
    *q = temp;

    return ;
}
int x = 1,y = 2;
fun(&x,&y);

补充:当定义的不是一个指针时(int a;),传给某个函数,而这个函数需要修改传入参数的值,即内容,则应该传入改参数的地址,然后在函数内部去修改传入参数所指向的值。
而当定义一个指针(int *p),传给某个函数,而这个函数需要修改这个指针本身,即p,那么我们应该传入指针本身(p)的地址。

5、4维数组

int cof[a][b][c][d];
cof[e][f][g][h]的地址应是:cof + sizeof(int)* e* b* c* d + sizeof(int)* f* c* d + sizeof(int)* g* d +sizeof(int)*h

如果已经知道了数组的大小,就用
int x[100][100][100][2];
在声明它的头文件用 extern int x[100][100][100][2];
在定义它的.cpp文件中用 int x[100][100][100][2];

C和C++程序员都应该这么写程序。访问速度快,内存占用小。
我们算个帐,用我的办法是100*100*100*2*sizeof(int) 在32位和64位编译器出来是8百万字节;
如果用你的办法是100*100*100个指针,最终的int个数与我的方法相同,前面1百万个指针(32位编译器出来是4百万字节,64位编译器出来是8百万字节,50-100%的overhead, 一下就把内存占用增加了老多。
访问的时候,每个最终的整数要做3次indirection, 对比我的方法的1次indrection. C/C++程序员不可以随便忽略这样的差异。Not without a compelling reason.
如果你确定你就是要用这个方法,代码可以这样写(C代码,当然C++下也没问题)

// user to free the returned pointer
int ****gen_4_dimensional_array()
{
    int i,j,k,l;
    void *p=malloc(100*sizeof(void*));
    for(i=0; i<100; ++i)
    {
         p[i]=malloc(100*sizeof(void*));
         for(j=0; j<100; ++j)
         {
             p[i][j]=malloc(100*sizeof(void*);
             for(k=0; k<100; ++k)
                 p[i][j][k]=malloc(2*sizeof(int));
         }
    }
    return (int****)p;
}

REF: http://bbs.csdn.net/topics/390699241

6、

7、浮点数陷进

问题一:

   double i;
   for(i = 0;i != 10;i+=0.1){
         printf("%.1lf\n",i);

该程序会不停输出,浮点数不是精确存储的,不能直接比较相等
问题二:

if(0.1+0.1+0.1 == 0.3)  
    printf("equal\n");  
else  
    printf("not equal\n");  

0.1+0.1+0.1 != 0.3
产生上述陷阱的原因

实际上,计算机中的所有数据都用二进制表示,包括浮点数。这就导致某些浮点数不能用二进制精确表示,例如0.1(这很容易理解,就像10/3不能被十进制精确表示一样)

进一步地说,浮点数是采用分数+指数来表示的,例如

0.5 = 1/2

0.75 = 1/2 + 1/(2^2)

0.875 = 1/2 + 1/(2^2) + 1/(2^3)

0.1 = 1/(2^4) + 1/(2^5) + 1/(2^8) + …

其中0.1只能无限循环下去,这就意味着0.1在计算机中不能被精确表示,因此产生上述两个陷阱也就很容易理解
REF: http://blog.csdn.net/zhengxu001/article/details/8066039

8、位操作

int value = 0xF;
    int bit_number = 2;

    //将指定位置1;位从右往左,以0开始算;0 =< bit_number <= 位数-1
    value = value | 1 << bit_number;  
    value |= 1 << bit_number;
    //将指定位置1;位从右往左,以1开始算;1 =< bit_number <= 位数
    value = value | bit_number;  

    value = value & ~(1 << bit_number);  //将指定位清0
    value &= ~(1 << bit_number); 
//返回v中1的位数
    int fun(unsigned v)
    {
        int count;
        for(count = 0; v != 0; v >>= 1)
        {
            if(v % 2 != 0)
                count ++;
        }

        return count;
    }

9、函数返回数组

第一种方法:
返回一个指向数组的指针,例如char ( *retArray() )[10]声明了一个函数retArray,该函数可以返回指向具有10个char元素的数组
例子如下:

#include <stdio.h>
#include <stdlib.h>

int (*retArray())[10]
{
    int (*a)[10];  //数组指针,指向数组的指针
    int i=0;
    /*动态开辟空间*/
    a=calloc(10,sizeof(int));  //分配了10个int大小的内存
    /*赋值*/
    for(i=0;i<10;i++)
    {
        (*a)[i]=i;
    }
    return a;

}

int main()
{
    int (*b)[10];
    /*函数返回指向数组的指针*/
    b=retArray();
    /*打印元素*/
    int i;
    for(i=0; i<10; ++i)
        printf("%d \n",(*b)[i]);
    /*释放空间*/
    free(b);
    return 0;
}

第二种方法,使用结构体作为返回值来传递数组:

struct Array
{
    char buf[30];
};

struct Array test(char *tmp)
{
    struct Array a;
    strcpy(a.buf,tmp);

    return a;
}

第三种方法,使用静态变量,返回指针

#include <stdio.h>

/* function to generate and return random numbers */
int * getRandom( )
{
  static int  r[10];
  int i;

  /* set the seed */
  srand( (unsigned)time( NULL ) );
  for ( i = 0; i < 10; ++i)
  {
     r[i] = rand();
     printf( "r[%d] = %d\n", i, r[i]);

  }

  return r;
}

/* main function to call above defined function -by www.yiibai.com/c */
int main ()
{
   /* a pointer to an int */
   int *p;
   int i;

   p = getRandom();
   for ( i = 0; i < 10; i++ )
   {
       printf( "*(p + %d) : %d\n", i, *(p + i));
   }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值