慕課網-LinuxC語言結構體-學習筆記
Linux C語言結構體
- 編譯指令:預處理,巨集定義,
- 建立自己的資料型別:結構體,聯合體,動態資料結構
- 邏輯運算子:& | ^ ~ << >>
- 遞迴函式的呼叫
什麼是預處理
.c檔案->.i檔案->.s檔案->.o檔案->可執行檔案
- 預處理
- 編譯
- 彙編
- 連結
gcc -o helloworld.i helloworld.c -E
-E表示只讓gcc執行預處理。
vim跳到整個文件底部,命令::$
- 展開標頭檔案。
#include <stdio.h>
展開
巨集是什麼
c語言常量分為直接常量和符號常量:#define 識別符號 常量值(沒有分號)
hello.c原始碼:
#include <stdio.h>
#define R 10
int main()
{
int a =R;
printf("a=%d
");
printf("hello,world!
");
return 0;
}
預處理過之後的程式碼
# 4 "helloworld.c"
int main()
{
int a =10;
printf("a=%d
");
printf("hello,world!
");
return 0;
}
10是直接當做一個字串來替換。
巨集的本質是在預處理階段發生的單純的字串替換(巨集替換);
在預處理階段,巨集不考慮語法;
#include <stdio.h>
#define R 10
#define M int main(
M){
printf("hello,world!
");
return 0;
}
預處理是沒有問題的。可以編譯執行。
- 巨集用於大量使用的常量、陣列buffer中,便於修改。
巨集函式
原始碼:
#include <stdio.h>
#define R 10
#define M int main(
#define N(n) n*10
M){
int a = R;
int b =N(a);
printf("b = %d
",b);
printf("a =%d
",a);
printf("hello,world!
");
return 0;
}
預處理之後:
# 8 "hello.c"
int main(){
int a = 10;
int b =a*10;
printf("b = %d
",b);
printf("a =%d
",a);
printf("hello,world!
");
return 0;
}
巨集替換中直接替換的優先順序問題。
#include <stdio.h>
#define R 10
#define M int main(
#define N(n) n*10
#define ADD(a,b) a+b
int add(int a,int b){
return a+b;
}
M){
int a = R;
int b =N(a);
int c =add(a,b);
int d =ADD(a,b);
int e = ADD(a,b) * ADD(a,b);
printf("e = %d
",e);
printf("b = %d
",b);
printf("a =%d
",a);
printf("c =%d
",c);
printf("d =%d
",d);
printf("hello,world!
");
return 0;
}
- 巨集定義時由於是看作字串的替換,因此在設計函式時利用巨集可以不用考慮輸入值的型別,這與普通的函式定義不同。
#define ADD(a,b) (a+b)
- 這裡後面的括號是為了防止呼叫多次時優先順序出錯:
- main 函式種。
ADD(2,3)*ADD(2,3)
如果定義時沒有括號則是2+3*2+3
其與(2+3)*(2+3)
不同。因為預處理階段沒有函式運算,定義的東西只會被當作字串。但在呼叫後可以實現其功能。 - 而普通函式例如int add(int a,int b)除了在開頭要宣告值的型別,還要設定返回值,因此在定義過程與呼叫過程相對複雜。若能用巨集定義實現的情況應優先考慮巨集定義.
float d = ADD(10.5,20.0)
巨集是不考慮資料型別等的。
條件編譯。
typedef是怎麼回事
-
typedef 簡記:取別名;但是屬於C語法,結束要加分號,與#define 不同。
-
typedef int tni;即將int 用tni代替,在之後的int定義可直接寫為:tni i;
-
typedef int *p
;給int *
起了別名:p, -
在指標定義中
int * q=null
即可等價為pq=null
-
巨集是會在預處理階段被替換的,而tni不會
-
typedef struct stu{ }stu_t;
給結構體起別名 -
typedef unsigned long size_t
注意typedef如果寫在方法體內則只可作用於該作用域內{},#define一直全域性。
結構體的宣告與定義
#include <stdio.h>
struct weapon{
char name[20];
int atk;
int price;
};
int main()
{
int a =0;
float b =0.0;
struct weapon weapon_1;
return 0;
}
struct 結構體型別名{}
在函式中呼叫時 struct 結構體型別名 變數名(前兩部分效果類似定義 int 變數 中的int)
結構體的初始化與引用。
struct weapon weapon_1 = {"weapon_name",100,200};
printf("%s
,%d
",weapon_1.name,++weapon_1.price);
結構體元素可以和普通變數一樣進行操作。
結構體陣列
- 運算子是一個成員運算子,在所有運算子中運算級最高,可用.運算子訪問結構體內部成員
- //陣列裡包含兩個結構體元素,每個元素有結構體裡的三個成員
struct weapon weapon_2[2]={{"weapon_name1",50,100},{"weapon_name2",100,200}};
printf("%s
,%d
",weapon_2[0].name,weapon_2[1].atk);
結構體指標
struct weapon *w ; //定義一個指向weapon的w結構體指標
w=&weapon_1; //具體指向weapon_1的記憶體地址
(*w).name
w->name
weapon_1.name //這3種訪問型別都是一樣效果
struct weapon *w;
w = &weapon_1;
printf("---------------------------------
");
printf("name=%s
,name=%s
,name=%s
",(*w).name,w->name,weapon_1.name);
return 0;
結構體陣列指標。不用取地址符&:陣列的名字代表了這個陣列的記憶體首地址,陣列括號內的長度代表了陣列的單元數,資料型別是int的話就按照int型別(32位系統上是4個位元組)乘以單元數的長度,如果資料型別是結構體的話就按照結構體的長度乘以單元的長度。
p++,不是記憶體位置右移了一個位元組,而是右移了一個單元長度的結構體weapon的記憶體長度。所以就不難理解為什麼右移到了第二個結構體例項的首地址上了
struct weapon *p;
p = weapon_2; //p->name weapon_2[0].name
printf("%s
",p->name);
printf("---------------------------------
");
p++;// weapon_2 +1 weapon_2[1]
printf("%s
",p->name);
return 0;
共用體型別是怎麼定義的以及怎麼使用的
- union共用體是多種不同資料型別的合集,所佔位元組按照共用體裡面型別所佔最長位元組決定,
- 例如有char(1位元組)型和int(4位元組)型,按照int型來計,整個共用體所佔四個位元組;此外,共同體裡面所有資料的地址是相同的,這個決定了它在有多種資料型別的時候,有且只能存放這些資料型別裡面的一種資料。以最後一次賦值為準。
- struct結構體也是不同資料型別的合集,所佔位元組按照裡面所有資料型別的長度來決定,
- 例如:char(1位元組)和int(4位元組),struct所佔空間是8個位元組,不是5個位元組,原因是涉及到位元組對齊,位元組對其是方便計算機快速的讀取資料。
- 大小 = 最後一個成員的偏移量+最後一個成員的大小+末尾填充位元組數。
- 偏移量,實際地址和結構體首地址之間的距離。
#include <stdio.h>
struct data{
int a;
char b;
int c;
};
int main()
{
// union data data_1;
//data_1.b =`C`;
// data_1.a =10;
printf("%lu",sizeof(struct data));
return 0;
}
a的偏移量0;b的偏移量4,自身大小為1。偏移量是大小的整數倍,不會填充空間;c的偏移量為5,c自身大小為4.要補齊為8.然後加上c自身的4。
所以整個佔用12.然後再判斷這個大小12是不是最寬成員的整數倍。
- %p表示輸出這個指標
- %d表示後面的輸出型別為有符號的10進位制整形,
- %u表示無符號10進位制整型,
- %lu表示輸出無符號長整型整數(long unsigned)
#include <stdio.h>
union data{
int a;
char b;
int c;
};
int main()
{
union data data_1;
data_1.b =`C`;
data_1.a =10;
printf("%p
,%p
,%p
",&data_1.a,&data_1.b,&data_1.c);
return 0;
}
共用體地址全部相同。
動態資料結構-靜態連結串列
靜態資料結構:
- 如:整型、浮點型、陣列。
- 系統分配固定大小的儲存空間
連結串列:
- 有頭指標,存放地址,地址指向第一個元素。沒有頭指標連結串列無法訪問
- 連結串列中的每一個元素都是一個節點。
- 節點裡包括使用者需要的資料和下一個節點的地址,各個元素的地址不一定是連續的
靜態連結串列;(所有節點都是在程式中定義的,而不是臨時開闢的)
【由三個武器資訊的節點組成,所以用結構體型別作為節點元素】
#include <stdio.h>
struct weapon{
int price;
int atk;
struct weapon * next;
};
int main()
{
struct weapon a,b,c,*head;
a.price =100;
a.atk = 100;
b.price =200;
b.atk =200;
c.price =300;
c.atk =300;
head = &a;
a.next =&b;
b.next =&c;
c.next = NULL;
struct weapon *p;
p =head;
while(p!=NULL){
printf("%d,%d
",p->atk,p->price);
p=p->next;
}
}
- 連結串列:可以用malloc來動態分配所需的記憶體,並且需要用free手動釋放在堆裡面申請的記憶體。連結串列有一個頭指標和尾指標,每個指標指向的是連結串列下一個資料的地址。在結構體裡面加入指標就構成連結串列,此時指標結構體包括兩個部分,一個是資訊域,另一個是指標域。
動態連結串列
程式執行過程中從無到有的建立起一個連結串列,也就是說需要一個一個的開闢新節點,輸入新節點的資料,然後建立起前後相連的關係。
建立武器資訊的單向動態連結串列:
#include <stdio.h>
#include <malloc.h>
struct weapon{
int price;
int atk;
struct weapon * next;
};
//【需要一個建立連結串列的函式,返回值是連結串列的頭指標】
struct weapon * create(){
struct weapon *head;
struct weapon *p1,*p2;//3個指標都用來指向struct weapon型別資料,p1,p2分別指向當前新建立和上一個。
int n=0;//記錄當前節點個數
//malloc分配記憶體塊的函式,sizeof判斷資料型別長度符
p1=p2=(struct weapon*)malloc(sizeof(struct weapon));
scanf("%d,%d",&p1->price,&p1->atk);
head = NULL;//一開始連結串列不存在,置空
while(p1->price!=0){//約定price為0時停止輸入
n++;
if(n==1) head=p1;
else p2->next=p1;
p2=p1;//保留p1當前所指向的的地址
//需要開闢一個新的動態儲存區,把這個的地址載給p1
p1=(struct weapon*)malloc(sizeof(struct weapon));
scanf("%d,%d",&p1->price,&p1->atk);//開闢後輸入資料
}
p2->next=NULL;
return (head);
}//p1,p2一個用來指向連結串列新創立的節點,一個用來指向下一個節點
int main()
{
struct weapon *p;
p=create();//p成為連結串列的頭指標
printf("%d,%d",p->price,p->atk);//列印第一個節點的資訊
return 0;
}
C語言中的位運算子:按位與、按位或、按位異或、左移和右移
按位與
- 位:指二進位制數中的一位 0false 1true
- 古老的微處理器速度:比加減運算快一些,比乘除法快很多
現在的框架中:通常與加減運算快相同,比乘除法快很多
六種位運算子
- & 按位與
- | 按位或
- ^按位異或
- ~按位取反
- <<左移
-
右移
#include <stdio.h>
int main()
{
// & | ^ ~ << >>
int a =4;//0100
int b =7;//0111
int c =a&b;//0100
printf("%d",c);
return 0;
}
- 位與運算就是將參與運算的兩個資料按照對應的二進位制數逐位進行邏輯與運算。
- 參與運算的兩個數必須是整型或者是字元型。
- 參與運算的數必須要以補碼的方式出現。
按位與的應用
- 迅速清零(對於一個數中為1的位,讓另一個數的相應位為0);
- 保留指定位置(對另一個數的相應位置1);
- 奇偶判斷(和1做與運算)[a&1//得到結果1位奇數,得到0為偶數]
#include <stdio.h>
int main()
{
// & | ^ ~ << >>
int a =4;//0100
int b =7;//0111
int c =a&1;//0100
int d =b&1;//0100
printf("%d
",c);
printf("%d
",d);
return 0;
}
輸出為0,1.
按位或運算。
#include <stdio.h>
int main()
{
// & | ^ ~ << >>
int a =9;//1001
int b =5;//0101
int c =a|b;//1101
printf("%d
",c);
return 0;
}
輸出為1101:13
按位或的作用:
設定資料的指定位,與255(0xFF)做或運算;
b = b| 0xFF,能設定資料b的指定二進位制數後8位置為1
即b的十進位制等於255
按位異或
將參與運算的兩個資料按對應的二進位制數逐位進行邏輯異或運算
- 定位反轉 a^0xff;
- 數值交換 a = a^b;b= b^a; a=a^b;
按位取反
~1000 = 0111
左移:高速乘以2;右移:高速除以2
左移:將資料對應的二進位制值逐位左移若干位;高位丟棄,低位補零;乘以2的n次方
右移:將資料對應的二進位制值逐位右移若干位:低位丟棄,高位補0或1(根據符號位判斷,就是正數數補0,負數補1);除以2的n次方
高位丟棄,低位補零
遞迴呼叫
遞迴呼叫有時候會犧牲效率
#include <stdio.h>
int func(int a)
{
int r =0;
if(a<0){
printf("error");
}else if(a==0 || a==1){
return 1;
}else{
r =a *func(a-1);
return r;
}
}
int main()
{
int a =0;
printf("please input the num:");
scanf("%d",&a);
int r = func(a);
printf("the result is %d
",r);
return 0;
}
遞迴的工作原理。
- 函式呼叫需要做的第一件事是為被呼叫的函式的形參分配一個臨時的記憶體單元然後才能把實參的值傳遞過來。
- 同時還需要傳遞的是主調函式的返回地址。(保護現場)
- 被調函式執行完了還需要繼續執行主調函式後面的程式碼。
- 資料儲存到棧裡面。
- 遞迴:大規模——化簡——>小規模,直到問題可求。
- 遞迴函式同時必須有 遞迴條件和遞迴表示式,否則會進入死迴圈。
- 遞推(for):則是由小問題的解逐步代入大問題並求出解。
總結
-
編譯預處理:標頭檔案、巨集替換
-
自定義資料型別:結構體、聯合體、連結串列宣告定義等,結構體涉及位元組對齊,共同體所有成員公用結構體記憶體地址
-
邏輯運算子位運算
-
遞迴和遞推
相關文章
- 慕課網go語言體系課搶先體驗Go
- Go語言學習筆記 - PART7 - 結構體Go筆記結構體
- C語言學習筆記:結構體與指標C語言筆記結構體指標
- Solidity語言學習筆記————15、結構體StructSolid筆記結構體Struct
- WebView學習的總結————慕課網WebView
- go語言學習-結構體Go結構體
- 慕課網《探秘Spring AOP》學習總結Spring
- 慕課網《前端JavaScript面試技巧》學習筆記(2)-原型和原型鏈前端JavaScript面試筆記原型
- GO 學習筆記->結構體Go筆記結構體
- 慕課網《Netty入門之WebSocket初體驗》學習總結NettyWeb
- 慕課網_《iOS基礎教程之介面初體驗》學習總結iOS
- Oracle體系結構學習筆記Oracle筆記
- ASM學習筆記_體系結構ASM筆記
- C 語言學習筆記筆記
- C語言學習筆記C語言筆記
- 慕課網玩轉資料結構課程之陣列資料結構陣列
- 【C#學習筆記】結構體使用C#筆記結構體
- DG學習筆記(2)_體系結構筆記
- 組合語言學習筆記組合語言筆記
- Solidity語言學習筆記————41、記憶體佈局Solid筆記記憶體
- Hive學習筆記 1 Hive體系結構Hive筆記
- Object C學習筆記20-結構體Object筆記結構體
- Go 結構 學習筆記Go筆記
- GO語言學習筆記-包結構篇 Study for Go ! Chapter eight - Package StructureGo筆記APTPackageStruct
- 熱更新語言--lua學習筆記筆記
- c語言學習筆記===函式C語言筆記函式
- 《JavaScript語言精粹》學習筆記二JavaScript筆記
- 《JavaScript語言精粹》學習筆記一JavaScript筆記
- R語言學習筆記之一R語言筆記
- Go 基礎語言學習筆記Go筆記
- 慕課網10小時大資料入門筆記大資料筆記
- 慕課網的中國式線上“慕課”模式模式
- Python自然語言處理學習筆記(57):小結Python自然語言處理筆記
- 層模式——面向模式體系結構學習筆記模式筆記
- Solidity語言學習筆記————31、智慧合約的基本檔案結構概述Solid筆記
- 資料結構學習筆記資料結構筆記
- 包羅永珍的結構體 -- 就要學習 Go 語言結構體Go
- 如何系統學習C 語言(中)之 結構體篇結構體