C語言學習筆記:結構體與指標 - IT人
文章推薦指數: 80 %
結構體結構體定義與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
//輸入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
延伸文章資訊
- 1第十一章結構與其它資料型態
利用sizeof() 得到結構所佔用的記憶體空間 ... 於程式中定義結構變數student,並以指標ptr 指向它 ... C/C++ 裡並沒有提供這樣的語法, 但是習慣上大家都用.
- 2[C 語言] 程式設計教學:如何使用結構(Struct) | 開源技術教學網
由於C 沒有內建的物件導向語法,使用指向結構的指標來模擬C++ (或Java 或C#) 的this ... 由於我們從堆積(heap) 動態配置記憶體,在程式尾段要記得將記憶體釋放掉。
- 3結構體(C語言) - 維基百科,自由的百科全書
在C語言中,結構體(struct)指的是一種資料結構,是C語言中複合資料類型(aggregate data type)的一類。結構體可以被聲明為變數、指標或陣列等,用以實現較複雜的 ...
- 4C 速查手冊- 6.3.1 自我參考的結構 - 程式語言教學誌
結構(structure) 中不能有與自己相同識別字(identifier) 名稱的結構,但可以有指向相同識別字名稱結構的指標(pointer) ,這是說C 語言可以簡單的利用結構與指標把資料 ...
- 5C 語言:結構變數與指標 - 寫點科普