C語言常用技巧和易錯(cuò)題匯總(一)

? 在C語言編程中,有許多高級技巧可以幫助我們更好地解決問題,提高代碼的效率和可維護(hù)性舞竿。在本文中, 本人根據(jù)工作多年的開發(fā)經(jīng)驗(yàn)總結(jié)出平時(shí)容易出錯(cuò)的知識點(diǎn)和一些常用的技巧方法, 使初學(xué)者少走彎路,避開之前走過的坑路,來提高開發(fā)的效率,總結(jié)出問題排查的一些方法掏秩。

1. 關(guān)于變量占位地址大小的問題:

---------------------------例子1-----------------------

(1)以下為Linux下的32位C程序,請計(jì)算sizeof的值荆姆。

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

void Func (char str2[100], int size)

{

printf (" sizeof (str2):%d.\n", sizeof(str2));

}

int main (int argc, char **argv)

{

char str1[] = "hello";

char *p = str1;

int? n = 10;

void *p2 = malloc(100);

char str2[100] = {0};

printf ("\n sizeof(str)=%d. \n", sizeof(str1));

printf (" sizeof(p)=%d.\n", sizeof(p));

printf (" sizeof(n)=%d.\n", sizeof(n));

printf (" sizeof(p2)=%d.\n", sizeof(p2));

Func (str2, 100);

return 0;

}

32位機(jī)器輸出結(jié)果如下:

1) sizeof(str1)= 6 ##字符串5個(gè)字符+一個(gè)結(jié)束符'\0' = 6個(gè)字節(jié)蒙幻;

2) sizeof(p)= 4 ##指針變量,大小固定為4個(gè)字節(jié)胞枕;

3) sizeof(n)= 4 ##int類型杆煞, 大小固定為4個(gè)字節(jié);

4) sizeof(p2)= 4 ##p2也是指針類型,大小為4個(gè)字節(jié)决乎,指向分配的100個(gè)字節(jié)首地址队询;

5) sizeof(str2)= 4 ##str2為形參,也是指針類型构诚,大小固定為4個(gè)字節(jié)蚌斩;

64位機(jī)器輸出結(jié)果如下:

1) sizeof(str1)= 6 ##字符串5個(gè)字符+一個(gè)結(jié)束符'\0' = 6個(gè)字節(jié);

2) sizeof(p)= 8 ##指針變量范嘱,大小固定為8個(gè)字節(jié)送膳;

3) sizeof(n)= 4 ##int類型, 大小固定為4個(gè)字節(jié)丑蛤;

4) sizeof(str2)= 8 ##p2也是指針類型叠聋,大小為4個(gè)字節(jié)

5) sizeof(p2)= 8 ##p2也是指針類型,大小為4個(gè)字節(jié)

---------------------------例子2-----------------------

(2).Linux下的64位C程序打印值是多少受裹?

typedef union

{

long i;

int k[5];

char c;

}Item1;

typedef struct __data{

int? ? cat;

Item1? cow;

double dog;

} Item2;

DATE max;

? ? printf("sizeof item1: %d, sizeof item2: %d.\n", sizeof(Item1), sizeof(Item2));

執(zhí)行結(jié)果:sizeof item1: 24, sizeof item2: 40.

解析:

32位系統(tǒng)一般為4字節(jié)對齊,64位系統(tǒng)一般為8字對齊碌补,所以在64位ubuntu系統(tǒng)下結(jié)果為:

--Item1是union類型,所有成員變量共用地址空間棉饶,要看最大變量所占地址厦章,由于8字節(jié)對齊,

k[5]占20個(gè)字節(jié)照藻,8字節(jié)對齊袜啃,所以為24個(gè)字節(jié);

--Item2是struct 類型幸缕,所有成員地址之和群发,并考慮字節(jié)對齊,所以結(jié)構(gòu)體大小為:

4+4(int8字節(jié)對齊) + 24(union類型) + 8(double類型為8個(gè)字節(jié)) = 40

2. 字節(jié)對齊問題:

1)結(jié)構(gòu)體對齊規(guī)則

<1> 每個(gè)數(shù)據(jù)成員的起始位置必須是自身大小的整數(shù)倍冀值;

<2> 結(jié)構(gòu)體總大小必須是結(jié)構(gòu)體成員中最大的對齊模數(shù)的整數(shù)倍也物;

<3> 結(jié)構(gòu)體包含數(shù)組時(shí)宫屠,按單個(gè)類型對齊方式列疗;

<4> 共用體union取成員的最大內(nèi)存,但包含在結(jié)構(gòu)體內(nèi)時(shí)浪蹂,按union內(nèi)部最大類型字節(jié)數(shù)的整數(shù)倍開始存儲抵栈; 以下均在32位系統(tǒng)默認(rèn)4字節(jié)對齊的情況下測試:

-----------------------------------例子1-----------------------------------

struct item_data1

{

? char? a;

? int? b;

? short c;

};

結(jié)構(gòu)體大小(32位系統(tǒng)):12個(gè)字節(jié)

解析:char占一個(gè)字節(jié)坤次,int占四個(gè)字節(jié)古劲,由于int的起始地址要在4的倍數(shù)上,char后邊補(bǔ)齊3個(gè)字節(jié)缰猴,

shor占兩個(gè)字節(jié)产艾,但是整個(gè)結(jié)構(gòu)體大小要是最大的對齊模數(shù)的整數(shù)倍,即4的倍數(shù),所以補(bǔ)兩個(gè)字節(jié)闷堡,一共12個(gè)字節(jié)隘膘。

-----------------------------------例子2-----------------------------------

struct item_data2

{

char? a;

short c;

int? b;

};

結(jié)構(gòu)體大小(32位系統(tǒng)):8個(gè)字節(jié)杠览;

解析:char占一個(gè)字節(jié)弯菊,short占兩個(gè)字節(jié),由于short的起始地址要在2的倍數(shù)上踱阿,char后邊補(bǔ)齊1個(gè)字節(jié)管钳;

int占四個(gè)字節(jié),剛好在4的倍數(shù)上软舌,所以總共8個(gè)字節(jié)才漆;

-----------------------------------例子3:結(jié)構(gòu)體嵌套結(jié)構(gòu)體-----------------------------------

結(jié)構(gòu)體包含另一個(gè)結(jié)構(gòu)體成員,則被包含的結(jié)構(gòu)體成員要從其原始結(jié)構(gòu)體內(nèi)部的最大對齊模數(shù)的整數(shù)倍地址開始存儲(比如struct a里含有struct b佛点,b中有char栽烂、double 、int 元素恋脚,那么b應(yīng)該從8(double)的整數(shù)倍開始存儲)

struct item_data3

{

char? a;

struct item_data1 b[2];

short c;

};

結(jié)構(gòu)體大邢侔臁(32位系統(tǒng)):32個(gè)字節(jié);

解析: char占一個(gè)字節(jié)糟描,char后邊補(bǔ)齊3個(gè)字節(jié)怀喉;結(jié)構(gòu)體item_data1占12個(gè)字節(jié),2個(gè)成員占24個(gè)字節(jié)船响;

成員c 占2個(gè)字節(jié)躬拢,后邊補(bǔ)齊2個(gè)字節(jié),所以總大小為:4+12*2+4 = 32见间;

-----------------------------------例子4:結(jié)構(gòu)體嵌套u(yù)nion-----------------------------------

結(jié)構(gòu)體包含共用體成員聊闯,則該共用體成員要從其原始共用體內(nèi)部成員中的最大對齊模數(shù)的整數(shù)倍地址開始存儲

struct item_data4

{

char? a;

union x{

char m;

int? n;

}? b;

short c;

};

結(jié)構(gòu)體大小(32位系統(tǒng)):12個(gè)字節(jié)米诉;

解析:?char占一個(gè)字節(jié)菱蔬,char后邊補(bǔ)齊3個(gè)字節(jié);共用體最大為4個(gè)字節(jié)史侣,成員c為short類型拴泌,需要補(bǔ)齊2個(gè)字節(jié); 所以總大小為:4+4+4 = 12惊橱;

-----------------------------------例子5:結(jié)構(gòu)體包含0數(shù)組-----------------------------------

struct byte2

{

? char a;

? short c;

? int b;

? double d[0];

};

結(jié)構(gòu)體大序礁(32位系統(tǒng)):8個(gè)字節(jié);

解析:

長度為0的數(shù)組的作用是為了滿足需要可變長度的結(jié)構(gòu)體税朴,具體用法是在一個(gè)結(jié)構(gòu)體的最后回季,申明一個(gè)長度為0的數(shù)組家制,就可以使得這個(gè)結(jié)構(gòu)體是可變長的。

對于編譯器來說泡一,此時(shí)長度為0的數(shù)組并不占用空間慰丛,因?yàn)閿?shù)組名本身不占空間,它只是一個(gè)偏移量瘾杭,數(shù)組名這個(gè)符號本身代表了一個(gè)不可修改的地址常量诅病。

2) 共同體union對齊規(guī)則

共同體的內(nèi)存除了取最大成員內(nèi)存外,還要保證字節(jié)對齊粥烁。

union byte3

{

char? a[6];

short c[5];

int? b;

};

共同體byte3中最大成員就是short c[5]贤笆,占10個(gè)字節(jié),由于還要保證字節(jié)對齊讨阻,所以是10+2=12芥永;

3) 位域字節(jié)對齊規(guī)則

a. “位域”是把一個(gè)字節(jié)中的二進(jìn)位劃分為幾個(gè)不同的區(qū)域,并說明每個(gè)區(qū)域的位數(shù)钝吮。使用位域的主要目的是壓縮存儲埋涧。 位域列表的形式為: 類型說明符 位域名:位域長度(單位:位 bite)

如:struct bs

? ? ? {

? ? ? ? ? int a:8;

? ? ? ? ? int b:2;

? ? ? ? ? int c:6;

? ? ? } data;

其中位域a占8位,位域b占2位奇瘦,位域c占6位棘催。

b. 位域說明:

<1>. 一個(gè)位域必須存儲在同一個(gè)字節(jié)中,不能跨兩個(gè)字節(jié)耳标。如一個(gè)字節(jié)所蚀及樱空間不夠存放另一位域時(shí),應(yīng)從下一單元起存放該位域次坡。

<2>. 由于位域不允許跨兩個(gè)字節(jié)呼猪,因此位域的長度不能大于一個(gè)字節(jié)(8位)的長度,也就是說不能超過8位二進(jìn)位砸琅。

<3>. 位域可以無位域名宋距,這時(shí)它只用來作填充或調(diào)整位置。無名的位域是不能使用的症脂。例如: int :2

c.位域?qū)R規(guī)則:

1) 如果相鄰位域字段的類型相同谚赎,且其位寬之和小于類型大小,則后面的字段將緊鄰前一個(gè)字段存儲摊腋,直到不能容納為止沸版;

2) 如果相鄰位域字段的類型相同,但其位寬之和大于類型的sizeof大小兴蒸,則后面的字段將從新的存儲單元開始,其偏移量為其類型大小的整數(shù)倍细办;

3) 如果相鄰的位域字段的類型不同橙凳,從新的存儲單元開始蕾殴,偏移量為其類型大小的整數(shù)倍,即不壓縮岛啸;

4) 如果位域字段之間穿插著非位域字段钓觉,則不進(jìn)行壓縮;

5) 整個(gè)結(jié)構(gòu)體的總大小為最寬基本類型成員大小的整數(shù)倍坚踩。

-----------------------------------例子1----------------------------------

例題:

(1)typedef struct? AA

{

? unsigned int b1:5;

? unsigned int b2:5;

? unsigned int b3:5;

? unsigned int b4:5;

? unsigned int b5:5;

}AA;

sizeof(AA)= 4

【解析】參考規(guī)則 1)荡灾。

由于相鄰成員類型相同,unsigned int為4個(gè)字節(jié)瞬铸,b1占5位批幌,b2加上b1的位數(shù)之和為10位,不超過4字節(jié)嗓节,因此b2接著b1繼續(xù)存儲荧缘;

同理b3、b4拦宣、b5的類型相同截粗,位數(shù)之和不超過4字節(jié),因此接著b2繼續(xù)存儲鸵隧,總位數(shù)為25位绸罗。

由于結(jié)構(gòu)體的大小是最寬類型成員的整數(shù)倍,因此25位之后的補(bǔ)0豆瘫,直到補(bǔ)滿4字節(jié)从诲。

-----------------------------------例子2----------------------------------

(2)typedef struct? BB

{

? unsigned int b1:5;

? unsigned int b2:5;

? unsigned int b3:5;

? unsigned int b4:5;

? unsigned int b5:5;

? unsigned int b6:5;

? unsigned int b7:5;

}BB;

sizeof(BB)= 8

【解析】參考規(guī)則 1) 和規(guī)則 2) 。由于相鄰成員類型相同靡羡,unsigned int為 4 個(gè)字節(jié)(32位)系洛,當(dāng)存儲到 b7 時(shí),b7和b6之前的位數(shù)相加超過4字節(jié)略步,因此b7從新的存儲單元開始存儲描扯。即b1~b6 存儲在 第0~29位,第30趟薄、31位補(bǔ)0绽诚,b7從下一個(gè)4字節(jié)存儲單元 開始存儲5位,剩下的補(bǔ)0杭煎。

-----------------------------------例子3----------------------------------

(3)

struct test1

{

? char a:1;

? char :2;

? long b:3;

? char c:2;

};

sizeof(test1)= 12

【解析】

char a:1恩够; //用一個(gè)字節(jié)去存儲

char :2; //空域羡铲。因?yàn)榕c前面的a的類型相同蜂桶,而兩個(gè)位域的位寬相加仍然少于8位,所以依然用1個(gè)字節(jié)表示

long b:3也切; //long類型的位寬是4個(gè)字節(jié)扑媚,與前面的char類型不同腰湾,所以b與a之間偏移4個(gè)字節(jié),它們之間自動補(bǔ)充3個(gè)字節(jié)

char c:2疆股; //因?yàn)閏與b又不同型费坊,以test1中的最長的long類型的位寬進(jìn)行偏移,所以雖然char只用1個(gè)字節(jié)就夠了旬痹,但依然要占4個(gè)字節(jié)附井。

結(jié)構(gòu)體總長以最長的類型位寬做為偏移量,最長的是long型两残,占4位永毅,所以不同類型之間應(yīng)該是4個(gè)字節(jié)的偏移,即test1應(yīng)該是4字節(jié)的整數(shù)倍磕昼。 總共是12字節(jié)卷雕。

3. 指針變量的理解和定義:

1) 一個(gè)整型數(shù)

int a;

例子:

int a = 100;? //定義變量a,其值為100票从;

2)一個(gè)指向整型數(shù)的指針

int *a;

例子:

int val = 100;

a = &val; //a為一個(gè)地址變量漫雕,其值為變量val的內(nèi)存地址;內(nèi)存地址的值為100峰鄙;

3)一個(gè)指向指針的的指針浸间,它指向的指針是指向一個(gè)整型數(shù)

int **a;

例子:

int val = 100;

int *p = &val;

a = &p;? //a為地址變量,其值為指針變量p的地址吟榴,p的值為變量val的地址魁蒜;**a = *(*a) = 100;

4)一個(gè)有10個(gè)整型數(shù)的數(shù)組

int a[10];

例子:

int a[10] = {1,2,3,4,5,6,7,8,9, 0}; //有10個(gè)int類型成員的數(shù)組;

5) 一個(gè)有10個(gè)指針的數(shù)組吩翻,該指針是指向一個(gè)整型數(shù)的兜看。

int *a[10];

例子:

int *p1, *p2, *p3...., *p10;? //定義了10個(gè)整形指針變量;a為10個(gè)指針變量的數(shù)組(相當(dāng)于二維數(shù)組)狭瞎;

a[0] = p1;

a[1] = p2;

......

a[9] = p10;

6) 一個(gè)指向有10個(gè)整型數(shù)數(shù)組的指針

int (*a)[10];

例子:

int array1[10], array2[10], array3[10];?

a = array1;? //a為一個(gè)指針變量细移,指向有10個(gè)成員的一維數(shù)組;(一維數(shù)組指針)

7)一個(gè)返回值為指針的函數(shù):

int *a(int );

例子:

int *a(int value){? ///a本質(zhì)是一個(gè)函數(shù)熊锭,返回值為指針的函數(shù)弧轧;

int? *p = (int *)malloc(4);

*p = value;

return p;

}

8) 一個(gè)指向函數(shù)的指針,該函數(shù)有一個(gè)整型參數(shù)并返回一個(gè)整型數(shù)

int (*a)(int a);

例子:

int function(int val)

{

....

}

a = function;? //a為函數(shù)指針變量碗殷,類型與function函數(shù)一致精绎;

int ret = (*a)(100);? //函數(shù)運(yùn)行;

9) 一個(gè)有10個(gè)指針的數(shù)組锌妻,該指針指向一個(gè)函數(shù)代乃,該函數(shù)有一個(gè)整型參數(shù)并返回一個(gè)整型數(shù)

int (*a[10])(int);

定義了10個(gè)指針函數(shù);

例子:

int func1(int val)

{

....

}

int func2(int val)

{

....

}

a[0] = func1;? ? //a為函數(shù)指針數(shù)組从祝,可以管理多個(gè)同類型(如func1一樣)的函數(shù)襟己;

a[1] = func2;

for(int i=0; i<10; i++)

ret = (*a[i])(100);? //可以使用for循環(huán)進(jìn)行管理引谜,非常方便牍陌;

4. 字符串變量相關(guān)的地址操作:

(1)分析下列程序的結(jié)果:

--------------------例子1-----------------------------------

char *s1 = "AAA";

char s2[] = "BBB";

s1[0] = 'B';? //程序崩潰擎浴;

s2[0] = 'C';

printf ("s1:%s, s2:%s.\n", s1, s2);

【解析】

(1)s1是一個(gè)指針變量,指向一個(gè)常量字符串毒涧,即“AAA”字符串在代碼段贮预,是無法進(jìn)行修改的;

所以s1沒有可寫的內(nèi)存契讲,當(dāng)進(jìn)行賦值時(shí)仿吞,會出現(xiàn)段錯(cuò)誤:Segmentation fault (core dumped);

(2)s2是一個(gè)數(shù)組捡偏,初始化為“BBB”,默認(rèn)已經(jīng)分配了4個(gè)字節(jié)的大小唤冈,所以可以進(jìn)行修改操作:s2[0]='C',沒問題银伟;

--------------------例子2-----------------------------------

void getmemory(char *p)

{

p=(char *)malloc(100):

strcpy(p, “hello world”);

}

int main()

{

char*str=NULL;

getmemory(str);

printf(“str:%s/n”,str);

free(str);

return 0;

}

【解析】

1) 形參中值傳遞你虹,并不會改變原值的數(shù)據(jù)。因?yàn)樵分皇强截愐环輸?shù)據(jù)傳進(jìn)去彤避,修改的值是拷貝的數(shù)據(jù)傅物。

2) 指針作為參數(shù),可以傳值琉预,但無法傳地址董饰;所以指針作為形參,傳遞的是變量的地址圆米,可以看成是指針變量地址的一份拷貝卒暂,函數(shù)返回后并沒有重新指向新的內(nèi)存;仍然為空娄帖;進(jìn)入函數(shù)后也祠,指針重新指向了一塊新分配的內(nèi)存老虫,但地址已經(jīng)改變譬巫;會產(chǎn)生內(nèi)存泄露悍手;

3)如果采用雙重指針對實(shí)現(xiàn)上述功能:

? ? ? ? void getmemory(char **pptr)

{ char *p = NULL;

p=(char *)malloc(100):

strcpy(p, “hello world”);

*pptr = p;? //把p對應(yīng)的地址作為pptr的值傳出

}

int main()

{

char*str=NULL;?

getmemory(&str);? 崭倘、

printf(“str:%s/n”,str);

free(str);

return 0;

}

--------------------例子3-----------------------------------

? char szstr[10] = {0};

? strcpy (szstr,"0123456789");?

? printf ("str:%s.--\n", szstr);

解析:字符串必須要有結(jié)尾符號'\0'惩淳,不然無法識別出來乍惊,所以此程序可能會因?yàn)榈刂吩浇绯霈F(xiàn)打印亂碼濒生;

應(yīng)該定義更大一些的數(shù)組szstr[11]见秤,另外說明下佩耳,strcpy會自動把'\0'一起copy到目的地址遂蛀;

--------------------例子4----------------------------------

? char aa[10] = {0xFF, 0x0, 'a', 'b','c','d'};

? printf ("size: %d, strlen:%d. \n", sizeof(aa), strlen(aa));

【解析】

1)sizeof 計(jì)算變量的實(shí)際大小,所以sizeof(aa) = 10干厚;

2) strlen 原理是遇到‘\0’或0馬上結(jié)束李滴,所以上述strlen(aa) = 1;

--------------------例子5-----------------------------------

? void swap_data( int *p1, *p2)

? {

? int *p;

? *p = *p1;

? *p1 = *p2;

? *p2 = *p;

? }

【解析】

運(yùn)行結(jié)果程序崩潰螃宙,原因是定義的p變量為指針類型,但未有分配地址空間所坯,所以*p = *p1,直接賦值會出錯(cuò)谆扎;

--------------------例子6-----------------------------------

說明以下變量對應(yīng)的地址和值是多少?

#include <stdio.h>

int main()

{

int array[5] = {1, 2, 3, 4, 5};

printf("array = %p, value:%d.\n", array, *(array));

printf("array + 1 = %p, value:%d.\n", array + 1, *(array+1)));

printf("array + 2 = %p, value:%d.\n", array + 2, *(array+2)));

printf("array + 3 = %p, value:%d.\n", array + 3, *(array+3)));

printf("&array = %p\n", &array);

printf("&array + 1 = %p\n", &array + 1);

printf ("sizeof(array):%d, sizeof(&array):%d.\n", sizeof(array), sizeof(&array));

int *ptr = (int *)(&array + 1);

printf ("*(array+1)=%d, *(ptr-1)=%d \n", *(array+1), *(ptr-1));

return 0;

}

【解析】(輸出結(jié)果):

array = 0x7ffe96cce190, value:1. //以為e190結(jié)尾的地址芹助;

array+1 = 0x7ffe96cce194, value:2. //以為e190+4結(jié)尾的地址堂湖;

array+2 = 0x7ffe96cce198, value:3. //以為e190+8結(jié)尾的地址;

array+3 = 0x7ffe96cce19c, value:4. //以為e190+12結(jié)尾的地址状土;

&array = 0x7ffe96cce190 //以為e190結(jié)尾的地址

&array + 1 = 0x7ffe96cce1a4

//!!重點(diǎn):以為e190+20結(jié)尾的地址,其中20整個(gè)數(shù)組的長度大小无蜂。

所以,&array + 1 表示:以整個(gè)數(shù)組大小為單位進(jìn)行計(jì)算操作的蒙谓;

sizeof(array):20, sizeof(&array):8.

//array是一個(gè)數(shù)組變量斥季,大小為數(shù)組長度;&array是一個(gè)指針變量累驮,大小為8個(gè)字節(jié)(64位系統(tǒng))

*(array+1)=2, *(ptr-1)=5

//這里注意ptr地址是array+sizeof(array), 所以ptr-1就是指向最后一個(gè)數(shù)據(jù)地址酣倾,址為5;

5. 指針與地址轉(zhuǎn)換問題:

--------------------例子1 ---------------------------

? unsigned char *p1 = NULL;

? ? ? unsigned long *p2 = NULL;

? ? ? unsigned int? address = 0x0801000;

? ? ? p1 = (unsigned char *)address;

? ? ? p2 = (unsigned long *)address;

? ? ? printf ("p1+1: %p, p2+1:%p.\n", p1+1, p2+1);

? ? ? printf ("p1+5: %p, p2+5:%p.\n", p1+5, p2+5);

請說明下打印結(jié)果的慰照。

【結(jié)果】

p1+1: 0x801001, p2+1:0x801008. //char類型占一個(gè)字節(jié)灶挟, long類型占8個(gè)字節(jié);

p1+5: 0x801005, p2+5:0x801028.

【解析】

定義不能類型的指針毒租,在進(jìn)行加減運(yùn)算時(shí)會按指針類型的字節(jié)數(shù)進(jìn)行操作稚铣。

- -------------------例子2---------------------------

int array [5] = {1,2,3,4,5};

int *ptr = (int *)(&array? + 1);

printf ("%d, %d \n", *(array +1), *(ptr-1));

【結(jié)果】?2, 5

【解析】?&array + 1 表示:以整個(gè)數(shù)組大小為單位進(jìn)行計(jì)算操作的;

所以ptr指向地址為:array +sizeof(array ) = array +5墅垮,那么 *(ptr-1)即為array [4]的值 惕医;

-------------------例子3-----------------------------

void foo(void)

{

unsigned int a = 6;

int b = -20;

(a+b > 6) ? puts("> 6") : puts("<= 6");

}

【結(jié)果】這個(gè)問題測試你是否懂得C語言中的整數(shù)自動轉(zhuǎn)換原則。這無符號整型問題的答案是輸出是 ">6"算色。

【解析】?是當(dāng)表達(dá)式中存在有符號類型和無符號類型時(shí)所有的操作數(shù)都自動轉(zhuǎn)換為無符號類型抬伺。

因此-20變成了一個(gè)非常大的正整數(shù),所以該表達(dá)式計(jì)算出的結(jié)果大于6灾梦。

這一點(diǎn)對于應(yīng)當(dāng)頻繁用到無符號數(shù)據(jù)類型的嵌入式系統(tǒng)來說是豐常重要的峡钓。

---------------------例子4 -------------------------------

1)如何把地址為 0x100000的內(nèi)存,賦值為0x1234;

2)如何跳轉(zhuǎn)到地址為 0x100000的函數(shù)若河,并運(yùn)行能岩;

【解析】

1)(unsigned int*)0x100000 = 0x1234;

2)步驟如下:

---首先要將0x100000強(qiáng)制轉(zhuǎn)換成函數(shù)指針即: (void(*)())0x100000

---然后再調(diào)用它: *( (void(*)())0x100000) ();

6. 變量自加的問題:

--------------------例子1 ---------------------------

#include <stdio.h>

int main

{

int a,b,c,d;

a=10;

b=a++;? ? ? //1. a先把值賦給b,然后自加萧福;所以:b=10,a=11;

c=++a; //2. a先自加后拉鹃,再把值賦給C; 所以:a=12,c=12;

d=10*a++; //3. a先乘以10賦給d, 然后a自加;所以:a=13, d=120;

printf("a, b,c膏燕,d: %a, %d,%d,%d", b, c,d);

return 0;

}

【結(jié)果】a=13, b=10钥屈,c=12,d=120

--------------------例子2 ---------------------------

int a = 5, b = 7, c, d;c = a+++b;

分析:重點(diǎn)是理解運(yùn)算的優(yōu)先級坝辫,++ 優(yōu)先級高于+篷就,所以先進(jìn)行a++運(yùn)算,再進(jìn)行+運(yùn)算阀溶;

可看成:c = a++ + b;

【答案】這段代碼持行后a = 6, b = 7, c = 12

---------------------例子3 -------------------------------

代碼如下:

? int b=10;

? ? printf("1-----(b++, b++): (%d, %d)\n", b++,b++);

? ? b=10;

? ? printf("2-----(++b, ++b): (%d, %d)\n", ++b,++b);

? ? b=10;

? ? printf("3-----(b++, ++b): (%d, %d)\n", b++,++b);

? ? b=10;

? ? printf("4-----(++b, b++): (%d, %d)\n", ++b,b++);

【結(jié)果】

1-----(b++, b++): (11, 10)

2-----(++b, ++b): (12, 12)

3-----(b++, ++b): (11, 12)

4-----(++b, b++): (12, 10)

【解析】printf函數(shù)參數(shù)中的變量是經(jīng)過壓棧和出棧操作的腻脏,參數(shù)中括號內(nèi)的表達(dá)式是從右向左執(zhí)行的鸦泳,輸出結(jié)果是從左向右的:

1. 先執(zhí)行右邊的b++银锻,因?yàn)閎++是先賦值保存,后++做鹰,所以cpu會記住b的值(即右邊打印值已經(jīng)確定即為10)击纬,之后再執(zhí)行左邊的b++,此時(shí) b為11(執(zhí)行前面b++得到的結(jié)果)钾麸,因?yàn)橛抑?+更振,因此就輸出為11,所以結(jié)果為11饭尝, 10肯腕;

2. 先執(zhí)行右邊的++b,因?yàn)?+b先自加钥平,再調(diào)用实撒,而此時(shí)cpu并沒有到調(diào)用它的時(shí)候,printf第二個(gè)格式化的值對應(yīng)的數(shù)字現(xiàn)在還不確定涉瘾, 再然后執(zhí)行++b知态,同樣先自加,再調(diào)用的左值運(yùn)算立叛,即輸出12负敏,接著再輸出第二個(gè),因?yàn)閏pu沒有記住對第二的調(diào)用秘蛇,他會找當(dāng)前b的值其做,當(dāng)前b的值是12,所以輸出12, 12赁还;

3. 先執(zhí)行右邊的++b妖泄,之后b=11,同樣秽浇,第二個(gè)打印參數(shù)未確定浮庐,再執(zhí)行b++,因?yàn)閎++是先調(diào)用,再自加审残,所以先輸出b梭域,此時(shí)b的值是11,再自加搅轿,b=12病涨,此時(shí)再輸出b,因此輸出的結(jié)果是11,12璧坟;

4. 同理分析既穆,右邊的b++先執(zhí)行,由于是右值運(yùn)算雀鹃,此時(shí)第二個(gè)打印值 已經(jīng)確定幻工,保存下來了,即為10黎茎, 再進(jìn)行左邊的++b運(yùn)算囊颅,打印值為12,即得為:12傅瞻, 10踢代。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市嗅骄,隨后出現(xiàn)的幾起案子胳挎,更是在濱河造成了極大的恐慌,老刑警劉巖溺森,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慕爬,死亡現(xiàn)場離奇詭異,居然都是意外死亡儿惫,警方通過查閱死者的電腦和手機(jī)澡罚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肾请,“玉大人留搔,你說我怎么就攤上這事☆跆” “怎么了隔显?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長饵逐。 經(jīng)常有香客問我括眠,道長,這世上最難降的妖魔是什么倍权? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任掷豺,我火速辦了婚禮捞烟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘当船。我一直安慰自己题画,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布德频。 她就那樣靜靜地躺著苍息,像睡著了一般。 火紅的嫁衣襯著肌膚如雪壹置。 梳的紋絲不亂的頭發(fā)上竞思,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天,我揣著相機(jī)與錄音钞护,去河邊找鬼盖喷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛患亿,可吹牛的內(nèi)容都是我干的传蹈。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼步藕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了挑格?” 一聲冷哼從身側(cè)響起咙冗,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎漂彤,沒想到半個(gè)月后雾消,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡挫望,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年立润,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片媳板。...
    茶點(diǎn)故事閱讀 38,654評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡桑腮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蛉幸,到底是詐尸還是另有隱情破讨,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布奕纫,位于F島的核電站提陶,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏匹层。R本人自食惡果不足惜隙笆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧撑柔,春花似錦煤率、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至辆沦,卻和暖如春昼捍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肢扯。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工妒茬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蔚晨。 一個(gè)月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓乍钻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親铭腕。 傳聞我的和親對象是個(gè)殘疾皇子银择,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容