C语言中容易出错的几个地方

总结下c语言中值得注意的地方:

1、逗号表达式。

 因为实际开发中应用的不多,所以很多人对这个都容易忽视。

逗号表达式,比赋值运算符优先级还低,结合性为左结合。

例子

#include <stdio.h>

void main()

{

int a=2,b=3,c=4,x,resulta,resultb;

resulta=(x=a+b),(b+c);//resulta=5,x=5

//resulta后面的赋值运算符优先级比,高,所以resulta=5。

resultb=(resulta=(x=a+b),(b+c));//resultb=7,x=5,resulta=5。

//resultb 保存的是整个逗号表示式的值。

printf("resulta = %d,resultb = %d, x=%d/n",resulta,resultb,x);

 

2、关系运算符中的一例

int a=1,b=2,c=2,t;

while(a<b<c){t=a;a=b;b=t;c--}//关系运算符左结合 而不是右结合,可以循环两次

printf("/n%d,%d,%d",a,b,c);//输出1,2,0

 

3、函数(指针参数)

void settozero(int *pvar)

{

    *pvar = 0;

}

//参数传递为指针就可以把原参数的值修改为0了。因为传递的指针是一个变量的地址。

看下面两个例子:

void interchange(int *u ,int *v)

{

  int temp;

 temp = *u;

*u = *v;

*v = temp;

}//可以实现交换*u与*v的值

void interchange(int *u ,int *v)

{

  int *temp;

temp = u;

 u = v;

v  = temp;

}//不能实现值的交换。

注意函数参数实际传递的为实参的副本。如果参数为指针形式,则也不例外,只是传递的指针副本与实际的参数指向的地址空间一样,所以修改指针副本所指向的内存的内容也就算是修改了实参(指针)所指向的内存的内容。效果是一样的。

引申:其实scanf("%d",&num);就用到了这层含义。读取一个数值,然后将其存储到通过参数获得的地址中。

 

4、*p++  等价于 *(p++)     而不是(*p)++;由于*与++的优先级别相同,但是结合性为从右至左。

 

5、函数中绝对不能返回局部变量的地址。

例子 1

long * IncomePlus(long *pPay)

{

 long pay = 0;

 pay  = *pPay + 10000;

return &pay;

}//这样做就不对,因为return的时候pay这个局部变量已经不在IncomePlus函数的作用域内。

例子 2

char * str_in(void)

{

  char buffer[BUFFER_LEN];

 char *pString = NULL;

 if(gets(buffer)  == NULL)

{

   return FALSE;

}

 pString = (char *) malloc( strlen(buffer) +1 );

if (pString == NULL)

{

   abort();

}

return  strcpy(pString , buffer);

}//这样做就可以,但是需要注意内存释放,因为函数内部只是malloc了一块内存,这就需要调用函数来释放内存了。搞不好会内存泄露的。

 

6、注意union类型;其所占内存大小为sizeof(其成员)最大的一个。因为所有成员都共享一块内存。

 

7、函数指针的用法很灵活。

int (*pfun)(int ,int);

typedef  int (*function_pointer) (int ,int); //声明一个函数指针类型

这样就可以function_pointer pfun1;

                   function_pointer pfun2;  假设有函数sum,difference,则可以

                  function_pointer  pfun3 = sum;

                  function_pointer  pfun3 = difference;

 

更有意思的是函数指针做参数:

int sum(int ,int );

int difference(int ,int );

int any_function(int  (*pfun)(int ,int ),int x,int y);

void main()

{

int a = 10;

int b = 5;

int result = 0;

int (*pf)(int ,int ) = sum;

result = any_function(pf,a,b);

printf("reslut  = %d/n",result);

}

int any_function(int (*pfun)(int, int),int x,int y)

{

   return pfun(x,y);

}  

int sum(int x,int y)

{

return x + y;

}

//仔细理解下 就会发现函数指针太灵活太好用太重要了。

还有函数指针数组 例子

int (*pfun[2]) (int ,int ) = { sum,difference };

 

 8、注意long double的sizeof大小;很多书上介绍的都为10,但是我计算机上运行结果为8。可能这个与cpu有关,不同的机器运行结果会不同的。

 

9、结构中的位域

    虽然用的比较少,但是还是值得注意

 struct

{

 unsigned   int  flag1:1;

  unsigned    int  flag2:2;//占2bits,所以范围为0~3

  unsigned    int  flag3:1;

}indic;

sizeof(indic) = ? //4

 

10、指向二维数组的指针常出错的地方

 int  a[4][3] ;

   int *pa = a;//非法,虽然这样写大多时,运行结果也对。但是这样写是不合法的

 int *pa = *a;//合法,这样两边就位于同一个层次了

    int  *pa = a[0];//合法

 int *pa = &a[0][0];//合法

 

11、注意数组指针与指针数组不要搞混淆了

 指针数组:就是指针的数组,数组的元素是指针,如 int *p[2];首先声明了一个数组,数组里的元素是int型的指针。

 数组指针:即指向数组的指针,如 int (*p) [2];声明了一个指针,该指针指向一个有2个int型元素的数组。

 其实这两种写法主要是因为运算符的优先级, 因为[ ]的优先级比*高。所以第一种写法,p先和[ ]结合,所以是一个数组,后与*结合,是指针。后一种写法同理。
    指针数组如下处理就会很清楚:
    typedef int* intPtr;
    intPtr p[2];
    一目了然,所以为了避免迷惑,做适当的typedef也是很有必要的。
    同理,数组指针也可以作类似处理:
    typedef int intArray2[2];
    intArray2 * p;
    和原来的声明都是等价的。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值