C語言學習筆記:結構體與指標 - IT人

文章推薦指數: 80 %
投票人數:10人

結構體結構體定義與C++不同的是,C語言中定義結構體必須加上關鍵字struct,而C++中結構體是一個類的關鍵字,故可以不加。

struct persin{ char ... Togglenavigation IT人 IT人 C語言學習筆記:結構體與指標 量化就是探索生活發表於 2020-11-12 結構體 結構體定義 與C++不同的是,C語言中定義結構體必須加上關鍵字struct,而C++中結構體是一個類的關鍵字,故可以不加。

structpersin{ charname[20]; intage; chargender; floatheight; } 訪問方式 直接引用 通過.實現 structpersonyu; yu.age=20; 間接引用 通過->實現 structperson*ptr=&yu; ptr->age=20; 結構體的記憶體分佈 不一定是結構體內元素的簡單相加,我們認為,結構體中的記憶體分佈應該如上圖左圖所示,但是實際上是右圖,由於結構體中存在記憶體對齊原則。

記憶體對齊原則 1.按照結構體中所佔位元組最大的資料元素進行對齊,每次申請記憶體只能是這個最大記憶體的整數倍。

2.而且結構體每個成員相對結構體首地址的記憶體偏移量都是該成員大小的整數倍。

3.結構體首地址,也是最大記憶體的整數倍。

上圖例子中,int和float都佔4個位元組,故每次至少申請4個位元組記憶體大小。

舉例說明: structnode1{ chara; charb; intc; } structnode2{ chara; intc; charb; } 上圖中,node1佔用八個位元組,第一次申請四個位元組的區域,兩個char型別變數都可以存入這四個位元組,餘下兩個位元組不夠存入int型別變數故再開闢四個位元組記憶體,總共開闢 2 ∗ 4 = 8 2*4=8 2∗4=8個位元組。

而node2佔用十二個位元組,第一次申請四個位元組的區域儲存一個char型別變數,餘下三個位元組不夠儲存int故再開闢一個4位元組記憶體,且int需要儲存在偏移量為4整數倍的位置,故佔用新開闢的這四個位元組,而最後一個char變數需要新開一片四位元組記憶體儲存,故總共開闢 3 ∗ 4 = 12 3*4=12 3∗4=12個位元組。

對齊值 編譯器是按照什麼方式進行對齊? 1.資料型別自身的對齊值,即自身所佔記憶體大小2.結構體或者類的自身對齊值:其成員中自身對齊值最大的那個值。

3.指定對齊值:#pragmapack(value)時的指定對齊值value。

4.資料成員、結構體和類的有效對齊值:自身對齊值和指定對齊值中小的那個值。

當一個成員的對齊值確定為 N N N後,該成員所存放地址必須滿足 起 始 地 址 % N = 0 起始地址\%N=0 起始地址%N=0。

#pragmapack(1)/*指定按1位元組對齊*/ structD { charb; inta; shortc; }; #pragmapack()/*取消指定對齊,恢復預設對齊*/ //大小為7個位元組,空地址 共用體(聯合體) 各個欄位共用一片空間,空間大小為欄位中最大的那一個。

舉例:P轉整數 #include unionIP{ struct{ unsignedchara1; unsignedchara2; unsignedchara3; unsignedchara4; }ip; unsignedintnum; }; intmain(){ unionIPp; charstr[100]={0}; intarr[4]; while(~scanf("%s",str)){ sscanf(str,"%d.%d.%d.%d",arr,arr+1,arr+2,arr+3); p.ip.a1=arr[0]; p.ip.a2=arr[1]; p.ip.a3=arr[2]; p.ip.a4=arr[3]; printf("%u\n",p.num); } return0; } 輸出結果與預期不符,改動最後一位整形數字變太大。

//輸入192.168.0.1 16820416 //輸入192.168.0.2 33597632 小端模式和大端模式 大端模式和小端模式是cpu兩種不同的儲存模式 小端:數字低位存在地址低位大端:數字低位存在地址高位 上圖結果是由於在小端機中,IP第一位存在與地址低位。

而轉int時,IP第一位192被作為數字低位,而最後一位2被作為數字高位。

在主函式中進行修改 intmain(){ unionIPp; charstr[100]={0}; intarr[4]; while(~scanf("%s",str)){ sscanf(str,"%d.%d.%d.%d",arr,arr+1,arr+2,arr+3); p.ip.a1=arr[3]; p.ip.a2=arr[2]; p.ip.a3=arr[1]; p.ip.a4=arr[0]; printf("%u\n",p.num); } return0; } 輸出結果正常 //輸入192.168.0.1 3232235521 //輸入192.168.0.2 3232235512 本機位元組序和網路位元組序 判斷大端機和小端機 intis_little(){ staticintnum=1; return((char*)(&num))[0]; } //返回1則為小端機,否則大端機 地址與指標 地址可以運算元據的本源: 地址 int型別在記憶體中的儲存方式:不同位數的作業系統的區別,就是記憶體定址能力不同。

32位作業系統只能識別4GB記憶體,因為只有32個bit位。

64位系統使用64bit,是一個不可能達到的上限。

機器給每一個位元組一個地址標號,變數的地址都是首地址,比如上圖變數a,首地址為0x187c20。

指標變數 指標變數是也是變數,其儲存的值是地址,其自身也有地址。

指標型別決定指向變數的型別。

同一個系統中,指標變數的大小都相同,指標型別決定定址偏移量。

*運算子的結合 *指標運算子的結合方式,跟變數結合 inta; int(*p)=&a; //通過編譯 inta; (int*)p=&a; //不通過編譯 多級指標,編譯時變數結合 inta; int(*p)=&a; int(**pp)=&p; //通過編譯 但邏輯上理解為,先定義一個指標變數p,指向int型別的變數a的地址,在定義一個指標變數pp,指向一個int*型別的指標變數p。

&取地址運算子 在C語言中,&a表示取出變數a的首地址,只能作用於存在於記憶體中的變數或者結構體。

只有位於記憶體中的變數可以取地址,位於暫存器中的變數不可以取地址。

inta=1; int*pa=&a;//編譯通過 int*pa2=&(a+1);//編譯不通過,a+1在暫存器中 *解引用運算子 *還可以作為對指標變數解引用,用於通過指標間接訪問一個變數。

舉例 structData{ intx,y; } structDataa[2]; structData*p=a; //多種方式表示a[1].x a[1].x (*(a+1)).x (a+1)->x (p+1)->x (*(p+1)).x p[1].x (&p[1])->x (&p[0]+1)->x (*(&p[0]+1)).x 地址偏移量 structData{ inta; doubleb; charc; } 上圖例子中結構體structData的對齊值為8個位元組,int型別變數a與偏移量0位置,double型別變數b與偏移量8位置,char型別變數c與偏移量16位置。

//計算偏移量巨集定義offset #defineoffset(T,a)({\ T*temp;\ (char*)&(temp->a)-(chat*)temp;\ }) //更便捷的寫法 #defineoffset(T,a)(long)(&(((T*)NULL)->a)) 指標定義陷阱 不要用巨集定義重新命名指標型別 #definepcharchar* typedefchar*ppchar; intmain(){ pcharc1,c2; //c2為一個char而不是char* //展開程式碼為char*c1,c2; ppcharc2,c4; //c3,c4均為char* } 函式指標 定義函式指標,*必須跟指標變數走,否則為函式宣告。

int(*add)(int,int);//定義函式指標 int*add(int,int);//宣告返回指標變數的函式 使用typedef命名函式指標 typedef用法: //內建型別重新命名 typedeflonglonglint; typedefchar*pchar; //結構體型別重新命名 typedefstruct__node{ intx,y; }Node,*PNode; //函式指標命名: typedefint(*func)(int); //func可以接收任何傳入int返回int的函式 main函式引數 //作業系統給main函式傳參 intmain(); intmain(intargc,char*argv[]); intmain(intargc,char*argv[],char**env); //返回值給作業系統 argc儲存引數個數,argv儲存字串陣列(個數為argv),env儲存環境變數。

測試引數 voidoutput(intargc,char*argv[],char**env){ printf("argc=%d\n"); for(inti=0;i #include void(char**env){ for(inti=0;env[i];i++){ if(!strcmp(env[i],"USER=",5)){ if(!strcmp(env[i]+5,"your_USER_NAME")){ printf("Welcome,USER_NAME"); } else{ printf("Youhavenoaccess,Pleasegoout!"); exit(0); } } } } 相關文章 C語言瑣碎知識 2020-11-21 Go踩坑筆記(十九) 2020-11-21 Go com.alibaba.fastjson學習筆記 2020-11-21 React學習筆記之雙向資料繫結 2020-11-21 React 結構體記憶體對齊 2020-11-21 用React.js+Egg.js造輪子全棧開發旅遊電商應用學習筆記和心得 2020-11-21 全棧React Java設計模式-17、直譯器模式-自定義語言的實現 2020-11-22 Java設計模式 CSS技術筆記 2020-11-22 CSS 作業系統實驗:銀行家演算法(C語言) 2020-11-22 演算法 形式語言與自動機:實驗二——DFA識別句子 2020-11-22 Java語言搭建介面自動化框架學習一(單介面請求和響應) 2020-11-22 Java框架 C語言小白走過的彎路 2020-11-22 組合語言-學習記錄(二) 2020-11-22 (2)verilog與Systemverilog兩種語言編寫打兩拍 2020-11-22 《吳恩達機器學習》學習筆記007_支援向量機 2020-11-22 MachineLearning HeadFirstJava學習筆記(7):繼承與多型 2020-11-22 Java 計網應用層筆記(個人學習用,如有錯誤萬分感謝指出((看到哪更到哪) 2020-11-22 現代作業系統-原理與實現【讀書筆記】 2020-11-22 JavaScript正則學習筆記 2020-11-22 JavaScript C語言練習——資料加密 2020-11-22 加密 最新文章 StrategyAnalytics:2022年Q1全球智慧音響出貨量下降5% 軟體專案管理8.4.軟體專案質量計劃 NTCAS:車控作業系統總體技術要求研究報告(附下載) 清華大學&智譜AI:2022年全球高超音速技術發展報告(附下載) 動脈網:2022眼科行業研究報告(附下載) 灼鼎諮詢:2022年中國製造業行業研究報告(附下載) 伽馬資料:2022年5月遊戲產業資料 乘聯會:2022年5月新能源乘用車區域市場分析 Canalys:2022年Q1中國雲基礎設施服務支出同比增長21% vue大型電商專案尚品彙(後臺篇)day05 官方零基礎入門JetpackCompose的中文課程來啦! 得物質量度量之“三級指標體系”及其應用實踐



請為這篇文章評分?