1. 程式人生 > 實用技巧 >C踩坑紀實——(一)

C踩坑紀實——(一)

最近在專案過程中發現了幾個c語言中沒有注意到的小細節,成功入坑。下面記錄的我遇到的問題,以及解決的方法,希望這個過程能給讀者帶來些許啟發。

字元型別變數的溢位

首先來看下面這段程式碼,你認為會輸出什麼呢?

int remain = 129
do{
	char d = remain%128;
	remain /= 128;
	if(remain > 0)
		d |= 0X80;
	*s++ = d;
}while(remain > 0);
printf("str:%x\r\n",*str);

你也許會和我的想法相同,這返回不是81麼?要是一眼就被看出來我也就不會記錄下來了,往往我們定義資料型別時都忽略了2個問題,資料型別的取值範圍與加unsigned與不加的區別,下面就通過這個例子來聊聊這兩點。
先揭曉答案,這段虛擬碼的返回FFFFFF81,為什麼呢? 因為char型別佔1個位元組的大小,其取值範圍為-128~127,1+(-128)=-127,而在計算機中,負數是由補碼錶示,也就是我們看到FFFFFF81,在計算機中表示-127,而81,在計算機中表示正數129,也許還有個疑問,char型別佔1位元組大小,而FFFFFF81佔了4位元組大小,這不是空間溢位了麼? 其實並沒有,當變數是負數時,在計算機中由32位表示,但其所佔的空間記憶體還是一位元組
如果*s的資料型別是unsigned char結果又是什麼呢? 沒錯,這回就真是81了,因為unsigned char的取值範圍為0~255。是不是若有所思呢?下面來檢驗下收穫吧,請看下面程式碼

short int a=1234;
short int *p=&a;
char *q=(char *)p;
char *k=(char *)p+1;
printf("address:%p--%p--%p\n",p,q,k);
printf("value:%x--%x--%x\n",*p,*q,*k);

實驗寫出上面程式碼的輸出結果吧!

二維陣列賦值

二維陣列賦值,你知道幾種方法呢,用for迴圈逐個完成、初始化時完成,使用下面的賦值方式你覺得怎麼樣呢?

char a[100][128];
char *topic = "matt test";

a[0] = topic;

printf("a[0]:%s\r\n",a[0])

上面虛擬碼是個錯誤的例子,因為陣列首地址不可被改變這條規則,所以編譯器不會通過這段程式碼。如果用陣列首地址對陣列賦值,有什麼方便的方法呢? 見下面程式碼

char a[100][128];
char *topic = "matt test";

memset(a,0x0,sizeof(a));
memcpy(a[0],topic,strlen(topic));

printf("a[0]:%s\r\n",a[0])

指標地址變化

C語言中,指標是一大精華,也是一個難點,使用不當容易造成記憶體洩漏,使系統不穩定。若對已初始化但未分配記憶體空間的指標寫值,易造成segmentation fault(段錯誤)。下面指標的地址你清楚麼?

short int a=1234;
short int *p=&a;
char *q=(char *)p;
printf("address:%p--%p--%p--%p\n",p,p+1,q,q+1);

指標地址的變化與指標的的資料型別相關,而在不同作業系統中,資料型別也有所不同,在64位Windows與linux系統中,char與int分別佔1位元組與4位元組記憶體空間,故(P+1)-p為4,(q+1)-q為1.

清風 | 文 【原創】

如果本篇部落格有任何錯誤,請批評指教,不勝感激 !