Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2373912
  • 博文数量: 298
  • 博客积分: 7876
  • 博客等级: 准将
  • 技术积分: 5500
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-23 13:39
文章存档

2013年(2)

2012年(142)

2011年(154)

分类: C/C++

2011-04-27 11:56:17

C语言易错点(指针和形参传递)

 

1.       零值比较

一般意义上的零值有布尔型,整型,指针,浮点型。

(1)             布尔型:C语言里面没有布尔类型,但是C99标准提供了一个库来表示,头文件为,其表示为bool mybool = true;注意都是小写,其实在C语言windows里面也定义了一个BOOL来区别于C++bool

1)         #include

2)          

3)         int main(void)

4)         {

5)                  bool mybool = true;

6)                  if(mybool)

7)                            printf("mybool is true\n");

8)                  else

9)                            printf("mybool is false\n");

10)          printf("c bool size is %d\n", sizeof(mybool));

11)               return 0;

12)      }

结果为:

mybool is true

c bool size is 4

请按任意键继续. . .

 

注意和C++的布尔型的区别,C语言里面的布尔型是用整数来代替的,零是假,任何非零的值为真,C++的布尔型是一个一个字节的变量。

1)         //#include

2)         #include

 

3)         using namespace std;

 

4)         int main(void)

5)         {

6)         bool mybool = true;

7)         if(mybool)

8)         cout<<"mybool is true"<

9)         else

10)      cout<<"mybool is false"<

11)      cout<<"c++ bool size is "<

12)      return 0;

13)      }

结果为:

mybool is true

c++ bool size is 1

请按任意键继续. . .

(2)             整型:同类bool型用法一样 int test = 0;

if(test){

}

else{

}

(3)             指针:指针的零值为空指针NULL int *ptest = NULL;

if(test == NULL){

}

else{

}

 

(4)             浮点型:浮点型的数据与零值比较不是直接测试与零是否相等,而是测试是否在0值左右的一个范围内。

if(fabs(flag2) < 1e-5)

        printf("flag2 is 0\n");

    else

        printf("flsg2 is not 0\n");

 

2.       函数形参传递

1Strcpy函数的实现:

char *mystrcpy(char *des, const char *sur)

{

char *p = des;

assert((des !=NULL ) && (sur != NULL));

while((*des++=*sur++) != '\0')

;

return p;

}

2)示例1

1)       void getmemory1(char *p)

2)       {

3)       p = (char *)malloc(100);

4)       }

 

5)       void test1(void)

6)       {

7)       char *str = NULL;

8)       getmemory1(str);

9)       strcpy(str, "hello world1 \n");

10)    printf(str);

11)      }

由于传入函数getmemory1的参数为指针,编译器为其准备一个副本_p传入,存在在系统栈里面,我们在getmemory1函数里面,为其动态分配空间存在于堆上,但是里面使用的是p的副本,分配空间的头指针指向的是_p,而不是p,所有该函数结束时p的值仍然没有改变,这里函数结束后不会把分配的空间释放掉,因为其分配的空间在堆上,如果程序员不释放的话其空间要在程序结束后由操作系统收回。测试函数使用未改变的的指针,其值为NULL,所有会出错。

 

3)示例2

1)       char* getmemory2(void)

2)       {

3)       char p[] = "hello world2 \n";//在栈上

4)       return p;

5)       }

 

6)       void test2(void)

7)       {

8)       char *str = NULL;

9)       str = getmemory2();

10)    printf(str);

11)      }

由于函数getmemory2在内部使用了char p[] = "hello world2 \n"; 所有我们这里说一下他和

char  *p1 = "hello world2 \n";的区别,首先char p[] = "hello world2 \n"都是存放在栈上的,函数执行完会自动释放,而char  *p1 = "hello world2 \n";却不一样,char  *p1存放在栈上这与前面一样,但是"hello world2 \n"却是存放在常量区的,程序结束后由系统释放 ,而且char p[]是一个数组名,为常量,而char  *p1不是,在getmemory2函数中,char p[] = "hello world2 \n"都是存放在栈上的,函数作用范围结束后会自动释放,所以,即使返回了p指针,我们打印出来的字符串也是乱码但是如果将函数内部char p[] = "hello world2 \n"改变为char  *p1 = "hello world2 \n",则不会出错,程序代码如下:

1)         char* getmemory2(void)

2)         {

3)         char *p1= "hello world2 \n";

4)         return p1;

5)         }

 

6)         void test2(void)

7)         {

8)         char *str = NULL;

9)         str = getmemory2();

10)      printf(str);

11)      }

从这里我们可以认为,char p[] = "hello world2 \n"是一个字符型数组,p为数组名不可以改变,而char  *p1 = "hello world2 \n"是指针指向的字符串常量,p1为可变指针,而字符串常量存在常量区。

(4)外传:字符串常量,我们可以知道"hello world2 \n"是一个字符串常量,并将第一个值的位置给一个指针p1,我们来看一下下面的表达式:

"hello world2 \n"+1

其实我咋一看,感觉这表达式没什么意义,在看了C和指针才知道,其实这个也是很有意思的,

"hello world2 \n"+1指向的是字符串常量的第二个字符,这样我们干脆就把它当成一个指针来看,这样下面的表达式也就有了意义

*"hello world2 \n"

这个表达式很明显的意思就是取字符串常量的第一个字符,依次我们可以进行的运算就可以知道如

"hello world2 \n"[3]; //等效于*("hello world2 \n"+3)

注意:由于字符串常量位于常量区,他的生命周期是恒定不变的,而且由于是常量,它不允许改变它的值,是只读的。

5)示例3

1)         void getmemory3(char **p, int num)

2)         {

3)         *p = (char *)malloc(num);

4)         }

 

5)         void test3(void)

6)         {

7)         char *str = NULL;

8)         int num = 100;

9)         getmemory3(&str,num);

10)      printf(str);

11)      }

这次这个示例可能有点难懂了,传入函数getmemory3可以说是指针的指针,假设这里编译器为其准备的副本为__p,那么*__p即是指向char类型的指针,那么我们可以像平常那样对其动态分配空间,你可能会有疑问,为什么这里可以为他动态分配呢,虽然编译值指定__p = p;

但是他们指向的地址都是同一个,*__p =  *p,分配空间后的头指针付给*__P 相当于赋给了*p,但是最好不要用这个方法分配空间。

 

注意:释放分配的空间后将指针设置为NULL,避免形成野指针。

 

6)示例4

1)         char* getmemory3(void)

2)         {

3)         char *p = (char *)malloc(100);

4)         printf("len is %d \n",strlen(mystrcpy(p, "hello mywold3")));

5)         return p;

6)         }

 

7)         void test3(void)

8)         {

9)         char *str = NULL;

10)      str = getmemory3();

11)      printf(str);

12)      }

getmemory3函数里面,char *p = (char *)malloc(100);分配空间,虽然指针p存在于系统栈在函数结束后将消亡,但是分配的空间存在于堆不会,返回分配的首指针,使该动态分配的区域有指针指向,置于可用状态。

 

3.       指针

 

我们这里直接通过下面一段代码来讲解:

char ch[7]="13579";

    char cr = 'm';

    char *cp = &cr;

    printf(" &cr is %0x\n", &cr);//取cr变量的地址,也就是m存储的位置

    printf(" cp is %0x\n", cp);/变量赋值的时候就是为m存储的位置

    printf(" &cp is %0x\n", &cp);//取cp的地址

    printf(" *cp is %c\n", *cp);//从存储m的位置,取出m

    cp = ch;

    printf(" *cp+1 is %c\n", *cp+1);//从存储m的位置,取出m并将m的值加‘*’优先级高

    printf(" *(cp+1) is %c\n", *(cp+1));//地址cp加单位字节,然后取出+1地址的内容

    printf(" cp is %0x\n", cp)

    printf(" ++cp is %0x\n", ++cp);//地址cp先加单位字节再使用

    printf(" cp is %0x\n", cp);

    printf(" cp++ is %0x\n", cp++);//地址cp先使用再加单位字节

    printf(" *cp is %c\n", *cp);

    printf(" *++cp is %c\n", *++cp);//*,++优先级相同,自右向左,先指针加1再取内容

    printf(" *cp is %c\n", *cp);

    printf(" *cp++ is %c\n", *cp++);//*,++优先级相同,自右向左,先取内容再指针加1

//其实这里挺奇怪的 两者优先级相同,且是从右向左,那就应该是先++,但是我们这里可以这//样认为两者操作符没有挨着,所有遵循从左到右,先取值,再指针+1

    printf(" *cp is %c\n", *cp);

    printf(" ++*cp is %c\n", ++*cp);// *,++优先级相同,自右向左,先取内容再内容加1

 

 

阅读(6015) | 评论(2) | 转发(4) |
给主人留下些什么吧!~~

g_programming2011-08-10 10:09:15

tobyzone: 看起来难度蛮大的.....
我就是瞎写。。。

tobyzone2011-08-09 09:55:38

看起来难度蛮大的