如何攻破C語言學(xué)習(xí)、筆試與機試的難點_第1頁
如何攻破C語言學(xué)習(xí)、筆試與機試的難點_第2頁
如何攻破C語言學(xué)習(xí)、筆試與機試的難點_第3頁
如何攻破C語言學(xué)習(xí)、筆試與機試的難點_第4頁
已閱讀5頁,還剩98頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

C語言編程中的幾個基本概念#includev>與#include””#include0和#include'"'有什么區(qū)別?這個題目考查大家的基礎(chǔ)能力,#include<>用來包含開發(fā)環(huán)境提供的庫,#include”"用來包含.c/.cpp文件所在目錄下的頭文件。注意:有些開發(fā)環(huán)境可以在當(dāng)前目錄下面自動收索(包含子目錄),有些開發(fā)環(huán)境需要指定明確的文件路徑名。switch()1.switch(c)語句中c可以是int,long,char,float,unsignedint類型?其實這個題H很基礎(chǔ),c應(yīng)該是整型或者可以隱式轉(zhuǎn)換為整型的數(shù)據(jù),很明顯不能是實型(float、double)。所以這個命題是錯誤的。constl. 8nst有什么用途?雖然const很常用,但是我相信有很多人仍然答不上來。(1)欲阻止一個變量被改變,可以使用const關(guān)鍵字。在定義該const變量時,通常需要對它進行初始化,因為以后就沒有機會再去改變它了;(2)對指針來說,可以指定指針本身為const,也可以指定指針?biāo)傅臄?shù)據(jù)為const,或二者同時指定為const;(3)在一個函數(shù)聲明中,const可以修飾形參,表明它是一個輸入?yún)?shù),在函數(shù)內(nèi)部不能改變其值;(4)對于類的成員函數(shù),若指定其為const類型,則表明其是一個常函數(shù),不能修改類的成員變量;

(5)對于類的成員函數(shù),有時候必須指定其返回值為const類型,以使得其返回值不為“左值”。#ifndef/#define/#endif1.頭文件中的#ifndef/#define/#endif干什么用?其實#ifndef、#define,#endif這些在u-boot、linux內(nèi)核文件中經(jīng)常見到,在這么大型的程序中大量使用,可見它的作用不可小覷。這些條件預(yù)編譯多用于對代碼的編譯控制,增加代碼的可裁剪性,通過宏定義可以輕松的對代碼進行裁剪。#ifndef/#define/#endif最主要的作用是防止頭文件被重復(fù)定義。全局變■和局部變?nèi)肿兞亢途植孔兞吭趦?nèi)存中是否有區(qū)別?如果有,是什么區(qū)別?全局變量儲存在靜態(tài)數(shù)據(jù)庫,局部變量在堆棧。其實,由于計算機沒有通用數(shù)據(jù)寄存器,則函數(shù)的參數(shù)、局部變量和返I可值只能保存在堆棧中。提示:局部變量太大可能導(dǎo)致棧溢出,所以建議把較大數(shù)組放在main函數(shù)外,防止產(chǎn)生棧溢出。思考:如程序清單1.1所示。會出現(xiàn)怎樣的情況?程序清單1.1大數(shù)組放在main函數(shù)中導(dǎo)致堆棧溢出intmain(intargc,char*argv[])(intiArray[1024*1024];return0;第:節(jié)數(shù)據(jù)存儲與變量2.1變量的聲明與定義如程序清單2.1所示會不會報錯?為什么?如果不會報錯,又是輸出什么結(jié)果?程序清單2.1變量的聲明與定義#include<stdio.h>staticinta;staticintb[];intmain(intargc,char*argv[])(printf("%d%d\nM,a,b[0]);return0;staticint a=8;staticint b[4] ;這個程序是不會報錯的,并且連警告都不會出現(xiàn)。輸出的結(jié)果是:80staticinta,這句程序是聲明全局變量a;staticintb□,這句程序是聲明全局數(shù)組變量b,并且是不完全聲明,也就組下標(biāo)。staticinta=8,這里才是定義全局變量a,staticintb[4],這里是定義全局變量b?局部變量與全局變■的較■請問如程序清單2.2所示輸出什么?程序清單2.2局部變量與全局變量#include<stdio.h>staticinta=8;intmain(intargc,char*argv[])printf(n%d\nM,a);return0;)C語言規(guī)定,局部變量在自己的可見范圍內(nèi)會“擋住”同名的全局變量,讓同名的全局變量臨時不可見。即在J見范圍內(nèi)不能訪問同名的全局變量。因此本程序輸出為:4。char、int、float、double的數(shù)據(jù)存儲請問如程序清單2.3所示,i和j輸出什么?程序清單2.3數(shù)據(jù)存儲floati=3;intj=*(int*)(&i);printf(ni=%f\nM,i);printf(0j=%#x\nn,j);i是毋庸置疑是:3.000000。但是j呢?3.000000?答案是否定的,j是輸出:0x40400000.有人會問了,難道j瞎說,j輸出0x40400000是有依據(jù),是一個定值!由于i是float數(shù)據(jù)類型,而j是int數(shù)據(jù)類型。理論上說,j是取了i的地址然后再去地址,應(yīng)該得到的就是ifr問題的關(guān)鍵就是float數(shù)據(jù)類型的存儲方式和int數(shù)據(jù)類型不一樣,float是占用4個字節(jié)(32位),但是float存儲數(shù)法存儲,最高位是存儲數(shù)符(負數(shù)的數(shù)符是0,正數(shù)的數(shù)符是1);接下來8位是存儲階碼;剩下的23位是存儲局i=3.000000,那么3.000000(10進制)=11(2進制)=<v:shapeid=_x0000J1027style="WlDTH:40.5pt;HEKequationxml='121.1^<2Vtype="#_x0000_t75">(二進制)。數(shù)據(jù)在電腦中存儲都是二進制,這個應(yīng)該都沒這里的數(shù)符為:0,階碼為:E-127=1,那么階碼為:E=128即為:10000000(2進制),尾數(shù)為:1000000000000。那么存儲形式就是:01000000010000000000000000000000o這個數(shù)據(jù)轉(zhuǎn)換成16進制就是(圖2.1數(shù)據(jù)存儲方式char、int、float,double的存儲方式如圖2.l所示。提問:如果i=-3.5的話,請問j輸出多少?i=-3.500000j=0xc0600000這個希望讀者自行分析。再問:如果如程序清單2.4所示。程序清單2.4數(shù)據(jù)存儲doublei=3;intj=*(int*)(&i);printf("i=%lf\nn,i);printf(nj=%#x\nn,j);這樣的話,j又輸出多少呢?提示:double(8個字節(jié)(64位))的存儲方式是:最高位存儲數(shù)符,接下來11位存儲階碼,剩下52位存儲尾數(shù)是不是得不到你想要的結(jié)果?double是8個字節(jié),int是4個字節(jié)。一定別忘記了這個。用這個方法也同時可以馬式!容易忽略char的范圍如程序清單2.5所示,假設(shè)&b=0x12ff54,請問三個輸出分別為多少?程序清單2.5char的范圍unsignedintb=0xl2ff60;printf(n((int)(&b)+1) =%#x\nn,((int)(&b)+1) );printf(n*((int*)((int)(&b)+1))=%#x\nn,*((int*)((int)(&b)+1)) );printf(n*((char*)((int)(&b)+1))=%#x\nH,*((char*)((int)(&b)+1)));很顯然,&b是取無符號整型b變量的地址,那么(int)(&b)是強制轉(zhuǎn)換為整型變量,那么力口1即為0x12ff54+1=(以((int)(&b)+1)^0x12ff55o圖2.3指針加1取字符型數(shù)據(jù)由于((int)(&b)+1)是整型數(shù)據(jù)類型,通過(足*)(。明(&功+1)轉(zhuǎn)化為了整型指針類型,說明要占4個字節(jié),即:0x12ff56、0x12ff57,0x12ff58,再去地址*((int*)((int)(&b)+1))得到存儲在這4個字節(jié)中的數(shù)據(jù)。但是很遺我們并不知道存儲的是什么,所以我們只能寫出0x**0012ff。**表示存儲在0x12ff58中的數(shù)據(jù)。如圖2.2所示。圖2.2指針加1取整型數(shù)據(jù)以此類推,*((char*)((int)(&b)+1))=Oxff.如圖2.3所示。但是,*((char*)((int)(&b)+1))輸出的卻是:Oxffffffff!問題出現(xiàn)了,為什么*((char*)((int)(&b)+1))不是Oxff,而是Oxffffffff?char型數(shù)據(jù)應(yīng)該占用1個字節(jié),為什ffffff?使用%d輸出,printf(n*((char*)((int)(&b)+1))=%d\nH,★((char*)((int)(&b)+1)));結(jié)果為?1???問題出在signedchar的范圍是:?128?127,這樣肯定無法儲存Oxff,出現(xiàn)溢出。所以將printf(n*((char*)((int)(&b)+1))=%#x\nM,★((char*)((int)(&b)+1)));改成printf(n*((unsignedchar*)((int)(&b)+1))=%#x\n”,*((unsignedchar*)((int)(&b)+1)));就可以輸出Oxff,因為unsignedchar的范圍是:0?255(0xff)。

1.iDa(34.04KB,卜,載次數(shù):23)圖2.1數(shù)據(jù)存儲方式char||||||||-|8位(1個字節(jié))Mllllllllllllllllllllllllll「ET32位(4個字節(jié))X:由畫皿皿畫面面工版位"字節(jié))double:||1I位| 52位 |:64位(8個字節(jié))符號位階碼位 尾數(shù)2.ipg(25.49KB,卜載次數(shù):20)圖2.2指針加1取整型數(shù)據(jù)int4個字節(jié)int4個字節(jié)3.ipa(17.13KB.下載次數(shù):17)圖2.3指針加1取字符型數(shù)據(jù)第三節(jié)數(shù)學(xué)算法解決C語言問題3.1N!結(jié)果中0的個數(shù)1. 99!結(jié)果中后面有多少個0?誰跟你說過高數(shù)沒用?數(shù)學(xué)是C語言的支撐,沒有數(shù)學(xué)建模的支撐就沒有那么經(jīng)典的C語言算法!如果你能一個一個乘出來我算你狠!我也佩服你!0也就意味著乘積是10的倍數(shù),有10的地方就有5.有5就不擔(dān)心沒2.10以內(nèi)能被5整除的只有5,但是能被2整除多的去了。所以就簡化成了這個數(shù)只要有一個因子5就一定對應(yīng)一個0.所以可以得出下面結(jié)論:當(dāng)0<n<5時,f(n!)=0;當(dāng)n>=5時,f(n!)=k+f(k!),其中k=n/5(取整)。如程序清單3.1所示。程序清單3.1求N!中0的個數(shù)#include<stdio.h>intfun(intiValue)(intiSum=0;while(iValue/5!=0)(iSum+=(iValue/5);iValue/=5;}returniSum;)intmain(intargc,char*argv[])(intiNumberziZoreNumber;scanf("%d",&iNumber);iZoreNumber=fun(iNumber);printf(n%d\nn,iZoreNumber);return0;)所以99!后面有多少個0的答案是:99/5=19,19/5=3;3/5=0.也就是:19+3+0=22.這里延伸為N!呢,一樣的,萬變不離其宗!3.2N!結(jié)果中的位數(shù)1.請問N!結(jié)果中有幾位數(shù)?數(shù)學(xué)!還是數(shù)學(xué),數(shù)學(xué)真的博大精深,如果大學(xué)沒有好好學(xué)數(shù)學(xué),會成為你一輩子的遺憾。我們先假設(shè):N!=10*A,我們知道10*ri0*2(不含10~2)之間是2位數(shù),10.2~1。3(不含1(T3)之間是3位數(shù),以此類推,(A+1)(不含10、(A+1))則是(A+1)位數(shù),那就是說,我們只要求出A,即可知道N!有幾位數(shù)。A=loglO(N!),N!=1*2*3 *N,那么A=Iogl0(l)+logl0(2)+ +loglO(N).這樣好計算了吧!程序如程序清單6.2所示。程序清單6.2求N!結(jié)果中的位數(shù)#include<stdio.h>#include<math.h>intmain(intargczchar*argv[]){intiNumberzi=0;doublesum=0;printf("請輸入iNumber:n);scanf(n%dn,&iNumber);for(i=1;i<(iNumber+1);i++){sum+=loglO(i);}printf(nN!有告d位\n”,(int)sum+1);return0;我們看下調(diào)試結(jié)果:請輸入iNumber:10N!有7位請按任意鍵繼續(xù)...第四節(jié)關(guān)鍵字、運算符與語句1.1static1. 如程序清單4.1所示,請問輸出i、j的結(jié)果?程序清單4.1static#include<stdio.h>staticintj;voidfuni(void)(staticinti=0;i++;printf(Mi=%d",i);voidfun2(void){j=0;j++;printf(Mj=%d\nMzj);)intmain(intargc,char*argv[])(intk=0;for(k=0;k<10;k++){funl();fur)2();printf(M\nn);}return0;}答案:i=1 j=1i=2 j=1TOC\o"1-5"\h\zi = 3 j = 1i = 4 j = 1i = 5 j = 1i = 6 j = 1i = 7 j = 1i = 8 j = 1i = 9 j = 1i=10j=1請按任意鍵繼續(xù)...很多人傻了,為什么呢?是啊,為什么呢?!由于被static修飾的變量總存在內(nèi)存靜態(tài)區(qū),所以運行這個函數(shù)結(jié)束,這個靜態(tài)變量的值也不會被銷毀,函數(shù)候仍然能使用這個值。有人就問啊,為什么j一直是1啊。因為每次調(diào)用fun2()這個函數(shù),j都被強行置。了。static的作用:(1)函數(shù)體內(nèi)static變量的作用范圍為該函數(shù)體,不同于auto變量,該變量的內(nèi)存只被分配一次,因此其4時仍維持上次的值;(2)在模塊內(nèi)的static全局變量可以被模塊內(nèi)所用函數(shù)訪問,但不能被模塊外其它函數(shù)訪問;(3)在模塊內(nèi)的static函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用,這個函數(shù)的使用范圍被限制在聲明它的模塊P(4)在類中的static成員變量屬于整個類所擁有,對類的所有對象只有一份拷貝;(5)在類中的static成員函數(shù)屬于整個類所擁有,這個函數(shù)不接收this指針,因而只能訪問類的static成員11.2 for循環(huán)的深究如程序清單4.2所示,輸出結(jié)果是什么?程序清單4.2for循環(huán)#include<stdio.h>intmain(intargc,char*argv[])(inti=0;for(i=0,printf("First=%d",i);printf(nSecond=%dMzi),i<10;i++,printf("Third=%d",i))(printf(nFourth=%d\nM,i);return0;這個題目主要考察對for循環(huán)的理解。我們先來看看運行程序會輸出什么?TOC\o"1-5"\h\zFirst= 0 Second = 0 Fourth = 0Third= 1 Second = 1 Fourth = 1Third= 2 Second = 2 Fourth = 2Third= 3 Second = 3 Fourth = 3Third= 4 Second = 4 Fourth = 4Third= 5 Second = 5 Fourth = 5Third= 6 Second = 6 Fourth = 6Third= 7 Second = 7 Fourth = 7Third= 8 Second = 8 Fourth = 8Third= 9 Second = 9 Fourth = 9Third=10Second=10請按任意鍵繼續(xù)...從輸出我們就可以知道程序到底是什么運行:首先i=0,所以輸出:Rrst=0;接著輸出:Second=0;i<10成立,則輸出:Fourth=0。就此完成接著i++,此時i=1,輸出:Third=1;接著輸出:Second=1;i<10成立,則輸出:Fourth=1???推。尺 sizeof如程序清單4.3所示,sizeof(a),sizeof(b)分別是多少?程序清單4.3sizeof#include<stdio.h>intmain(intargc,char*argv[])chara[2][3];shortb[2][3];printf(nsizeof(a)=%d\nn,sizeof(a));printf("sizeof(b)=%d\nn,sizeof(b));return0;)這個題目比較簡單,由于char是1個字節(jié)、short是2個字節(jié),所以本題答案是:sizeof(a)=6sizeof(b)=12請按任意鍵繼續(xù)...好的,再來看看如程序清單4.4所示,sizeof(a),sizeof(b)分別是多少?程序清單4.4sizeof?include<stdio.h>intmain(intargc,char*argv[])(char*a[2][3];short*b[2][3];printf(nsizeof(a)=%d\nn,sizeof(a));printf("sizeof(b)=%d\nn,sizeof(b));return0;}是數(shù)組指針呢,還是指針數(shù)組呢?這里涉及*和□和優(yōu)先級的問題。我告訴大家的是這兩個數(shù)組存放的都是指針什么,在后續(xù)章節(jié)會詳細解釋,然而指針變量所占的字節(jié)數(shù)為4字節(jié),所以答案:sizeof(a)=2424sizeof(b)=24請按任意鍵繼續(xù)..?++i和i++1.或許大家都知道,++i是先執(zhí)行i自加再賦值,但是i++是先賦值再自加,但是還有隱藏在后面的東西呢inti=0;intiNumber=0;iNumber=(++i)+(++i)+(++i);C-Free編譯輸出是:7,有的編譯器輸出是:9。這兩個答案都是對的,編譯器不同所不同。7=2+2+3;9=3+3,答案是7的先執(zhí)行(++i)+(++i)再執(zhí)行+(++i),但是答案是9的是一起執(zhí)行。這只是前奏,先看幾個讓你目瞪口呆的例子。編譯環(huán)境是VS2010。inti=0;intiNumber=0;iNumber=(i++)+(++i)+(++i);printf(niNumber=%d\nn,iNumber);這里輸出是:4!!!4=1+1+2。inti=0;intiNumber=0;iNumber=(++i)+(i++)+(++i);printf(MiNumber=%d\nn,iNumber);這里輸出是:4!!!4=1+1+2ointi=0;intiNumber=0;iNumber=(++i) +(++i)+(i++);printf("iNumber=%d\nn,iNumber);這里輸出是:6!!!6=2+2+2o這里至少能說明兩個問題,其一,先執(zhí)行前面兩個,再執(zhí)行第三個;其二,。++)這個i的自加是最后執(zhí)行!inti=0;intiNumber=0;iNumber=(++i)+(i++)+(++i)+(++i)+(i++);printf(niNumber=%d\nn,iNumber);這個會是多少?!答案是:10!!!10=1+1+2+3+3!不同的編譯器或許會存在不同的答案,希望讀者自行進行驗證。scanf()函數(shù)的輸入如程序清單4.5所示,運行程序,當(dāng)顯示EnterDividend:,輸入的是a,按下Enter之后程序會怎么運彳:程序清單4.5scanf()函數(shù)的輸入#include<stdio.h>intmain(void)floatfDividend,fDivisorzfResult;printf(MEnterDividend:H);scanf(H%fnz&fDividend);printf(HEnterDivisor:n);scanf(H%fnz&fDivisor);fResult=fDividend/fDivisor;printf("Resultis:%f\nM,fResult);return0;這個問題有人會說,肯定是顯示EnterDivisor:要我輸入除數(shù)咯。是這樣嗎?答案是:如果你在日iterDividend:之后輸入非數(shù)字,按下Enter之后顯示的不是EnterDivisor:要你輸入除數(shù)此就運行結(jié)束,顯示一個不確定答案,這個答案每一次都會變。如果你在EnterDivisor:之后輸入非數(shù)字,按顯示的不是Reslut的結(jié)果,而是程序到此就運行結(jié)束,顯示一個不確定答案,這個答案每一次都會變。由于scanf。使用了%f,當(dāng)輸入數(shù)字的時候,scanf()將緩沖區(qū)中的數(shù)字讀入fDividend,并清空緩沖區(qū)。由于我數(shù)字,因此scanf。在讀入失敗的同時并不會清空緩沖區(qū)。最后的的結(jié)果是,我們不需要再輸入其他字符,scant讀取緩沖區(qū),每次都失敗,每次都不會清空緩沖區(qū)。當(dāng)執(zhí)行下一條scanf()函數(shù)讀取除數(shù)時,由于緩沖區(qū)中有數(shù)等待用戶輸入,而是直接從緩沖區(qū)中取走數(shù)據(jù)。那么防止輸入非數(shù)字的程序應(yīng)該怎樣呢?#include<stdio.h>intmain(intargc,char*argv[])float fDividend,fDivisor,fResult;intiRet;charcTmpl[256];printf("EnterDividend\nn);iRet=scanf(n%fn,&fDividend);if(1==iRet)(printf("EnterDivisor\nH);iRet=scanf( ,&fDivisor);if(1==iRet)(fResult=fDividend/fDivisor;printf("Resultis%f\nM,fResult);}else(printf(nInputerror,notanumber!\nn);gets(cTmpl);return1;}}elseprintf(HInputerror,notanumber!\n");gets(cTmpl);return1;return0;}scanf()函數(shù)的返回值如程序清單4.6所示,請問輸出會是什么?程序清單4.6scanf()函數(shù)的返回值intazb;printf(\nn,scanf(n%d%dn,&a,&b));輸出輸入這個函數(shù)的返回值?!答案是:2。只要你合法輸入,不管你輸入什么,輸出都是2。那么我們就要深這個函數(shù)。scanf()的返回值是成功賦值的變量數(shù)量。1.7 const作用下的變量閱讀如程序清單4.7所示,想想會輸出什么?為什么?程序清單4.7const作用下的變量constintiNumber=10;printf(niNumber=%d\n",iNumber);int*ptr=(int*)(&iNumber);*ptr=100;printf(niNumber=%d\nu,iNumber);8nst的作用在第四章已經(jīng)詳細講了,這里就不再累贅,答案是:10,10。這里補充一個知識點:constint*p 指針變量p可變,而p指向的數(shù)據(jù)元素不能變int*constp 指針變量p不可變,而p指向的數(shù)據(jù)元素可變constint*constp 指針變量p不可變,而p指向的數(shù)據(jù)元素亦不能變1.8 *ptr++、*(ptr++),*++ptr、*(++ptr),++(*ptr)、(*ptr)++的糾纏不清1. 如程序清單4.8所示程序,輸出什么?程序清單4.8*ptr++intiArray[3]={1,11,22);int*ptr=iArray;printf(n*ptr++=%d\nn,*ptr++);printf(M*ptr=\nH,*ptr);糾結(jié)啊,是先算*ptr還是ptr++;還是糾結(jié)啊,ptr是地址加1還是偏移一個數(shù)組元素!這里考查了兩個知識點,其一:*與++的優(yōu)先級問題;其二,數(shù)組i++和++i的問題。*和++都是優(yōu)先級為2,算符,自右向左結(jié)合。所以這里的*ptr++和*(ptr++)是等效的。首先ptr是數(shù)組首元素的地址,所以ptr++是偏移一個數(shù)組元素的地址。那么ptr++運算完成之后,此時的ptr是由所以第二個輸出*ptr=11。如圖4.1所示。那么倒回來看第一個輸出,ptr++是在執(zhí)行完成*ptr++之后再執(zhí)行的,=1O如程序清單4.9所示程序,輸出會是什么?程序清單4.9*++ptrintiArray[3]={1,11,22);int*ptr =iArray;printf(n*++ptr=%d\nn,*++ptr);printf(M*ptr=%d\nn,*ptr);這個解釋和上面解釋差不多,就是++ptr和ptr++的差別,所以這里的兩個輸出都是:11。同樣的道理,*++p是等效。再如程序清單4.10所示,輸出又會是什么?程序清單4.10(*ptr)++intiArray[3]={1,11,22);int*ptr=iArray;printf(n(*ptr)++=%d\n”,(*ptr)++);printf(n*ptr=%d\nn,*ptr);這個的輸出是:1,2。原因請讀者分析。4.ipa(94.96KB,卜.載次數(shù):11)圖4.1ptr++11122ptrptr++ptr指向的是數(shù)組元素a[0]=1的地址,

ptr++指向的是數(shù)組元素a[1]=11的地址第五節(jié)C語言中的細節(jié)1.1“零值”比較寫出floatx與''零值”比較的if語句。首先要知道float是有精度的,不能直接與0相比較或者兩數(shù)相減與。相比較。float能保留幾位小數(shù)格案是6位。既然如此,那么就應(yīng)該這么寫:if((x>0.000001)&&(x<-0.000001)).宏定義定義一個宏,返回X、丫中的較大值。這個題目其實很簡單,但是在很多筆試中都會拿出來考試,并且出錯率很高,原因只有一個,忽略細節(jié)(優(yōu)先級的問題,實在搞不明白就加括號吧,你好理解,別人一看也懂)。終究還是細節(jié)決定成敗。?defineMAX((X),(Y)) ((X)>=(Y)?(X):(Y))宏定義兩個數(shù)相加請問如程序清單5.1輸出什么?程序清單5.1宏定義兩數(shù)相加#defineDOUBLE(x)x+xintmain(intargc,char*argv[])(intiNumber=0;printf(n%d\nn,10*DOUBLE(10));return0;)其實這個程序非常簡單,學(xué)習(xí)C語言一周就應(yīng)該理解是什么意思,但是一般會出錯的的地方都在細節(jié)。其實這個程序輸出是110??赡苡腥藭?,不是10先DOUBLE嘛,然后乘以10,不是200嘛。是啊,想法是好的,我想這個程序的“原意”也應(yīng)該是這樣,但是就是由于優(yōu)先級的問題,打破了我們的愿望。如果要得到200,那么就應(yīng)該是這樣宏定義:#defineDOUBLRx)((x)+(x))。我想,無論我加多少層括號都不算違法吧。遞歸運算如程序清單5.2所示,輸出什么?程序清單5.2遞歸運算#include<stdio.h>intfunc(inta)if(a==0)returna;)printf("為d\n",func(a++/2));returna;intmain(intargc,char*argv[])(printf(H%dn,func(7));return0;)答案:0,2,4,8這里把7送進去,那么func(a++/2),先執(zhí)行7/2=3,然后a++=8,此時返回3;接著把3送進去,func(a++/2),先執(zhí)行3/2=1,然后a++=4,此時返回1;接著把1送進去,func(a++/2),先執(zhí)行1/2=0,然后a++=2,此時返回0;接著把。送進去,此時直接返回0,遞歸結(jié)束。遞歸最容易忽略的細節(jié)是,由于遞歸次數(shù)過多,容易導(dǎo)致堆棧溢出。讓人忽略的貪心法如程序清單5.3所示,程序輸出什么?程序清單5.3貪心法intk=8;inti=10;intj=10;k*=i+++j;

printf(n%d\nM,k);貪心法,就是一次性能盡可能多得吃運算符,那么這里k*=i+++j,加上括號之后就是這樣:k=k*((i++)+j);這樣的話就很簡單可以得出答案為:160。性能優(yōu)化.對如程序清單5.4所示進行性能優(yōu)化,使得效率提高。程序清單5.4性能優(yōu)化intiValuel;intiValue2;iValuel=1234/16;iValue2=1234%32;對于嵌入式進行除法是很消耗效率的,能使用移位完成最好使用移位完成。iValuel=1234>>4;iValue2=1234-((1234?5)?5);1234/16=77;1234%32=18。而十進制:1234轉(zhuǎn)化成二進制:010011010010.1234>>4=000001001101,轉(zhuǎn)化為十進制即為:77;1234>>5=000000100110,((1234>>5)<<5)即為010011000000,轉(zhuǎn)化為十進制即為:1120,1234-1216=18。第六節(jié)數(shù)組與指針數(shù)組、數(shù)組元素、指針的大小1.如程序清單1.如程序清單61所示,程序輸出什么?程序清單6.1數(shù)組、數(shù)組元素、指針的大小#include<stdio.h>intmain(intargc,char*argv[])(int*p;TOC\o"1-5"\h\zprintf( nsizeof(p) = %d \nn , sizeof(p) );printf( 11sizeof(*p) = %d \nM , sizeof(*p));inta[100];printf( "sizeof(a) = %d \nn , sizeof(a) ) ;printf( "sizeof(a[100]) = %d \n" , sizeof(a[100]));printf( nsizeof(&a) = %d \nM , sizeof(&a) );printf( nsizeof(&a[0]) = %d \n" , sizeof(&a[0]));return0;}p是指針,任何數(shù)據(jù)類型的指針都是占4字節(jié);*p是一個指針指向的int數(shù)據(jù),int型數(shù)據(jù)占用4字節(jié);a是數(shù)組,除了sizeof(a)和&a之外,當(dāng)a出現(xiàn)在表達式中時,編譯器會將a生成一個指向a[0]的指針,而這里數(shù)組的大小。答案:TOC\o"1-5"\h\zsizeof(p) = 4sizeof(*p) = 4sizeof(a) = 400

sizeof(a[100])=sizeof(&a) =4sizeof(&a[0]) =4請按任意鍵繼續(xù)...廣東省的省政府和廣州市的市政府都在廣州如程序清單6.2所示,如果ptr=Ox10000000,那么剩下三個輸出是多少?程序清單6.2數(shù)組首地址與數(shù)組首元素地址intiArray[3]={1,2,3};int*ptr=iArray;printf(nptr =%#x\nM,ptr);printf(niArray =%#x\nn,iArray);printf(n&iArray =%#x\nn,&iArray);printf(n&iArray[0] =%#x\nn,&iArray[0]);iArray是數(shù)組名,由6.1節(jié)對a的說明,可iArray知同時也是數(shù)組首元素的地址,為Ox10000000;&iArray是婁這是毫無疑問的。&iArray[O]是數(shù)組首元素的地址,也是0x10000000。也就是說數(shù)組的首地址和數(shù)組首元素的此因為廣東省的省政府和廣東省的首號城市廣州市的市政府都在廣州,兩者的地址是相等的。如圖6.1所示。如程序清單6.3所示,ptr=0x10000000,那么這三個輸出會是多少?程序清單9.3數(shù)組首地址加1、數(shù)組首元素地址加1intiArray[3]={1,2,3);int*ptr=iArray;printf(nprintf(n&iArray+l%#x\nH,&iArray+l);printf(niArray+l=%#x\nH,iArray+1);printf(n&iArray[0]+l=%#x\nM,&iArray[0]+1);答案是,第一個輸出:0x1000000C;第二個、第三個輸出:0x10000004o&iArray是數(shù)組的首地址,那么&iArray+1是偏移一個數(shù)組單元,因為站在全國的角度報全國各省政府的天氣預(yù):省省政府之后就為湖南省省政府;如圖6.1所示。&iArray[O]是數(shù)組首元素的地址,&iArray[0]+1是偏移一個數(shù)學(xué)好比站在廣東的角度報廣東各城市的天氣預(yù)報,報完廣東省首號城市廣州的天氣預(yù)報之后就是為廣東省第二號:報。1.3 數(shù)組作為函數(shù)參數(shù),是傳什么進去了如程序清單6.4所示,程序輸出什么?程序清單6.4數(shù)組作為函數(shù)參數(shù)voidtext(charcArray[])(printf(nsizeof(cArray)=%d\nn,sizeof(cArray));)intmain(intargc,char*argv[])(charcArray[]=naBcDeFn;printf(nsizeof(cArray)=%d\nn,sizeof(cArray));text(cArray);return0;}這里考查兩個知識點,其一,sizeoffnstrlen();其二text(charcArray⑴形參到底是什么?答案是7,4??吹酱鸢肝蚁氪蠹揖蛻?yīng)該明白上面兩個問題了吧。到底是傳值還是傳址一定要搞明白哦。如程序清單6.5程序,輸出會是什么?程序清單6.5指針相減#include<stdio.h>intmain(intargc,char*argv[])(inta[2]={3,6};int*p=a;int*q=p+1;printf(nq-p=%d\nn,q-p);printf(n(int)q-(int)p=%d\nn,(int)q-(int)p);return0;)用數(shù)學(xué)方法到可以做出q-p=1這個答案,但是(int)q-(int)p的答案。指針,指針的強大。由于指針加1,內(nèi)不sizeof(int),但是int(q)和int(p)就不再是指針,而是一個整形數(shù)據(jù)。所以(int)q-(int)p=4,1.5 指針加1到底是加什么如程序清單6.6所示,請問p1+5=_;p2+5=_;程序清單6.6指針加1#include<stdio.h>intmain(intargc,char*argv[])(unsignedchar*pl;unsignedlong*p2;pl=(unsignedchar*)0x801000;p2=(unsignedlong*)0x810000;printf(npl+5=%#x\nHzpl+5);printf(np2+5=%#x\nM,p2+5);return0;)由于p+n=p+n*sizeof(p的數(shù)據(jù)類型),所以答案為:pl+5=0x801005p2+5=0x810014請按任意鍵繼續(xù)...1.6 數(shù)組與指針的概念如程序清單6.7所示,解釋程序。程序清單6.7數(shù)組與指針的概念inta;int*a;int**a;inta[10];int*a[10];int(*a)[10];int(*a)(int);int(*a[10])(int);答案:一個整型數(shù):一個指向整型數(shù)的指針;一個指向指針的指針,它指向的指針是指向一個整型數(shù):一個有10個整型數(shù)的數(shù)組;一個有10個指針的數(shù)組,該指針是指向一個整型數(shù)的;一個指向有10個整型數(shù)數(shù)組的指針;一個指向函數(shù)的指針,該函數(shù)有一個整型參數(shù)并返回一個整型數(shù);一個有10個指針的數(shù)組,該指針指向一個函數(shù),該函數(shù)有一個整型參數(shù)并返回一個整型數(shù)。這個題目很經(jīng)典,很多公司的筆試題目都會截取上面部分出來考試。特別是e和f,哪一個是數(shù)組指針,哪一個5g和h哪一個是函數(shù)指針,哪一個又是指針函數(shù)。1.7 數(shù)組與指針的糅合如程序清單6.8所示,輸出會是什么?程序清單6.8數(shù)組與指針的糅合應(yīng)用1intarr[]={6,7,8,9,10};int*ptr=arr;*(ptr++) +=123;printf(H%dz%d”,*ptr,*(++ptr));這個題目來源于華為的一道C語言筆試題,答案是:8,8Jptr=arr,這里ptr取得是數(shù)組arr{]的首元素地址,*(ptr-這里是ptr++,此時*(ptr)即為:6,那么*(prt++)+123=129,執(zhí)行完*(ptr++)+=123之后,*(ptr)=7。跟*(.8這個值是沒有半點關(guān)系,由于執(zhí)行了*(++ptr),所以此刻的*(ptr)為8,所以輸出為:8,8,如程序清單6.9所示,輸出會是什么?程序清單6.9數(shù)組與指針的糅合應(yīng)用2intmain(intargc,char*argv[])inta[5]={1,2,3,4,5};int*ptr=(int*)(&a+1);printf(n%d,%dn,*(a+1),*(ptr-1));}這個題目要求對指針的理解要比較透徹。由于*(a+1)和a[1]是等效的,則*(a+1)=a[1]=2。&a指的是指向與的指針,&a+1不是首地址+1,系統(tǒng)會認為加了一個a數(shù)組的偏移量,即偏移了一個數(shù)組的大小,因此ptr指市是*(ptr+5),既然如此,那么*(ptr-1)當(dāng)然就是a[4]=5咯。所以這個題目的答案是:2,5。其實這個題目還有一個延伸,int*ptr=(int*)((int)a+1),*ptr是多少。答案是:2000000。假設(shè)&a[0]=0x10000000,由于存儲方式是小端模式,那么a[0]=1和a[1]=2的存儲方式如圖6.2所示。因為a=0x10000000,而(int)a將這個地址強制轉(zhuǎn)化為了int型數(shù)據(jù),((int)a+1)=0x10000001,經(jīng)過(int成了地址,ptr=(int*)((int)a+1),由于ptr是指向int型的指針,*ptr占4個字節(jié),*ptr所占字節(jié)即為:0x00,0x0那么*ptr即為0x02000000。如程序清單6.10所示,如果ptrl為Ox10000000,那么三個輸出分別為多少?程序清單9.10數(shù)組與指針的糅合應(yīng)用3intiArray[7]={1,2,3,4,5,6,7};int*ptr1 =iArray;int*ptr2=&iArray[5];printf("ptr2 =%#x\nn,ptr2);printf(”ptrl =%#x\nH,ptrl);printf(nptr2-ptrl=%d\nH,ptr2-ptrl);很明顯iArray是整型數(shù)據(jù)類型數(shù)組,那么ptr2=ptrl+5*sizeof(int)=0x10000014。很多同學(xué)立馬就會脫口而t:=20嘛!真的是這樣嗎?其實答案是:5!解釋之前,我們先來看這個程序:intiArray[7]={1,2,3,4,5,6,7};char*pl =(char*)iArray;char*p2 =(char*)&iArray[5];printf("p2-pl=%d\nM,p2-pl);這個程序的輸出是:20。因為指針類型是char*,char是1個字節(jié);而上面*ptr1和*ptr2是int*,所以答案是:如果是:short*pl =(short*)iArray;short*p2 =(short*)&iArray[5];貝ijp2-p1就是為:10。這里還有一個延仰:intiArray[7]={1,2,3,4,5,6,7};int*ptrl=iArray;int*ptr2=&iArray[5];printf(”ptr2 =%#x\nn,ptr2);printf(”ptrl =%#x\nn,ptrl);printf(nptr2-ptrl=%d\nn,(int)ptr2-(int)ptrl);這樣輸出答案是多少呢?20!閱讀程序,輸出什么?char*cArray[3]={HabodefH,”123456”,Hjxlgdxn};printf(nsizeof(cArray[0])=%d\nH,sizeof(cArray[0]));我相信有較多的人的答案是:6或者7。原因是忽略了*cArray[3]這是一個指針數(shù)組,也就是說cArray[3]數(shù)組中不而不是字符串常量。在C語言筆試陷阱與難點第一階段講過,只要是指針變量,其大小就是:4。所以這里毋克應(yīng)該是:4o你要是存在懷疑,可以輸出cArray[3]數(shù)組的各個元素看看是不是指針。printf( ncArray[0] = %#x \nn , cArray[0]);printf( ncArray[1] = %#x \n" , cArray[1]);printf( HcArray[2] = %#x \n" , cArray[2]);運行程序輸出為:sizeof(cArray[0])=4cArray[0]=0x415840cArray[1]=0x415770cArray[2]=0x415768請按任意鍵繼續(xù)...讀者亦可輸出指針?biāo)赶虻淖址簆rintf( ncArray[0] = %s \nn , cArray[0]);printf( HcArray[1] = %s \nn , cArray[1]);printf( HcArray[2] = %s \nn , cArray[2]);運行輸出為:cArray[0]=abcdefcArray[1]=123456cArray[2]=jxlgdx請按任意鍵繼續(xù)...2. 閱讀下列程序,輸出什么?typedefint(init_fnc_t)(void);externintarch_cpu_init(void);externintboard_early_init_f(void);init_fnc_t*init_sequence[]={arch_cpu__initzboard_early_init_ffNULL,);intarch__cpu__init(void)(printf(MThisisarch_cpu_init\nn);return0;)intboard_early_init_f(void)(printf(HThisisboard_early_init_f\nM;voidhang(void)printf(**Error!\n");while(1);)intmain(intargc,char*argv[])(init_fnc_t**init_fnc_ptr;for(init_fnc_ptr=init_sequence; nc_ptr; init_fnc_.ptr)(if((*init_fnc_ptr)()!=0)(hang();}}return0;}這個題目是我在閱讀u-boot-2012.10源碼的時候稍作修改從中提取出來的。這個題目將指針數(shù)組、函數(shù)指針等體。Thisisarch__cpu_initThisisboard_early_init_f請按任意鍵繼續(xù)...1.9 數(shù)組指針如程序清單6.11所示,程序輸出什么?程序清單6.11數(shù)組指針#include<stdio.h>intmain(intargc,char*argv[])(inta[][4]={1,3,5,7,9,11,13,15,17,19,21,23};int(*p)[4],i=2,j=l;p=a;printf("%d\n",*(*(p+i)+j));return0;}答案是:19。不能理解?好吧,如果我告訴你**(p+1)=9,*((*p)+1)=3!到這里能理解了嗎?如果還是不能理解,Ok,p有4個整型數(shù)據(jù)的數(shù)組,那么p如果加1,地址是不是得偏移4個整形數(shù)據(jù)的地址,而p等于數(shù)組a的首元素地ill組,也就意味著p是雙重指針了。1.10再論數(shù)組指針與數(shù)組首地址如程序清單6.12所示,已知&a[0][0]=0x22fe70,想想會是輸出什么?程序清單6.12數(shù)組指針與數(shù)組首地址intmain(intargc,char*argv[])inta[8][8]={1,2,3,4};int(*ptrl)[8] =a;int(*ptr2)[8][8]=&a;int*ptr3 =&a[0][0];printf(Mptrl =%#x\nn,ptrl);printf(H&a[0] =%#x\nn,&a[0]);printf(nptrl+1 =%#x\nn,ptr1+1);printf(M&a[0]+l=%#x\n\nH,&a[0]+l);printf(Hptr2 =%#x\nn,ptr2);printf(H&a=%#x\nn,&a);printf(Hptr2+l=%#x\nn,ptr2+l);printf(H&a+l =%#x\n\nH,&a+l);printf(nptr3 =%#x\n",ptr3);printf(M&a[0][0] =%#x\nn,&a[0][0]);printf(nptr3+l =%#x\nM,ptr3+l);printf(H&a[0][0]+l=%#x\n\nn,&a[0][0]+1);

這個題目涉及到兩個知識點,其一,講爛了的數(shù)組首元素地址和數(shù)組的首地址;其二,數(shù)組指針和指針數(shù)組的先看第三個指針,int*ptr3=&a[0][0];這個毫無疑問,是將數(shù)組a的首元素地址賦給指針ptr3,由于是int型數(shù)組則是偏移一個int型大小,即偏移4個字節(jié),那么ptr3這一組的輸出即為:ptr3 =0x22fe70&a[0][0] =0x22fe70ptr3+l =0x22fe74&a[0][0]+l=0x22fe74我們再看第二個指針,int(*ptr2)[8][8]=&a;根據(jù)之前我們講過的,這個是取數(shù)組a的首地址,ptr2的解釋京向二維數(shù)組網(wǎng)[8]的指針,那么ptr2+1則是偏移了一個二維數(shù)組[8][8]的地址,即為4*8*8=256(0x100)個字節(jié)ptr2這一組的輸出即為:ptr2 = 0x22fe70&a = 0x22fo70ptr2+l = 0x22ff70&a+l = 0x22ff70剩下第一個指針,這個和6,9節(jié)差不多,int(*ptr1)[8] =a淇實它是等價于int(*ptr1)網(wǎng)=&a[8];那1個指向一維數(shù)組[8]的指針,如果我們這么理解a[8H8]={a1[8],a2[8],…a8網(wǎng)}(當(dāng)然這個理解是錯誤的),那Z向a1[8],那么當(dāng)ptr1+1就是指向a2[8],也就是偏移了一個含有8個int型數(shù)據(jù)的數(shù)組,即4*8=32(0x20)個字這一組的輸出即為:ptrl = 0x22fe70&a[0] = 0x22fe70ptrl+1 = 0x22fe90&a[0]+l = 0x22fe90這里再一次重復(fù)講一下數(shù)組指針和指針數(shù)組。int(*p)[8] p是指向一個含有8個整型數(shù)據(jù)的數(shù)組的指針(數(shù)組指針)int*p[8]p是一個含有8個指針型變量的數(shù)組(指針數(shù)組)&iArray &iArray+1&iArray &iArray+1【廣東省政府】 【湖南省政府】5.iDa(268.75KB.F載次數(shù):10)圖6.1省政府和市政府iArray和 iArray+1和&iArray[0]&iArray[0]+1所指向的地址所指向的地址【廣州市政府】【深圳市政府】gj£q(374.54KB,下載次數(shù):11)6.2地址加數(shù)據(jù)10x10000007—AwlAAACCCG—?0x00UX1UUUUUUbnonnone0x00UX1UUUUUUDAv1nonnoo/i0x02UXIUUUUUU4Hw-1AAAAAAO0x00UX1UUUUUUJC"non0x00UX1UUUuuuznonnoni0x00UXIUUUUUUI0x10000000—QXQ1 Hvionnnon70x00UXIUUUUUU/j0x00UXlUUUUUUbAv1HAHCCCU0x00UX1UUUUUUuAv1onnnnnAj 1 ?一1 0x02uxiuuuuuuqAwAAHAAAAQ0x00UX1UUUUUUonv-4nonnnno0x00UX1UUUUUUZAvinonnnn*i.j■0x00UX1uuuUUU10x10000000——?0x01第七節(jié)結(jié)構(gòu)體與聯(lián)合體1.1結(jié)構(gòu)體內(nèi)存對齊問題I. 這個程序本是我寫來驗證結(jié)構(gòu)體內(nèi)存對齊問題,但是我在linux系統(tǒng)和windows系統(tǒng)下的答案讓我:便將其加進本書。如程序清單7.1所示,程序輸出會是什么?程序清單7.1結(jié)構(gòu)體的內(nèi)存對齊問題#include<stdio.h>structDate{TOC\o"1-5"\h\zint year ;int month ;int day ;structDateType{TOC\o"1-5"\h\zint year ;int month ;int day ;}birthday;structstudent{int iNum ;charcName[30];float fScore ;char cSex ;doublemenber;}people;intmain(intargc,char*argv[])(printf(Hsizeof(structDate)=%d\n\n”,sizeof(structDate));printf(nsizeof(structDateType)=%d\nnsizeof(structDateType));printf("sizeof(birthday)=%d\n\n",sizeof(birthday)printf("sizeof(birthday)printf(n&birthday.year=%d\nn,&birthday.year);printf(n&sizeof.month=%d\nH,&birthday.month);printf(n&sizeof.day=%d\n\n",&birthday.day);TOC\o"1-5"\h\zprintf(nsizeof(structstudent)=%d\nn,sizeof(structstudent) );printf(nsizeof(people)=%d\n\nnrsizeof(people) )printf(M&people.iNum=%d\nHf&people.iNum )printf(n^people.cName=%d\nHr&people.cName )printf(n&people.fScore=%d\nM,&people.fScore )printf(n&people.cSex=%d\nn,TOC\o"1-5"\h\z&people.cSex );printf(n&people.menber =%d\n\n”,&people.menber );printf(Hsizeof(people.menber)=%d\n\n",sizeof(people.menber));return0;}傳統(tǒng)在windows下,結(jié)果大家都應(yīng)該知道,我現(xiàn)在就直接把window下和linux下結(jié)果直接貼出來,大家看看。結(jié)果有質(zhì)疑,大可上機試試,畢竟眼見為實。)sizeof(structDate)=12sizeof(structDateType)=12&birthday.year=4210832&sizeof.month=4210836&sizeof.day=4210840sizeof(structstudent)=56sizeof(people) =56&people.iNum = 4210848&people.cName = 4210852&people.fScore = 4210884&people,cSex = 4210888&peop1e.menber = 4210896sizeof(people.menber)=8請按任意鍵繼續(xù)..?上面是GFree中運行的結(jié)果,你可以試試VC等,答案依然如此。我們再來看看linux下結(jié)果:root@zhuzhaoqi-desktop:/home/zhuzhaoqi/C/prog1.34#./progsizeof(structDate)=12sizeof(birthday) =12&birthday.year =134520948&sizeof.month =134520952&sizeof.day =134520956sizeof(structstudent)=52sizeof(people) =52&people.iNum = 134520896&people.cName = 134520900&people.fScore = 134520932&people.cSex = 134520936&people.menber = 134520940sizeof(people.menber)=8這是linux下編譯的結(jié)果。加粗標(biāo)注區(qū)域夠讓你吃驚吧!說實話,看到第一眼,我也傻了。為什么,我們再看下劃線標(biāo)注區(qū)域,people.cSex在windows下聯(lián)系上下確個字節(jié),可是,可是為什么在linuxF只占用4個字節(jié)??!原來,在linux中以4個字節(jié)為開辟單元,即不足4個開辟4個,多于4個的繼續(xù)開辟4個,多出的部分放進另一個4structstudent{intiNum; /*開辟4個字節(jié)★/charcName[30];/*開辟32個字節(jié)★/floatfScore ; /*開辟4個字節(jié)*///開辟4個字節(jié),自己用1個字節(jié),剩下3個,不足以存儲menber*/charcSex;doublemenber;/*所以這里重新開辟4+4個字節(jié)*/}people;所以我們得出的答案是:4+32+4+4+8=52。但是,我們一直使用的windows下,以最大單元為開辟單位,即系統(tǒng)先檢查結(jié)構(gòu)中最大單位為double8個字節(jié)節(jié)為單位。student在Linux和windows下內(nèi)存開辟如圖7.1和圖7.2所示。結(jié)構(gòu)體在STM32的應(yīng)用如程序清單7.2所示程序是截取STM32固件庫中的一段代碼,請問輸出是什么?程序清單7.2結(jié)構(gòu)體在STM32的應(yīng)用#include<stdio.h>typedefvolatileunsignedintvui32;typedefstruct{vui32CRL;vui32CRH;vui32IDR;vui32ODR;vui32BSRR;vui32BRR;vui32LCKR;}GPIO_TypeDef;#defineGPIOA (GPIO_TypeDef*)0x10000000#defineGPIOLED (GPIO_TypeDef*)GPIOAvoidfunc(GPIO_TypeDef*GPIO)(printf(HGPIO->CRL=%#x\nn,&(GPIO->CRL));printf(MGPIO->CRH=%#x\nn,&(GPIO->CRH));printf(nGPIO->LCKR=%#x\nn,&(GPIO->LCKR));)intmain(intargc,char*argv[])(printf(Hsizeof(GPIO_TypeDef) =%d\nM,sizeof(GPIO_TypeDef));printf(HGPIOLED=%#x\nH,GPIOLED);func(GPIOLED);return0;)如果使用過STM32的固件函數(shù)庫的話,應(yīng)該對這個結(jié)構(gòu)體不會陌生,STM32固件函數(shù)庫就是這樣,通過“大行體和指針實現(xiàn)對一大堆寄存器的配置,在—map.h這個頭文件中,定義很多這樣的結(jié)構(gòu)體。這樣做有什么好處呢抽象出來了,上面7個寄存器就是每個GPI??诩拇嫫鞯墓灿刑匦?,那么只要給定某一個GPIOU的映射地址,過這個結(jié)構(gòu)體得到每個寄存器的地址。能這么做很巧的是ARM的MCU每個寄存器的偏移量都是4個字節(jié)或者2能使用結(jié)構(gòu)體完成,如果有一天出現(xiàn)了3個字節(jié)的偏移量,我想此時結(jié)構(gòu)體也就沒轍了。答案是:sizeof(GPIO_TypeDef) =28GPIOLED=0x10000000GPIO->CRL=0x10000000GPIO->CRH=0x10000004GPIO->LCKR=0x10000018請按任意鍵繼續(xù)..?確實很巧妙,方便!結(jié)構(gòu)體與指針已知如下所示條件。structstudent{TOC\o"1-5"\h\zlongint num ;char *name ;shortintdate ;char sex ;shortintda[5] ;)*P;p=(student*)0x1000000;那么請問,以下輸出什么?,sizeof(*p) );printf(Msizeof,sizeof(*p) );printf(nsizeof(student)=%d\n”,sizeof(student));TOC\o"1-5"\h\zprintf("p =%#x\nH,p );printf(np+0x200 =%#x\nn,p+0x200 );printf(H(char*)p+0x200 =%#x\nM,(char*)p+0x200 );printf(n(int*)p+0x200 =%#x\nM,(int*)p+0x200 ).第一個輸出不解釋,內(nèi)存對齊問題,結(jié)構(gòu)體指針,答案為:24。第二個輸出答案為:24。第三個輸出,為已知,答案為:0x1000000。第四個輸出,由于p此時是結(jié)構(gòu)體類型指針,那么p+0x200=p+0x200*sizeof(student)=所以p+0x200=p+0x200*24=0x1000000+0x3000=0x1003000o第五個輸出,由于p被強制轉(zhuǎn)換成了字符型指針,那么p+0x200=0x1000200。第六個輸出同理為:p+0x200=0x1000800.聯(lián)合體的存儲如程序清單7.3所示,程序輸出什么?程序清單7.3聯(lián)合體的存儲union{inti;struct{charL;charH;}N;intmain(intargc,char*argv[])(N.i=0x1234;printf(HN.Bity.L=%#x\nnzN.Bity.L);printf(MN.Bity.H=%#x\nn,N.Bity.H);return0;)結(jié)構(gòu)體的成員是共用一塊內(nèi)存,也就是說N.i和N.Bity是在同一個地址空間中。那么好辦了,但是要注意,CP模式,所以低字節(jié)存儲在低地址中,高字節(jié)存儲在高地址中。那么N.Bity.L是取了低地址,也就是得到低字節(jié),N.Bity.H是取了高字節(jié),即為0x12。在電腦中,int是占4字節(jié),所以存儲方式如圖10.3所示。其實這里有一個很巧妙的用法可以用于C51單片機中,為了與上面不重復(fù),假設(shè)C51的存儲模式是大端模式。在給定時器賦初值的時候,要將高八位和低八位分別賦給模式1定時器的高位預(yù)置值和低位預(yù)置值,有這么個式寸THx=(65536-10000)/256;TLx=(65536-10000)%256.那么我們就可以讓這樣寫這個程序union{unsignedinti;struct{unsignedcharH;unsignedcharL;}N;intmain(intargc,char*argv[])N.i=65536-10000;THx=N.Bity.H;TLx=N.Bity.L;return0;}這樣很方便并且高效地將高低位置好,其實單片機是一個很好學(xué)習(xí)C語言的載體,麻雀雖小,但是五臟俱全。65536-10000=55536=0xD8F0.由于在單片機中,int是占2字節(jié),那么存儲方式如圖7.4所示。結(jié)構(gòu)體在聯(lián)合體中的聲明如程序清單7.4所示,請問:printf("%d\n",sizeof(T.N));printf("%d\n",sizeof(T));輸出什么?程序清單7.4結(jié)構(gòu)體在聯(lián)合體中的聲明unionT

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論