總結下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;
和原來的聲明都是等價的。