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

下載本文檔

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

文檔簡(jiǎn)介

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

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

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

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

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

sizeof(a[100])=sizeof(&a) =4sizeof(&a[0]) =4請(qǐng)按任意鍵繼續(xù)...廣東省的省政府和廣州市的市政府都在廣州如程序清單6.2所示,如果ptr=Ox10000000,那么剩下三個(gè)輸出是多少?程序清單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é)對(duì)a的說明,可iArray知同時(shí)也是數(shù)組首元素的地址,為Ox10000000;&iArray是婁這是毫無疑問的。&iArray[O]是數(shù)組首元素的地址,也是0x10000000。也就是說數(shù)組的首地址和數(shù)組首元素的此因?yàn)閺V東省的省政府和廣東省的首號(hào)城市廣州市的市政府都在廣州,兩者的地址是相等的。如圖6.1所示。如程序清單6.3所示,ptr=0x10000000,那么這三個(gè)輸出會(huì)是多少?程序清單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);答案是,第一個(gè)輸出:0x1000000C;第二個(gè)、第三個(gè)輸出:0x10000004o&iArray是數(shù)組的首地址,那么&iArray+1是偏移一個(gè)數(shù)組單元,因?yàn)檎驹谌珖?guó)的角度報(bào)全國(guó)各省政府的天氣預(yù):省省政府之后就為湖南省省政府;如圖6.1所示。&iArray[O]是數(shù)組首元素的地址,&iArray[0]+1是偏移一個(gè)數(shù)學(xué)好比站在廣東的角度報(bào)廣東各城市的天氣預(yù)報(bào),報(bào)完廣東省首號(hào)城市廣州的天氣預(yù)報(bào)之后就是為廣東省第二號(hào):報(bào)。1.3 數(shù)組作為函數(shù)參數(shù),是傳什么進(jìn)去了如程序清單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;}這里考查兩個(gè)知識(shí)點(diǎn),其一,sizeoffnstrlen();其二text(charcArray⑴形參到底是什么?答案是7,4??吹酱鸢肝蚁氪蠹揖蛻?yīng)該明白上面兩個(gè)問題了吧。到底是傳值還是傳址一定要搞明白哦。如程序清單6.5程序,輸出會(huì)是什么?程序清單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這個(gè)答案,但是(int)q-(int)p的答案。指針,指針的強(qiáng)大。由于指針加1,內(nèi)不sizeof(int),但是int(q)和int(p)就不再是指針,而是一個(gè)整形數(shù)據(jù)。所以(int)q-(int)p=4,1.5 指針加1到底是加什么如程序清單6.6所示,請(qǐng)問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請(qǐng)按任意鍵繼續(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);答案:一個(gè)整型數(shù):一個(gè)指向整型數(shù)的指針;一個(gè)指向指針的指針,它指向的指針是指向一個(gè)整型數(shù):一個(gè)有10個(gè)整型數(shù)的數(shù)組;一個(gè)有10個(gè)指針的數(shù)組,該指針是指向一個(gè)整型數(shù)的;一個(gè)指向有10個(gè)整型數(shù)數(shù)組的指針;一個(gè)指向函數(shù)的指針,該函數(shù)有一個(gè)整型參數(shù)并返回一個(gè)整型數(shù);一個(gè)有10個(gè)指針的數(shù)組,該指針指向一個(gè)函數(shù),該函數(shù)有一個(gè)整型參數(shù)并返回一個(gè)整型數(shù)。這個(gè)題目很經(jīng)典,很多公司的筆試題目都會(huì)截取上面部分出來考試。特別是e和f,哪一個(gè)是數(shù)組指針,哪一個(gè)5g和h哪一個(gè)是函數(shù)指針,哪一個(gè)又是指針函數(shù)。1.7 數(shù)組與指針的糅合如程序清單6.8所示,輸出會(huì)是什么?程序清單6.8數(shù)組與指針的糅合應(yīng)用1intarr[]={6,7,8,9,10};int*ptr=arr;*(ptr++) +=123;printf(H%dz%d”,*ptr,*(++ptr));這個(gè)題目來源于華為的一道C語言筆試題,答案是:8,8Jptr=arr,這里ptr取得是數(shù)組arr{]的首元素地址,*(ptr-這里是ptr++,此時(shí)*(ptr)即為:6,那么*(prt++)+123=129,執(zhí)行完*(ptr++)+=123之后,*(ptr)=7。跟*(.8這個(gè)值是沒有半點(diǎn)關(guān)系,由于執(zhí)行了*(++ptr),所以此刻的*(ptr)為8,所以輸出為:8,8,如程序清單6.9所示,輸出會(huì)是什么?程序清單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));}這個(gè)題目要求對(duì)指針的理解要比較透徹。由于*(a+1)和a[1]是等效的,則*(a+1)=a[1]=2。&a指的是指向與的指針,&a+1不是首地址+1,系統(tǒng)會(huì)認(rèn)為加了一個(gè)a數(shù)組的偏移量,即偏移了一個(gè)數(shù)組的大小,因此ptr指市是*(ptr+5),既然如此,那么*(ptr-1)當(dāng)然就是a[4]=5咯。所以這個(gè)題目的答案是:2,5。其實(shí)這個(gè)題目還有一個(gè)延伸,int*ptr=(int*)((int)a+1),*ptr是多少。答案是:2000000。假設(shè)&a[0]=0x10000000,由于存儲(chǔ)方式是小端模式,那么a[0]=1和a[1]=2的存儲(chǔ)方式如圖6.2所示。因?yàn)閍=0x10000000,而(int)a將這個(gè)地址強(qiáng)制轉(zhuǎn)化為了int型數(shù)據(jù),((int)a+1)=0x10000001,經(jīng)過(int成了地址,ptr=(int*)((int)a+1),由于ptr是指向int型的指針,*ptr占4個(gè)字節(jié),*ptr所占字節(jié)即為:0x00,0x0那么*ptr即為0x02000000。如程序清單6.10所示,如果ptrl為Ox10000000,那么三個(gè)輸出分別為多少?程序清單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é)立馬就會(huì)脫口而t:=20嘛!真的是這樣嗎?其實(shí)答案是:5!解釋之前,我們先來看這個(gè)程序: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);這個(gè)程序的輸出是:20。因?yàn)橹羔橆愋褪莄har*,char是1個(gè)字節(jié);而上面*ptr1和*ptr2是int*,所以答案是:如果是:short*pl =(short*)iArray;short*p2 =(short*)&iArray[5];貝ijp2-p1就是為:10。這里還有一個(gè)延仰: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]這是一個(gè)指針數(shù)組,也就是說cArray[3]數(shù)組中不而不是字符串常量。在C語言筆試陷阱與難點(diǎn)第一階段講過,只要是指針變量,其大小就是:4。所以這里毋克應(yīng)該是:4o你要是存在懷疑,可以輸出cArray[3]數(shù)組的各個(gè)元素看看是不是指針。printf( ncArray[0] = %#x \nn , cArray[0]);printf( ncArray[1] = %#x \n" , cArray[1]);printf( HcArray[2] = %#x \n" , cArray[2]);運(yùn)行程序輸出為:sizeof(cArray[0])=4cArray[0]=0x415840cArray[1]=0x415770cArray[2]=0x415768請(qǐng)按任意鍵繼續(xù)...讀者亦可輸出指針?biāo)赶虻淖址簆rintf( ncArray[0] = %s \nn , cArray[0]);printf( HcArray[1] = %s \nn , cArray[1]);printf( HcArray[2] = %s \nn , cArray[2]);運(yùn)行輸出為:cArray[0]=abcdefcArray[1]=123456cArray[2]=jxlgdx請(qǐng)按任意鍵繼續(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;}這個(gè)題目是我在閱讀u-boot-2012.10源碼的時(shí)候稍作修改從中提取出來的。這個(gè)題目將指針數(shù)組、函數(shù)指針等體。Thisisarch__cpu_initThisisboard_early_init_f請(qǐng)按任意鍵繼續(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個(gè)整型數(shù)據(jù)的數(shù)組,那么p如果加1,地址是不是得偏移4個(gè)整形數(shù)據(jù)的地址,而p等于數(shù)組a的首元素地ill組,也就意味著p是雙重指針了。1.10再論數(shù)組指針與數(shù)組首地址如程序清單6.12所示,已知&a[0][0]=0x22fe70,想想會(huì)是輸出什么?程序清單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);

這個(gè)題目涉及到兩個(gè)知識(shí)點(diǎn),其一,講爛了的數(shù)組首元素地址和數(shù)組的首地址;其二,數(shù)組指針和指針數(shù)組的先看第三個(gè)指針,int*ptr3=&a[0][0];這個(gè)毫無疑問,是將數(shù)組a的首元素地址賦給指針ptr3,由于是int型數(shù)組則是偏移一個(gè)int型大小,即偏移4個(gè)字節(jié),那么ptr3這一組的輸出即為:ptr3 =0x22fe70&a[0][0] =0x22fe70ptr3+l =0x22fe74&a[0][0]+l=0x22fe74我們?cè)倏吹诙€(gè)指針,int(*ptr2)[8][8]=&a;根據(jù)之前我們講過的,這個(gè)是取數(shù)組a的首地址,ptr2的解釋京向二維數(shù)組網(wǎng)[8]的指針,那么ptr2+1則是偏移了一個(gè)二維數(shù)組[8][8]的地址,即為4*8*8=256(0x100)個(gè)字節(jié)ptr2這一組的輸出即為:ptr2 = 0x22fe70&a = 0x22fo70ptr2+l = 0x22ff70&a+l = 0x22ff70剩下第一個(gè)指針,這個(gè)和6,9節(jié)差不多,int(*ptr1)[8] =a淇實(shí)它是等價(jià)于int(*ptr1)網(wǎng)=&a[8];那1個(gè)指向一維數(shù)組[8]的指針,如果我們這么理解a[8H8]={a1[8],a2[8],…a8網(wǎng)}(當(dāng)然這個(gè)理解是錯(cuò)誤的),那Z向a1[8],那么當(dāng)ptr1+1就是指向a2[8],也就是偏移了一個(gè)含有8個(gè)int型數(shù)據(jù)的數(shù)組,即4*8=32(0x20)個(gè)字這一組的輸出即為:ptrl = 0x22fe70&a[0] = 0x22fe70ptrl+1 = 0x22fe90&a[0]+l = 0x22fe90這里再一次重復(fù)講一下數(shù)組指針和指針數(shù)組。int(*p)[8] p是指向一個(gè)含有8個(gè)整型數(shù)據(jù)的數(shù)組的指針(數(shù)組指針)int*p[8]p是一個(gè)含有8個(gè)指針型變量的數(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)存對(duì)齊問題I. 這個(gè)程序本是我寫來驗(yàn)證結(jié)構(gòu)體內(nèi)存對(duì)齊問題,但是我在linux系統(tǒng)和windows系統(tǒng)下的答案讓我:便將其加進(jìn)本書。如程序清單7.1所示,程序輸出會(huì)是什么?程序清單7.1結(jié)構(gòu)體的內(nèi)存對(duì)齊問題#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ì)疑,大可上機(jī)試試,畢竟眼見為實(shí)。)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請(qǐng)按任意鍵繼續(xù)..?上面是GFree中運(yùn)行的結(jié)果,你可以試試VC等,答案依然如此。我們?cè)賮砜纯磍inux下結(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ū)域夠讓你吃驚吧!說實(shí)話,看到第一眼,我也傻了。為什么,我們?cè)倏聪聞澗€標(biāo)注區(qū)域,people.cSex在windows下聯(lián)系上下確個(gè)字節(jié),可是,可是為什么在linuxF只占用4個(gè)字節(jié)?。≡瓉?,在linux中以4個(gè)字節(jié)為開辟單元,即不足4個(gè)開辟4個(gè),多于4個(gè)的繼續(xù)開辟4個(gè),多出的部分放進(jìn)另一個(gè)4structstudent{intiNum; /*開辟4個(gè)字節(jié)★/charcName[30];/*開辟32個(gè)字節(jié)★/floatfScore ; /*開辟4個(gè)字節(jié)*///開辟4個(gè)字節(jié),自己用1個(gè)字節(jié),剩下3個(gè),不足以存儲(chǔ)menber*/charcSex;doublemenber;/*所以這里重新開辟4+4個(gè)字節(jié)*/}people;所以我們得出的答案是:4+32+4+4+8=52。但是,我們一直使用的windows下,以最大單元為開辟單位,即系統(tǒng)先檢查結(jié)構(gòu)中最大單位為double8個(gè)字節(jié)節(jié)為單位。student在Linux和windows下內(nèi)存開辟如圖7.1和圖7.2所示。結(jié)構(gòu)體在STM32的應(yīng)用如程序清單7.2所示程序是截取STM32固件庫中的一段代碼,請(qǐng)問輸出是什么?程序清單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)該對(duì)這個(gè)結(jié)構(gòu)體不會(huì)陌生,STM32固件函數(shù)庫就是這樣,通過“大行體和指針實(shí)現(xiàn)對(duì)一大堆寄存器的配置,在—map.h這個(gè)頭文件中,定義很多這樣的結(jié)構(gòu)體。這樣做有什么好處呢抽象出來了,上面7個(gè)寄存器就是每個(gè)GPI??诩拇嫫鞯墓灿刑匦?,那么只要給定某一個(gè)GPIOU的映射地址,過這個(gè)結(jié)構(gòu)體得到每個(gè)寄存器的地址。能這么做很巧的是ARM的MCU每個(gè)寄存器的偏移量都是4個(gè)字節(jié)或者2能使用結(jié)構(gòu)體完成,如果有一天出現(xiàn)了3個(gè)字節(jié)的偏移量,我想此時(shí)結(jié)構(gòu)體也就沒轍了。答案是:sizeof(GPIO_TypeDef) =28GPIOLED=0x10000000GPIO->CRL=0x10000000GPIO->CRH=0x10000004GPIO->LCKR=0x10000018請(qǐng)按任意鍵繼續(xù)..?確實(shí)很巧妙,方便!結(jié)構(gòu)體與指針已知如下所示條件。structstudent{TOC\o"1-5"\h\zlongint num ;char *name ;shortintdate ;char sex ;shortintda[5] ;)*P;p=(student*)0x1000000;那么請(qǐng)問,以下輸出什么?,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 ).第一個(gè)輸出不解釋,內(nèi)存對(duì)齊問題,結(jié)構(gòu)體指針,答案為:24。第二個(gè)輸出答案為:24。第三個(gè)輸出,為已知,答案為:0x1000000。第四個(gè)輸出,由于p此時(shí)是結(jié)構(gòu)體類型指針,那么p+0x200=p+0x200*sizeof(student)=所以p+0x200=p+0x200*24=0x1000000+0x3000=0x1003000o第五個(gè)輸出,由于p被強(qiáng)制轉(zhuǎn)換成了字符型指針,那么p+0x200=0x1000200。第六個(gè)輸出同理為:p+0x200=0x1000800.聯(lián)合體的存儲(chǔ)如程序清單7.3所示,程序輸出什么?程序清單7.3聯(lián)合體的存儲(chǔ)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是在同一個(gè)地址空間中。那么好辦了,但是要注意,CP模式,所以低字節(jié)存儲(chǔ)在低地址中,高字節(jié)存儲(chǔ)在高地址中。那么N.Bity.L是取了低地址,也就是得到低字節(jié),N.Bity.H是取了高字節(jié),即為0x12。在電腦中,int是占4字節(jié),所以存儲(chǔ)方式如圖10.3所示。其實(shí)這里有一個(gè)很巧妙的用法可以用于C51單片機(jī)中,為了與上面不重復(fù),假設(shè)C51的存儲(chǔ)模式是大端模式。在給定時(shí)器賦初值的時(shí)候,要將高八位和低八位分別賦給模式1定時(shí)器的高位預(yù)置值和低位預(yù)置值,有這么個(gè)式寸THx=(65536-10000)/256;TLx=(65536-10000)%256.那么我們就可以讓這樣寫這個(gè)程序union{unsignedinti;struct{unsignedcharH;unsignedcharL;}N;intmain(intargc,char*argv[])N.i=65536-10000;THx=N.Bity.H;TLx=N.Bity.L;return0;}這樣很方便并且高效地將高低位置好,其實(shí)單片機(jī)是一個(gè)很好學(xué)習(xí)C語言的載體,麻雀雖小,但是五臟俱全。65536-10000=55536=0xD8F0.由于在單片機(jī)中,int是占2字節(jié),那么存儲(chǔ)方式如圖7.4所示。結(jié)構(gòu)體在聯(lián)合體中的聲明如程序清單7.4所示,請(qǐng)問: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等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論