c語言之疑惑問答

2021-09-24 16:54:25 字數 4011 閱讀 5082

在我們學習當中,我們會思考很多問題,下面我們就提出幾個針對前面學習的東西的一些疑惑。

#include

intmain()

else

return0;

}

這段**的執行結果居然會是a凡是函式內部定義的都在stack區,都是全域性變數。凡是函式外部定義的變數都在data區,是全域性變數?

這段話是有問題的,因為當我們定義乙個stact的靜態區域性變數時候,這個時候就不是在stack區,而是data區。

資料區(靜態區)

全域性變數和靜態變數存放在此. 裡面細分有乙個常量區, 字串常量和其他常量也存放在此. 該區域是在程式結束後由作業系統釋放.

continue的作用是跳出本次的迴圈,並且要進行下一次的迴圈。他在不一樣的迴圈中,跳出的位置也不一樣,比如在for迴圈中,當我們執行了continue以後,那麼迴圈體後面的**將不再執行,而是跳轉到for(***1;***2;***3)中的***3語句開始下一次的迴圈。但是當在while語句或者do{}while(***1);當中,continue會跳轉到***1語句繼續判斷執行。continue一般只在迴圈結構**現,而且一般在乙個選擇結構中。

break語句不只是可以在迴圈中使用,並且可以在switch語句中使用。在迴圈中的break意味著結束整個迴圈週期,跳出離他最近的一層的迴圈,實際上break也可以用於多層迴圈的跳出,這樣一段**:

#include

intmain()

}}return0;

}

給外層迴圈起個名字就可以跳出了。

break在switch語句中的作用是:使得程式跳出switch,執行switch結構以後的**。

c語言的return也就意味著當前函式停止執行。

return 語句可以有多個,可以出現在函式體的任意位置,但是每次呼叫函式只能有乙個 return 語句被執行,所以只有乙個返回值。

函式一旦遇到 return 語句就立即返回,後面的所有語句都不會被執行到了。從這個角度看,return 語句還有強制結束函式執行的作用。

return 語句是提前結束函式的唯一辦法。return 後面可以跟乙份資料,表示將這份資料返回到函式外面;return 後面也可以不跟任何資料,表示什麼也不返回,僅僅用來結束函式。

goto 語句是一種無條件流程跳轉語句,通常 goto 語句與 if 語句結合使用,當滿足一定條件時,程式流程跳轉到指定標號處,接著往下執行。

其中,「語句標識」可以是任乙個合法的識別符號,如 pos_1、pos_2、label_1、label_2 等都是合法的語句標識。注意,語句標識後的冒號不能省略。

程式將從對應「語句標號」的**處開始往下執行。

e.g

#include

int main (

void

)printf

("成功輸入正整數:%d\n"

,n);

return0;

}

通過上述執行流程及執行結果的分析,可以發現該例中使用 goto 跳轉語句實現了迴圈的功能。故可以使用迴圈結構的**替換該 goto 結構的**。使用 goto 語句可能會造成程式層次不清晰,可讀性差,故在實際程式設計中,應盡量少使用或避免使用 goto 語句。

#undef 識別符號

用來將前面定義的巨集識別符號取消定義。

這樣一段例項**:

#include

#define int int *

intmain()

這樣就可以實現區域性替換了,後面如果想要使用可以繼續#define來定義。

jmp 無條件轉移指令

add 加法.

mov 傳送字或位元組.

push,pop 把運算元壓入或取出堆疊

sub 減法指令

eax 是"累加器"(accumulator), 它是很多加法乘法指令的預設暫存器。

ebx 是"基位址"(base)暫存器, 在記憶體定址時存放基位址。

ecx 是計數器(counter), 是重複(rep)字首指令和loop指令的內定計數器。

edx 則總是被用來放整數除法產生的餘數。

esi/edi 分別叫做"源/目標索引暫存器"(source/destination index),因為在很多字串操作指令中, ds:esi指向源串,而es:edi指向目標串.

ebp 是"基址指標"(base pointer), 它最經常被用作高階語言函式呼叫的"框架指標"(frame pointer). 在破解的時候,經常可以看見乙個標準的函式起始**:

push ebp ; 儲存當前ebp

mov ebp,esp ; ebp設為當前堆疊指標

sub esp, *** ; 預留***位元組給函式臨時變數.

…這樣一來,ebp 構成了該函式的乙個框架, 在ebp上方分別是原來的ebp, 返回位址和引數. ebp下方則是臨時變數. 函式返回時作 mov esp,ebp/pop ebp/ret 即可.

esp 專門用作堆疊指標,被形象地稱為棧頂指標,堆疊的頂部是位址小的區域,壓入堆疊的資料越多,esp也就越來越小。在32位平台上,esp每次減少4位元組。

eip 暫存器,用來儲存cpu要讀取指令的位址,cpu通過eip暫存器讀取即將要執行的指令。每次cpu執行完相應的彙編指令之後,eip暫存器的值就會增加。

ret 棧頂字單元出棧,其值賦給ip暫存器。即實現了乙個程式的轉移,將棧頂字單元儲存的偏移位址作為下一條指令的偏移位址。

call call指令經常和ret指令配合使用,因為cpu執行call指令進行兩部操作將當前ip或cs和ip壓入棧中轉移(相當於jmp指令)call指令不能實現短轉移(短轉移8位位移,近轉移16位位移),除此之外call指令實現轉移的方法和jmp指令的原理相同(只是多了乙個將cs、ip入棧)。

dword ptr:dword 雙字 就是四個位元組ptr pointer縮寫 即指標

裡的資料是乙個位址值,這個位址指向乙個雙字型資料

比如mov eax, dword ptr [12345678] 把記憶體位址12345678中的雙字型(32位)資料賦給eax 。

const 最好是賦初值,否則可能出現不可預料的後果。

你無法排除編譯器直接將const變數當成常量來用,另外,全域性變數有些編譯器會預設賦值0.

const關鍵字的作用主要有以下幾點:

(1)可以定義const常量,具有不可變性。

例如:const int max=100; int array[max];

(3)可以避免意義模糊的數字出現,同樣可以很方便地進行引數的調整和修改。

(4)可以保護被修飾的東西,防止意外的修改,增強程式的健壯性。還是上面的例子,如果在函式體內修改了i,編譯器就會報錯;

例如:void f(const int i)

(6) 可以節省空間,避免不必要的記憶體分配。

例如:#define pi 3.14159 //常量巨集const doulbe pi=3.14159; //此時並未將pi放入rom中 …doublei=pi; //此時為pi分配記憶體,以後不再分配!double i=pi; //編譯期間進行巨集替換,分配記憶體double j=pi;//沒有記憶體分配double j=pi; //再進行巨集替換,又一次分配記憶體!const定義常量從彙編的角度來看,只是給出了對應的記憶體位址,而不是象#define一樣給出的是立即數,所以,const定義的常量在程式執行過程中只有乙份拷貝,而#define定義的常量在記憶體中有若干個拷貝。

(7) 提高了效率。編譯器通常不為普通const常量分配儲存空間,而是將它們儲存在符號表中,這使得它成為乙個編譯期間的常量,沒有了儲存與讀記憶體的操作,使得它的效率也很高。

c和c++中區別與聯絡:

const int n = 10;

在c中n是乙個唯讀變數,n的值執行時才知道,占有記憶體

在c++中n是常量,編譯時就有值,直接替換使用的地方,不佔記憶體

比如

const int n = 10;

int a[n];

用c編譯是編譯不過的,因為n是變數,編譯的時候大小不知道

但用c++編譯可以編譯通過,因為n是常量,相當與 #defind n 3

C語言疑惑

c語言 存款預算 假設銀行一年整存零取的月息為1.875 現在某人手頭有一筆錢,他打算在今後5年中,每年年底取出1000元作為孩子來年的教育金,到第5年孩子畢業時剛好取完這筆錢,現在算一算第1年年初時他應存入銀行多少錢?define rate 0.225 rate 12 1.875 intmain ...

c 語言使用疑惑小記

第一段程式 關於一級指標與二級指標 int p null int p2 p cout p 這裡需要注意的是 null 不代表位址0,或者說在windows中代表0.null作為乙個巨集定義,任何系統均有自己的實現方式。代表乙個不可取值的地方 二級指標是指向一級指標的位址,與null無關。分水線第二段...

C語言 C語言之continue

c語言迴圈 c 語言中的continue語句有點像break語句。但它不是跳出該迴圈語句,continue是跳過本次迴圈直接開始下一次迴圈的。在for迴圈裡,continue會跳過本次迴圈,但是自增語句仍然會執行,而在while和do while語句裡嘖是跳過迴圈重新執行判斷語句 課堂作業內容為 輸...