C語言學習筆記_第1頁
C語言學習筆記_第2頁
C語言學習筆記_第3頁
C語言學習筆記_第4頁
C語言學習筆記_第5頁
已閱讀5頁,還剩28頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

知識點一標準輸入輸出函數

#include<stdio.h>

〃這是一個頭文件,文件內部包含了很多C語言運行過程中必要的庫函數頭文件有很多

個,很多時候,調用的庫函數都需要包含特定的頭文件才能使用

//main函數為所有c語言程序的入口函數。就是說所有c語言的程序,都是從main函

數開始執行的,如果main函數不存在,在c語言的編譯器在編譯過程中就會報錯

intmain(intargc.char**argv){

〃現在需要向標準輸出流輸出一個"helloworld"

〃想要完成這個操作,可以直接調用庫函數printf來實現

printf(”helloworld'n")"\n為轉義符,轉義符并不會將他本身的樣子打印到終端上

去,而是會將他轉義之后所代表的內容打印到終端上去。退格鍵的轉義符為\b,tab鍵的轉義

符為\t

return0;

}

格式化字符串輸出示例:

轉換字符諭出示例

%dor%i有符號十進制整數printf("%d心%i意\n”,3,2);

%c單個字符printf("少林功夫好(y/n)~%c\n”,V);

%s字符串printf(“愛我的人%s,我愛的人%s\n”,"呵呵呵”,"老美了”);

%f浮點數,默認精確到6位小數printf(“圓周率:%.2f\nM,3.1415926);

%%打印一個百分號printf(”手游占中國網絡游戲海外發行細分市場的65%%”);

轉義序列小結:

轉義序列名稱描述

\a蜂鳴警報在一些系統中警報不起作用

\b退格將光標回退一格

\f換頁將光標移到下一頁的開始處

\n換行將光標移到下一行的開始處

\r回車將光標移到當前行的開始出

\t水平制表將光標移到下一個水平制表位置

\v垂直制表將光標移到下一個垂直制表位置

單引號

V用于打印單引號'雙引號、問號'反斜

V雙引號線等字符(由于這些字符用于定義字符

\?問號常量,是printf函數的一部分,若直接使

用會造成混亂)

w反斜線

變量的使用:

teinclude<stdio.h>

tntmain(tntargc.char**argv){

〃申請一個變量:根據需求,先寫出變量的具體類型,然后在類型的后面跟上變量的名

字(注意要滿足規則)

tnta=5;

tntb=10;

p「tntf(”a的值是:%d,b的值是:%d\n",a,b);

〃此處需要使用格式點位符:格式點位符能夠取代一個變量所占據的位置,然后通過告

訴系統,當前時間我這個變量的具體是多少,最終將這個值賦值給格式點位符。

return0;

scanf函數的使用:

概述:

C函數庫包含了多個輸入函數,Scanf是最能用的一個,可以讀取不同格式的數據

回基本用法

轉換字符串含義

intnum;%d把輸入解釋成有符號整型

printf(“請輸入數量:");%c把輸入解釋成字符型

scanf("%d",&num);

%s把輸入解釋成字符串

%f把輸入解釋成單精度浮點數

i、格式辛符串的用法巧P行nd函數次母%lf把輸入解釋成雙精度浮點數

2、讀取總本類型的點附,變詈甫裳加&將號)

說明:

?scant"%d-%d-%d",&a,&b,&c|;//&這個叫取地址符,其作

用為直接取到變量地址值

注意:當發生scanf調用的時候,scanf會做2件事情:

①scanf會跑到緩存區域去查看緩存區是否有數據,有則執行第二步;沒有則會將系統

掛起,并等待用戶輸入數據,完成后繼續第二步。

②scanf會讀取緩存區最靠前的數據,如果能夠被96d吸收則吸收,并將值賦值給變量,

如果不能吸收,則數據依舊在緩存區內部,則直接退出。

在輸入函數scanf后可以使用循環while(getchar()!='\n')來清除緩存區域的回車符號。

回使用size。他算符可以獲得數據類型占用內存空間的大小

使用O或Ox打印八進制或十六進制數。

intx=100:

printf("dec=%d:octal=%o:hex=?%x\n".x.x(x);

printf("dec=%d:octal=%#o:hex=%#x\n',x,x,x);

dec=100:octal=144:hex=64

0dec=100:octal=0144:hex=0x64

知識點二gcc編譯過程

gcc編譯過程,總共有4個階段。

例如:現在要編譯demo.c文件

1、預處理階段

語法:gcc-Edemo.c-odemo.i

其中:-E:為gcc預處理指令,只做預處理,其他部分不做

-。:為將文件指定生成文件名

①去注釋〃:為單行注釋,僅對該行生效/**/多選注釋,會將其包含的內容全部注釋。

②頭文件展開:

③宏替換:de行ne是傻瓜式替換,系統并不會對優先級進行處理。所以,當進行宏定義

的時候,如果該宏牽涉到優先級計算,用戶需要自己通過小括號來標定優先級。

注意:typedef與#define的區別

#define在預處理階段生效,它會直接執行簡單的宏替換,將de幣ne的內容替換成定義

的內容;而typedef在編譯階段生效,它的作用是將typedef的內容取一個別名,那么在編

譯階段,那個別名就會按照正確的名字進行編譯。

#include<stdio.h>

#definex3+3

#definef(x)(x+x)

#defineINTint

typedefinttit;

intmain(intargc,char**argv){

INTa=3;

titb=5;

pctntf("你好,世界!\n");

printf("%d\n",f(5)*f(5));

return0;

)

④標記行號

注意:預處理只做以上部分,程序中如果有語法錯誤,并不會在預處理階段體現出來。

2、編譯階段(整個編譯過程的核心階段)

語法:gcc-Sdemo,i-odemo.s

這個階段會對待編譯文件的詞義,語義,語法進行分析,優化并確保正確。當以上所有

內容都正確時,生成$文件-匯編文件。

3、匯編階段

語法:gcc-cdemo.s-odemo.o

將匯編語言,轉換成計算機能夠識別的二進制語言。

4、鏈接階段

語法:gccdemo.o-odemo

鏈接動態庫和靜態庫

將demo.o這個二進制文件使用-。參數指定生成名字為demo的可執行文件。

zhu@ubuntu:~/cyuyin/day2$gcc-EdemoZ.c-odemo2.i

zhuQubuntu:~/cyuytn/day2$gcc-Sde(no2.i-odemo2.s

zhu@ubuntu:~/cyuyin/day2$gcc-cdemo2.s-odemo2.o

zhu@ubuntu:~/cyuy3Mgg#$.95£心皆2.0de

注意:

使用gccdemo2.c-odem2生成指定文件名的可執行程序。

知識點三變量

1、變量:

在程序運行中,隨時可能改變的量

在程序運行中,如果不使用變量來編程,那么每一次數值的改變,都需要重新修改程序

并編譯。而使用變量的話,只需要對變量重新動態賦值,就可以達到目的。

名字:a大小:4空間上的值:5空間上的地址:OXfffOOl

____/1

地址由系統隨機分配

___7

2、變量的類型

短整型short

C語言包含的數據類型如卜圖所示:整整型int

‘數值類型《長整型long

單精度型float

浮點型

基本類型雙精度型double

〔字符類型char

,數組

C<結構體struct

構造類型I共用體union

據、

類I枚舉類型enum

指針類型

(空類型void

1)、整型:

①普通整型:int-2八31~2A31-1用%d進行格式占位,在32/64位系統中占據4個字節

大小

②長整型:long-2人63~2A63-1用%Id進行格式占位,在32/64位系統中占據8個字節

大小

③短整型:short-2^15-2^15-1用%d進行格式占位,在32/64位系統中占據2個字節

大小

#注意:1K=1O24BlB=8bit(位)

L計算機中,不存在減法操作,如果需要執行減法計算,則通過加上一個數的負數來

實現。

1計算機中所有的二進制數據都是補碼的形式存在于計算機中:

什么是補碼:

?源碼:人為的從十進制轉換成二進制的數。

?反碼:在源碼的基礎,符號位不變,其它位取反。

?補碼:在反碼的基礎上+1。

以上概念只針對負數,而正數的補碼為源碼本身。

sizeof():用來測量一個變量/一個數據類型在內存空間中占據的字節大小。

2)、字符型char使用虹來進行格式占位

字符型變量能夠儲存所有單個的數據,包含但不限于2~2人~乙0~9,!,?。由于有一些特殊

字符在程序中無法通過可視化操作來表示出來,所以我們人為的為所有字符編制了一個帶有

序號的表格,這個表格就是ASCII碼表

3)、浮點型:儲存所有的小數數據

單精度浮點型-float,使用蜥進行格式占位,在內存占4個字節,最高位為符號,第2

到9位為指數位,10到32位為尾數位,float一般精確到小數位后6位,即保證6位有效。

雙精度浮點型-double,使用%lf進行格式占位,在內存占8個字節,最高位為符號,第

2到12位為指數位,13到64位為尾數位。double類型一般精確到小數位后12位,即保證

12位有效。

注意:

①浮點型數據不涉及位運算。

②浮點型的數據不能直接進行大小的比較

我們可以使用%g來占位浮點型數據,這樣只會打印出有效位。還可以使用%.nf來打印

小數點后n位數據,使用這種占位符打印的數據,在顯示的時候會四舍五入(即數據本身沒

有發生改變)。

9returnpswd-data>-0.0O0001|&&pswd-

data<0.000001"/這才是一個double數據代表==0的正確表述方式

4)、空類型void

5)、自定義類型

6)、指針類型

指針是一個值為內存地址的變量(或數據對象)。正如char■類型變量的值是字符,int類

型的變量的值是整數,指針變量的值地址。在C語言中,指針有許多用法。要創建指針變

量,先要聲明指針變量的類型。

3、變量命名規則

i.禁止數字開頭命名變量(語法上的禁止)

ii.禁止以系統關鍵字命名變量(語法上的禁止)

iii.變量的名字需要有其意義

當一個變量的意義有多重修飾時,可以采用以下兩種規則命名:

?下劃線命名法:

?駝峰命名法

?匈牙利命名法

?帕斯卡命名法

知識點四運算符

1、算術運算符%

/:除數不能為0;

%:對除法操作結果取余數,兩個數據不能為浮點型,如果需要對浮點型數據進行取余操

作,可以對原數據進行強制類型轉換,將兩個double類型的數據(在運算過程中)轉換

成int類型。

強制類型轉換(int)a(目標類型)變量

2、賦值運算符:=,+=,-=,/=,*=……

例如:a=a+b;代表將b+c的運算結果賦值給a。'=’會將等號的右值賦值給左值。

a-=b;等價于a=a-b代表將a-b的運算結果賦值給a。

賦值運算符的優先級非常的低。所以當有賦值運算符存在的時候,都是先計算右值,再

賦值給左值的。

3、比較運算符:>,<,>=,<=,==,!=

正如之前所說,每一個表達式,都會產生一個計算結果。如果表達式成立的計算結果為

1(也就是真),不成立的計算結果為0(也就是假)。

4、單目運算符(自增運算符)++,一

如果對inta=0進行自增操作,有收下兩種方式

a++==a+=l==a=a+l后加加:先賦值,后運算(這里所謂的賦值對象,

為a++這個表達式本身,先將a=0的值賦值給a++,然后再執行自增操作,得到a=l.)

++a==a+=l==a=a+l前加加:先運算,后賦值(先將a=0進行自增運算,

再將得到的a=l的結果賦值給++a表達式本身)

注意:無論是使用a++不是++a,a的值都會自增1。

5、邏輯運算符:&&.||.!(與,或,非),

對于邏輯與(&&),當參數兩者都是真的時候,表達式結果為真;其它情況為假。

對于邏輯或(||),當參數兩者任意一個為真的時候,表達式結果為真,其它情況為假,

(有一真,則為真)。

對于邏輯非(!),真則為假,假則為真。

當三個變量進行大小比較的時候:

6、三目運算符

用來計算兩個數據之中較大/較小的數量哪一個。即,計算完成后,整個表達式的計算結

果應該是進行比較的兩個數其中之一。

例如:inta=2,b=3;intbigger=0;bigger=(a>b)?a:b;

括號內結果為邏輯真假,?可以理解成是否成立。如果括號邏輯為真,則整個表達式

取‘:’的左值,反之則取右值。

7、位運算符:位運算符都是針對二進制數進行位運算

①按位與-&:都為1,則為1,其它情況為0

②按位或-I:有1為1,全0為0。

③按位取反一:1為0,。為1;

④按位異或-人:相同為0,不同為1.

inta=10;

intb=8;a和b可以是相等的,但是

a—3AR?

b=a^b;他們卻不能是同一個個體

a=aAb;

⑤左移<<

右移>>

a&=~(l<<n),將a從右往左數,第n+1盞燈關閉。

a|=(l?n),將a從右往左數,第n+1盞燈打開。

知識點五語法結構

[、順序結構

代碼從上到下,從左到右依次執行。

2、分支結構

代碼根據給定的條件,直接跳轉到與條件相符合的分支中,繼續執行。

①判斷語句-if語句

講法格式:if(邏輯){

語句;

如果“邏輯”為真,則執行“語句”,邏輯不成文則跳過整個if語句,繼續執行if語句

之后的代碼。

②二選一選擇語句:if(邏輯){語句1;}else{語句2;}

如果“邏輯”為真,貝IJ執行“語句r,邏輯為假則執行“語句2”,完成后繼續執行選

擇語句后面的代碼。

③多選一選擇語句:if(邏輯1){語句1;}elseif(邏輯2){語句2;}……elseif(邏輯n){語句

n;}else{語句0;}

系統會從“邏輯V開始,逐條向下執行代碼,直到找到某一個邏輯為真,則直接執行

該邏輯對應的語句,剩余的邏輯不再判斷。如果說多選一語句中存在復數個正確的邏輯,系

統只會執行每一個正確的邏輯對應的語句。如果所有邏輯都為假,直接執行“語句0”。

Switchcase語句:

語法:

switch(表達式){

case常量1:

語句1;

break;

case常量2:

語句2;

break;

case常量n:

語句n;

break;

default:

語句0;

break;

}

解釋:“表達式”可以是一個變量,可以是一個算數表達式,可以是擁有返回值的函數。

這個“表達式”不管存放什么形式的數據,最終必須導出一個結果,這片結果可以是任意的

數據類型。通常情況下,一般都是整型變量或者字符型變量。

當“表達式”的值與某一個case后面常量相等時,則直接跳轉到該case分支中,執行

對應的語句,其它case中語句不再執行。

如果有多個case滿足條件,則只會執行第一個滿足條件的case語句。

如果沒有case滿足條件,則跳轉到default執行“語句0”(default)

注意:

Lswitch-case語句,只負責跳轉進入,不負責跳出。跳出功能由break負責。

』switch-case語句中,case分支中不能申請變量。

,break語句只能跳出分支與循環結構。

3、循環結構

代碼根據給定的條件是否成立,如果條件成立執行循環體內部的語句,如果條件不成立,

執行循環體外部語句。

循環三要素:①循環條件,②循環變量的初始化,③循環變量的改變方式

注意:

/循環條件必須與一個變量掛鉤,否則循環條件不變的話,要么無限循環,要么從不

循環。

/循環條件必須隨著每一次循環進行改變,來保證第一次循環都可能結束循環。

/循環旨在用來解決一些重復操作的計算,使得代碼的重復率降低,提高編程效率。

/當程序本身不確定某一個計算具體要執行多少次的時候,但是卻又明確程序循環退

出點在哪。此時,就可以使用循環來解決問題。

1)、for循環語句

語法:for(表達式1;表達式2;表達式3){語句1}

釋義:

“表達式r是循環變量的初始化,也就是循環變量從哪一個點開始做改變。

“表達式2”循環條件,滿足該條件,則進入循環,執行語句1。直到某次循環的時候,

條件不滿足,則退出循環。

“表達式3”循環變量的改變方式,

注意:如果循環中,嵌套了一個判斷語句,判斷語句中存在一個break,如果執行該break,

無法當前循環條件是否滿足,都會直接退出循環。

如果循環語句沒有那么在循環體后緊跟著的1條代碼,屬于這個循環體。if語句

同理。

2)、while循環語句

語法:while(邏輯判斷){語句};

解釋:當“邏輯判斷”為真時,則會執行循環體“語句”,直到'‘邏輯判斷”為假。

這里的循環準備條件需要寫在while語句之前,不能像for語句一樣可以直接寫for里

面。

注意:

循環變量的改變方式注意一定寫在“語句內部”

3)、dowhile循環語句

語法:d。{語句;}while(邏輯判斷)

解釋:先執行一次“語句”,再進行“邏輯判斷”,“邏輯判斷”如果為真,則會循環執

行“語句”,直到“邏輯判斷”主假。

dowhile和while的最大區別在于,dowhile不管邏輯是否為真,至少執行一次循環語

句。

d。while一般使用的環境:在項目中,可能存在這樣的邊界條件,使得第一次循環可能

不滿足循環條件,但是之后的所有循環直到結束為止都是滿足條件。此時如果使用while循

環,就不會進入循環。可以使用dowhile來解決這種問題。

continue關鍵字:可能使用在循環語句當中。

解釋:當循環過程中,遇到continue關鍵字,則會直接結束本次循環,開始下一次循環

(也就是說,一旦遇到continue,那么continue之后所有循環體代碼不再執行,重新從循

環的開關開始執行。)

變量的作用域以及生命周期:

i.生命同期范圍,通常都在一個“0”內八

ii.當一個變量生命周期結束后,則無法再訪問該變量。

iii.在相同作用域內,變量名不能重復。但是在不同作用域內,變量名允許重復。遇到

這種情況,系統會訪問最近的作用域內的變量(就近原則)。

隨機函數的使用:

①把相關的函數引用

#include<time.h>^n#include<stdlib.h>

②產生時間因子:Srand(time(O))

③產生一定范圍內隨機數

inta=rand()%99+l;由于rand會產生非常大的一個隨機數,不能保證它的范圍在

1~99之間,所以可以直接對該隨機數取余99,那么結果就是0~98之間的數,再+1之

后,結題就是1~99之間的數了。

gdb調試工具:

1)、一個調試C語言的工具。當程序邏輯正確,沒有錯誤時,則gdb會直接運行

完成程序。當程序中存在邏輯錯誤會導致程序運行中斷,則使用gdb運行程序的時候,

gdb會記錄程序中斷點并停留。

2)、如何使用gdb來調試一個C語言程序?

必須生成一個可調試的可執行文件。使用指令:gcc文件名-g(參數)來生成一個

可調試可執行文件(a.out)。

使用gdb打開該可執行文件:gdb./a/out

3)、gdb中的調試指令:

①r-開始運行程序。

②b行號/函數名:將程序停止在相對應的行號或者函數處。如果說,有多個.c文

件參與編譯,那么斷點的格式為:b文件名:行數/函數名

③P:可以使用p+變量名來打印當前變量的值。

④n:使代碼向下執行一行。

⑤c:全速執行剩余的代碼。

⑥q:退出gdb調試

⑦s:進入函數內部查看函數邏輯

⑧I:查看當前行周圍的代碼

gdb調試的編譯選項gdb調試流程

/調試命令:

gcc(-g1其它選項][文件名]K/^list):杳看所載入的文件

I4(break):設置斷點,程序運行

7\,到斷點即可停止

J:infob:查看設置的斷點情況

</r(run):從第一行開始運行代碼,

調試的是Q.或者指定行開始,可在r后面加

@我行史而不是源代碼))上行號

玄枳演文件進行編譯pn:查看變量n的值

一定要加上選項”-g”,這n(next):單步運行下一行代碼(遇

樣編譯出I制的赤四即執行文件才GDB到函數不會進入函數)

TheGNUProject

包醯畫1塾Debuggers(step):單步運行下一行代碼(遇

到函數會進入函數)

c(continue):恢復程序的運行,

執行剩余的程序

知識點六函數

1、函數的使用目的:

當我將某一個功能封裝成一個函數的時候,那么我修改該功能的時候,只需要修改該函

數。如果程序中,該功能出現若干次,那么我只要修改一次函數,所有功能實現處都會改變。

即,函數提高了我的代碼的重構效率,指提高了工作效率。提高了代碼的重用性。

注:函數中功能的覆蓋性可以廣泛。但是函數的功能越單一越好。舉例說明:一個函數,

如果是用來驗證是否為質數,那么只驗證是否為質數,不輸出。

2、函數的定義:將某一個特定的功能,打包封裝后,稱為函數。那么在該函數外部,

如果需要實現這個特定功能,只需要調用封裝好的函數即可。

3、函數的三要素:、

①函數名:

一個函數的名字,注意,在C語言中,函數名絕對不能重復。

②函數返回值類型:

什么叫函數的返回值:如同所有的表達式都會得到一個運算結果。那么對于函數,

當發生調用函數時,調用函數的語句就是一個表達式,這個表達式得到的運算結果,僅僅取

決于函數的返回值(如果我們想將一個特定的值給到函數表達式本身。那么只要在return后

面寫上該特定值,當函數調用完成后,函數表達式本身的值就是該特定值)。

③函數的參數列表:

一個函數在運算過程中,如果需要使用外部的變量,則可能通過參數列表的形式,來得

到這個外部變量的值。

注意:

①函數定義的時候,參數列表稱為形參。

②函數調用的時候,參數列表稱為實參。

③發生函數調用的時候,會將實參的值賦值給形參。

④函數調用完成時,形參并不會賦值給實參。而是會將返回值賦值給函數表達式本身

⑤可變參數函數:參數的數量根據實際需求,動態改變。

但是注意:無論怎么改變,必須有一個固定參數(第一個參數)。

linclude<stdarg.h>〃可變參數的相關頭文

voidshow_array(constdouble

double*new_d__array(intn,

intmain()

double*Pl;

double*P2;

Plnewd_array(5Z1.2,2.3,3.4,4.5,5.6);

P2new_d_array(4,100.Oz20.00,8.08,-1890.0);

show_array(pl,

show__array(p2,笨、函數調用時,必須指明參數個數,即第

free(pl);參數要寫明

free(p2);

return0;

voidshow_array(constdoublear[]rintn)

(-

double*new_d_array(intn,...)

va_listap;〃聲明對象來保存參數

int1;

double*pt;

va_start(ap,n);〃把ap初始化為一個參數列表

pt=(double*)malloc(n*sizeof(double));

for(i=0;i<n;i++)

pt[i]=va_arg(aprdouble);〃訪問參數列表中的每個

va_end(ap);

可變參數的函數使用:1

關閉回顯system("sty-echo");〃函數會將輸入的字符在終端上執行。

打開回顯system("sttyecho");

使用system函數時需要使用#include<stdlib.h>

4、遞歸函數

函數自己調用自己

遞歸函數的3要素:

A自己調用自己

上要有明確的退出點,否則就會造成棧溢出

1每一次遞歸,必須逐漸趨近于遞歸退出點。

遞歸的思想:在某些復雜的問題中,我們并不知道這個問題的解是多少。此時可以將該

問題分解成邏輯相似的簡單問題去解決。如果這個簡單的問題依舊無法解決,繼續分解。當

分散到最低層的時候,我們需要給最低層問題一個確切的解。此時由于最低層已經解決,那

么依賴于低層問題的上一層問題也能解決,依次逐層向上解決,直到解決最高層問題為止。

注意在遞歸函數中,嚴禁使用static.如果遞歸函數中使用static變量來完成邏輯計算,

那么當你第一次遞歸函數的時候,能夠算出正確的結果。但是當第二次調用這個遞歸函數的

時候,結果肯定是錯誤的。

遞歸和循環的區別:

循環在時間復雜度上會很高,但是其空間復雜度一定會很低。

遞歸在空間復雜度上會很高,但是其在時間復雜度上不一定會低。當設計合理時,遞歸

的時間復雜度會非常非常的低。

對一個地址(一個十六進制的數)前面加上代表著系統會跑到該地址上,將該地

址值上的值取出來使用。

例如:0x01上保存的值為2

此時,我有一個地址變量p==0x01

那么,此時,*p==2;

printf("%.*lf\n",nzres);

程序的分文件:

第一步,編寫相關頭文件(.h)

示例代碼:

#ifndcf_hcad_h

#define_head_h

#include<stdio.h>

intadd(inta4ntb);〃函數原型

#endif

第二步,在主文件中包含相關自定義的頭文件(main所在函數中)

#inelude"hcad.h"

第三步,編寫函數實現文件(.C)

#includc"hcad.h"

intadd(intajntb){retruna+b;}

知識點七硬件

lx內存(ram)

a)掉電則數據丟失

b)讀取速度很快

c)隨機訪問:申請內存的時候隨機申請內存空間;訪問內存的時候,直接訪問。

2、硬盤(rom)

a)掉電數據不會丟失

b)訪問速度慢于內存

c)模塊化訪問

3、內存空間的分類

a)棧內存空間:

①linux系統棧空間默認大小10mb(我們的ubuntu默認的棧空間大小大概在2m左右),

②棧內存空間都是先進后出的。

③棧內存中保存的變量都叫自動變量,自動變量的特點,申明時,自動申請內存空間,

結束時自動釋放內存空間。(申請空間代表用戶向系統申請一片內存空間的使用權限。釋放

空間代表系統回收了該內存空間的使用權限。)

④絕大多數的棧內存都是從高地址向低地址生長,這就是意味著先申請的數據,會存放

在高地址,后申請的會在低地址。無論是向你低地址生長,還是向高地址生長,系統都會滿

足用戶的一般邏輯思維。就是說,在申請某些數據結構的時候(可以存放復數數據的結構),

寫在前面的數據總歸在低地址。

注意:

L根據棧特性,我們可以認為自動變量就是局部變量。

2.嚴禁在函數內部返回一個局部變量的地址。

局部變量屬于函數內部,不屬于main函數,當函數調用完畢,局部變量被系統回收,

該地址使用權不屬于用戶,而主函數內部卻可以通過地址的方式直接訪問到該地址,這就變

成了一個非法操作。所以系統會提示警告。在編程過程中,需要盡量避免出現這種情況。

3.針對以上情況,存在著一種情況,可以向外返回一個局部變量的地址,并且運行不報

錯。那就是棧內存入侵。

b)堆內存空間

堆內存空間上的數據都是由用戶手動申請空間,并且手動釋放。(只要申請了不釋放,

那么在哪里申請,怎么返回都是合法的。)

調用函數時,在函數中定義的變量是在堆內存中

c)靜態存儲區

靜態存儲區中,存放了靜態變量,靜態存儲區存在于整個程序的運行過程之中。

static關鍵字,能夠修飾局部變量和全局變量,

static修飾局部變量的時候,會將該變量存儲到靜態存儲區內去。達到延長生命周期的效果。

注意:

static僅僅延長了變量的生命周期,并沒有擴展變量的作用域。

extern:可以引用外部全局變量

當static修飾全局變量的時候:限制作用域,此時這個全局變量的作用域被限制在當前

文件內。

d)常量存儲區

主的數中a的內存管理

:dd函數中,形參a的嚴存管理主函數中a的內存管理ad函數中a的內存管

名:a名:a

名:&a名:a

大小:4大小:4

大小:8大小:8im*類型

值:2值:2

值:0x01值:0x01

地址:

0x01儂止:0x02地址:0x10

*a(*0xuI)=2

用了一個不屬于我的地址

本書設定編譯器中(limits.h>的內容如代碼清單7-1所示.

代碼清單7-1

ttdefineUCHARMAX255U*unsignedchar

WdefineSCHAR_MIN-128*signedchar'jit

^defineSCHAR二MAX+127*signedcharIjh

"defineCHAR_MIN0*char-J/ti,pl'-;?

^defineCHAR^MAXUCHAR_MAX?charTj/ii).(■[?

^defineSHRTMIN-32768*shortint二小」,

*defineSHRTMAX+32767*shortint。派人?

^defineUSHRT_MAX65535U?unsignedshort

ttdefineINT__MIN-32768?int!';/d?

^defineINT_MAX+32767?int!;公大々*

*defineUINT_MAX65535U*unsignedint/:公,?

?defineLONG-MIN-2147483648L*longint?

^defineLONG二MAX+2147483647L*longintifjM,舟?

^defineULONG_MAX4294967295UL?unsignedlong:;

知識點八數組

1)、數組:是一個能夠存放若干個相同數據類型的數據結構

注意:在聲明數組的時候,想要往數組內存放什么數據類型,那么就必須給這個數組聲

明成對應的數據類型。

2)、數據的聲明及定義:

數組的數據類型+數組名[數組的容量尸{實際數據(每一個實際數據使用‘,‘分隔開小

示例:

①:intarr[5]={0,1,2,3,4};

②:intarr[5]={4};將數組中的第0個元素初始化為4,其它元素初始化成0;

③:intarr[5]={0};將數組中的所有元素初始化成0;

注意:

①在聲明數組的時候,可以不規定數組長度,但是必須初始化數據。如:intarr[]={(),

1,2,3,4};因為系統在運行到數組聲明部分時,必須向內存空間申請一片固定大小的內存。那

么數據的聲明部分沒有給到系統數組的大小是多少,那么系統就會去數組的定義部分,查找

數組的實際的長度,用來向系統申請空間大小。

所以說,系統會優先查看數組聲明部分的容量,再去查看數組實際定義的長度來申請內

存空間。如果聲明和定義都沒有約定數組的容量,那么導致編譯報錯。

②當數組的容量使用一個變量去聲明的時候,則此時不能定義數組。因為變量的值可能

發生改變,當數組使用變量去聲明長的時候,系統肯定不會知道數組的確切長度是多少,此

時如果給該數組做了明確的定義,可能導致定義的長度比實際數組容量要大。所以系統禁止

使用變量聲明容量的時候同時去定義該數組。

3)、數組的訪問

數組名[數組元素位置];

示例:

有一個數組intarr[5]={0,1,2,3,4};如要訪問第1個元素和第2個元素,使其相加,導出

結果:arr[l]+arr[2]==3(數組的下標是從。開始計算的);

4)、訪問整個數據結構

訪問整個數據結構這個思想,在所有數據結構中都是通用的,并且是所有功能的基礎。

我們把訪問整個數據結構的過程稱作:遍歷——對一個數據結構中的所有數據,全都并

且僅訪問一次。

所有數據結構都會面臨如下課題:

數據結構的增、刪、改、查、排、遍歷

數組名本身是一個地址,這個地址和該數組首元素的地址是一樣的。

SLEEP(3)LinuxProgrammer^Manual

NAME

sleep-sleepforthespecifiednumberofseconds

SYNOPSIS?一

/Include<unistd.h>

unsignedtntsleep(unstgnedtntseconds);

DESCRIPTION

4)、二維數組

intarr[m][n];表示二維數組有n列m行即由m個有n個元素的一維數組組

成。示例:intarr[2][3]={{l,2,3},{4,5,6}};

逗號運算符:可以用來將一個表達式隔開成若干個表達式,使得每一個表達式獨立運算,

但是整個表達式的值取最末尾表達式的值。

5)、數組的排序:

①冒泡排序:邏輯最簡單,代碼也最簡單,但是時間復雜度最高(效率最低)。

使用比較運算符,當發現兩者之間的最大值出現,就立即進行換位。

②選擇排序:比冒泡難一點,但是效率高。

使用比較運算符,查找出第一位置的元素并記錄好下標,當遍歷完畢后再把找到的元素

進行換位。

③快速排序:代碼難度最為高的一種排序方式,但是效率非常高。

6)、字符數組

字符數組能夠和整形數組一樣的使用方式,但是字符數組有其特殊的使用方式。

6.1字符數組的聲明及定義:

①如同其它數組一樣定義:

charstr[20]={'h'e'1'1'o'};

②字符數組特有的定義方式:

charstr[20]=whellow;

6.2字符數組的使用:

①如同整型數組一樣輸入輸出

charstr[20]={'h'e'/TTo'};

fbr(inti=0;i<5;i++)

{scanf(“%c",&strR]);printf("%c”,str[i]);}

②字符數組特有的輸入輸出

charstr[20]={0};

scanf(a%sw,str);//scnaf中%(1要求是int*類型,%c要求的是char*類型,%s要求的是

char*類型,

printf("%s\n",str);〃scnaf中%(1要求是int類型,%c要求的是char類型,%s要求的是

char類型,

注意:在字符數組中,系統默認會在每一個字符數組/字符串的結尾位置,加上結束

符'\0'(也就是空字符)。

由于以上特性,我們在設計字符數組的時候,最大容量最低要求要比實際長度多1.

6.3字符數組的函數:#include<string.h>

①strlen,用來測量一個字符數組的實際長度,

參數列表:目標字符數組

返回值:返回字符串的長度。

②strcpy(sl,s2);,用來實現字符數組的拷貝,

功能:復制字符串s2到字符串slo是字符數組/字符串之間唯一的相互賦值的方法。

使用該函數的時候,目標字符數組盡量比源字符的容量要大。

③strcmp(s1,$2);

如果si和s2是相同的,則返回0;如果sl<s2則返回小于0;如果sl>s2則返回大

于0o是比較ascii的值。返回的是兩者的差值

④strcat,用來拼接兩個字符數組/I個字符數組和1個字符串

參數列表:字符數組1,字符數組2/字符串

返回值:將更新后的"字符數組1”返回

⑤strtok用來分隔字符串

參數列表:待分隔的字符串,分隔字符串

返回值:分隔后取出來的第一個字符串;

⑥mcmcpy用法:

參數列表:目標指針,源指針,需要復制的數量

函數功能:將源指針上的內容,復制到目標指針指向內存空間上,復制的內存空間

大小,為第三個參數。

返回值:將更新后的目標指針返回。

知識點九指針

1、指針的概念:

指針的全稱:指針變量(相對應的有指針常量。),是一個變量,該變量可以用來保存一

個數據。保存的數據是一個十六進制的地址,給一個指針進行賦值操作的時候,稱為“指向”O

2、定義及聲明:

①一個完整的指針定義方式:

變量類型+“*”+變量名

②指針變量的大小:

一個指針在32位系統中,占4個字節大小,在64位系統中,占8個字節大小。

3、指針的取值操作:*

對一個地址進行取取*操作,就會直接取到該地址空間上的值。

同理,對一個指向一片地址空間的指針進行取*操作,同樣會取到那片地址空間上的值。

使用指針是特別注意,一個指針指向的數據是哪一個數據,以及一個指針取*后是哪一

個數據。

4、指針變量的類型:

所有數據類型,都可以變成該數據類型的指針。

?int*代表int類型的指針

?char*代表char類型的指針

?int**代表int*類型的指針

?void*代表通用指針

通用指針可以作為左值接受任何類型的指針數據。但是通用指針有一個缺點:它不可以

直接取值。通用指針保存的數據,系統并不會知道這個數據具體是什么數據類型,所以帶該

地址進行取*操作的話,系統不知道需要分配多少緩存空間。所以,在對void*通用指針進行

取*之間,需要對該通用指針明確數據類型。

對一個通用指針明確數據類型:強制類型轉換。

void*不代表空指針,而代表通用指針,將指針設置為空指針應用NULL來代表,或者用

0。

*((int*)pl));

5、指針與函數的關系:

①函數參數使用指針傳參的形式:將地址傳給函數內部,函數外部與函數內部變量同步

發生改變。

但是依舊會發生實參給形參賦值的操作:這個操作代表了形參保存了實參的值,由于實

參是一個變量的地址,所以形參實際上保存的就是該變量的地址。所以在函數內部對該地

址進行改變的地里,實參也在改變。

②函數名本身也是一個指針,它不能作為左值,只能作為右值。

函數指針可以用來接受一個函數名,接受之后,調用這個指針,就相當于在調用該函數。

函數指針聲明方式:指向函數的返回值類型+指針變量+(指向的函數的參數列表的具

體格式);

double(*cal[5])(void*,void*)={add,pos,mul,div,mod};

6、指針與數組的關系:

數組名本身就是一個指針,但是需要注意的是,數組名這個指針不能作為左值去指向其

它地方,它只能作為右值給其它指針賦值。數組名這個指針是一個常量。

指針的偏移:

通過對已知的指針進行+或-操作,來實現訪問到與已知指針相關的其它內存空間。

指針偏移的量(即一個指針+1后,地址增加的絕對值):它根據數據類型的大小模塊化

偏移。

數組名指向數組首元素的地址。

一個用來存放指針的數組,稱為指針數組。那么一個用來指向數組的指針,就稱為數組

指針。我們嚴格意義上說的數組指針,它是一個指向二維數組的指針。

intarr2[2][3]={

{1,2,3}.

{4,5,6}

};

/*申請一個指針指向該數組*/

int(*pl)[3]=arr2;

二維數組和指針數組的區別:

指針小結:

1.指針是一個變量,

溫馨提示

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

評論

0/150

提交評論