tft每日頭條

 > 生活

 > c語言前後區别

c語言前後區别

生活 更新时间:2025-01-11 00:11:35

c語言和C 到底是什麼關系?

首先C 和C語言本來就是兩種不同的編程語言,但C 确實是對C語言的擴充和延伸,并且對C語言提供後向兼容的能力。對于有些人說的C 完全就包含了C語言的說法也并沒有錯。

c語言前後區别(C語言和C的區别和聯系)1

C 一開始被本賈尼·斯特勞斯特盧普(Bjarne Stroustrup)發明時,起初被稱為“C with Classes”,即「帶類的C」。

很明顯它是在C語言的基礎上擴充了類class等面向對象的特性和機制。但是後來經過一步步修訂和很多次演變,最終才形成了現如今這個支持一系列重大特性的龐大編程語言。

c語言前後區别(C語言和C的區别和聯系)2

1、C語言是面向過程語言,而C 是面向對象語言

我們都知道C語言是面向過程語言,而C 是面向對象語言,說C和C 的區别,也就是在比較面向過程和面向對象的區别。

(1)面向過程和面向對象的區别

面向過程:面向過程編程就是分析出解決問題的步驟,然後把這些步驟一步一步的實現,使用的時候一個一個的依次調用就可以了。

面向對象:面向對象編程就是把問題分解成各個對象,建立對象的目的不是為了完成一個步驟,而是為了描述某個事物在整個解決問題的步驟中的行為。

c語言前後區别(C語言和C的區别和聯系)3

(2)面向過程和面向對象的優缺點

面向過程語言

優點:性能比面向對象高,因為類調用時需要實例化,開銷比較大,比較消耗資源;比如單片機、嵌入式開發、 Linux/Unix等一般采用面向過程開發,性能是最重要的因素。

缺點:沒有面向對象易維護、易複用、易擴展

面向對象語言

優點:易維護、易複用、易擴展,由于面向對象有封裝、繼承、多态性的特性,可以設計出低耦合的系統,使系統更加靈活、更加易于維護

缺點:性能比面向過程低。

c語言前後區别(C語言和C的區别和聯系)4

二、具體語言上的區别

1、關鍵字的不同

C語言有32個關鍵字;

C 有63個關鍵字;

2、後綴名不同

C源文件後綴.c,C 源文件後綴.cpp,在VS中,如果在創建源文件時什麼都不給,默認是.cpp。

3、返回值

C語言中,如果一個函數沒有指定返回值類型,默認返回int類型;C 中,如果一個函數沒有返回值則必須指定為void。

c語言前後區别(C語言和C的區别和聯系)5

4、參數列表

在C語言中,函數沒有指定參數列表時,默認可以接收任意多個參數;但在C 中,因為嚴格的參數類型檢測,沒有參數列表的函數,默認為 void,不接收任何參數。

5、缺省參數

缺省參數是聲明或定義函數時為函數的參數指定一個默認值。在調用該函數時,如果沒有指定實參則采用該默認值,否則使用指定的參。(C語言不支持缺省參數)

· 半缺省參數

c語言前後區别(C語言和C的區别和聯系)6

· 全缺省參數

c語言前後區别(C語言和C的區别和聯系)7

注意:

· 在半缺省的情況下,帶缺省值的參數必須放在參數列表的最後面。

· 缺省參數不能同時在函數的聲明和函數定義中出現,二者隻能選其一。

· 缺省值必須是常量或者全局變量。

· 缺省參數必須通過值參或常參傳遞。

6、函數重載

函數重載:函數重載是函數的一種特殊情況,指在同一作用域中,聲明幾個功能類似的同名函數,這些同名函數的形參列表(參數個數、類型、順序)必須不同,返回值類型可以相同也可以不同,常用來處理實現功能類似數據類型不同的問題。(C語言沒有函數重載,C 支持函數重載)。

c語言前後區别(C語言和C的區别和聯系)8

C語言中産生函數符号的規則是根據名稱産生,這也就注定了c語言不存在函數重載的概念。而C 生成函數符号則考慮了函數名、參數個數、參數類型。需要注意的是函數的返回值并不能作為函數重載的依據,也就是說int sum和double sum這兩個函數是不能構成重載的!

我們的函數重載也屬于多态的一種,這就是所謂的靜多态。

靜多态:函數重載,函數模闆

動多态(運行時的多态):繼承中的多态(虛函數)。

使用重載的時候需要注意作用域問題:請看如下代碼。

c語言前後區别(C語言和C的區别和聯系)9

我在全局作用域定義了兩個函數,它們由于參數類型不同可以構成重載,此時main函數中調用則可以正确的調用到各自的函數。

但是請看main函數中被注釋掉的一句代碼。如果将它放出來,則會提出警告:将double類型轉換成int類型可能會丢失數據。

這就意味着我們編譯器針對下面兩句調用都調用了參數類型int的compare。由此可見,編譯器調用函數時優先在局部作用域搜索,若搜索成功則全部按照該函數的标準調用。若未搜索到才在全局作用域進行搜索。

總結:C語言不存在函數重載,C 根據函數名參數個數參數類型判斷重載,屬于靜多态,必須同一作用域下才叫重載。

c語言前後區别(C語言和C的區别和聯系)10

7、const

C語言中被const修飾的變量不是常量,叫做常變量或者隻讀變量,這個常變量是無法當作數組下标的。然而在C 中const修飾的變量可以當作數組下标使用,成為了真正的常量,這就是C 對const的擴展。

C語言中的const:被修飾後不能做左值,可以不初始化,但是之後沒有機會再初始化。不可以當數組的下标,可以通過指針修改。

簡單來說,它和普通變量的區别隻是不能做左值而已,其他地方都是一樣的。

C 中的const:真正的常量。定義的時候必須初始化,可以用作數組的下标。const在C 中的編譯規則是替換(和宏很像),所以它被看作是真正的常量。也可以通過指針修改。需要注意的是,C 的指針有可能退化成C語言的指針。比如以下情況:

c語言前後區别(C語言和C的區别和聯系)11

這時候的a就隻是一個普通的C語言的const常變量了,已經無法當數組的下标了。(引用了一個編譯階段不确定的值)

const在生成符号時,是local符号。即在本文件中才可見。如果非要在别的文件中使用它的話,在文件頭部聲明:externcosnt int data = 10;這樣生成的符号就是global符号。

總結:C中的const叫隻讀變量,隻是無法做左值的變量;C 中的const是真正的常量,但也有可能退化成c語言的常量,默認生成local符号。

c語言前後區别(C語言和C的區别和聯系)12

8、引用

說到引用,我們第一反應就是想到了他的兄弟:指針。

引用從底層來說和指針就是同一個東西,但是在編譯器中它的特性和指針完全不同。

c語言前後區别(C語言和C的區别和聯系)13

首先定義一個變量a = 10,然後我們分别定義一個引用b以及一個指針p指向a。我們來轉到反彙編看看底層的實現:

c語言前後區别(C語言和C的區别和聯系)14

可以看到底層實現完全一緻,取a的地址放入eax寄存器,再将eax中的值存入引用b/指針p的内存中。至此我們可以說(在底層)引用本質就是一個指針。

了解了底層實現,我們回到編譯器。我們看到對a的值的修改,指針p的做法是*p = 20;即進行解引用後替換值。

再來看看引用修改:

我們看到修改a的值的方法也是一樣的,也是解引用。隻是我們在調用的時候有所不同:調用p時需要*p解引用,b則直接使用就可以。由此我們 推斷出:引用在直接使用時是指針解引用。p直接使用則是它自己的地址。

這樣我們也了解了,我們給引用開辟的這塊内存是根本訪問不到的。如果直接用就直接解引用了。即使打印&b,輸出的也是a的地址。

c語言前後區别(C語言和C的區别和聯系)15

在此附上将指針轉為引用的小技巧:int *p = &a,我們将 引用符号移到左邊 将 *替換即可:int &p = a。

接下來看看如何創建數組的引用:

intarray[10] = {0}; //定義一個數組

我們知道,array拿出來使用的話就是數組array的首元素地址。即是int *類型。

那麼&array是什麼意思呢?int **類型,用來指向array[0]地址的一個地址嗎?不要想當然了,&array是整個數組類型。

那麼要定義一個數組引用,按照上面的小訣竅,先來寫寫數組指針吧:

int(*q) [10] = &array;

将右側的&對左邊的*進行覆蓋:

int(&q)[10] = array;

測試sizeof(q) = 10。我們成功創建了數組引用。

經過上面的詳解,我們知道了引用其實就是取地址。那麼我們都知道一個立即數是沒有地址的,即

int&b = 10;

這樣的代碼是無法通過編譯的。那如果你就是非要引用一個立即數,其實也不是沒有辦法:

constint &b = 10;

即将這個立即數用const修飾一下,就可以了。為什麼呢?

這時因為被const修飾的都會産生一個臨時量來保存這個數據,自然就有地址可取了。

c語言前後區别(C語言和C的區别和聯系)16

9、malloc,free && new,delete

這個問題很有意思,也是重點需要關注的問題。malloc()和free()是C語言中動态申請内存和釋放内存的标準庫中的函數。而new和delete是C 運算符、關鍵字。new和delete底層其實還是調用了malloc和free。它們之間的區别有以下幾個方面:

1)、malloc和free是函數,new和delete是運算符。

2)、malloc在分配内存前需要大小,new不需要。

例如:int *p1 = (int *)malloc(sizeof(int));

int *p2 = new int; //int *p3 = new int(10);

malloc時需要指定大小,還需要類型轉換。new時不需要指定大小因為它可以從給出的類型判斷,并且還可以同時賦初始值。

c語言前後區别(C語言和C的區别和聯系)17

3)、malloc不安全,需要手動類型轉換,new不需要類型轉換。

4)、free隻釋放空間,delete先調用析構函數再釋放空間(如果需要)。

與第⑤條對應,如果使用了複雜類型,先析構再call operator delete回收内存。

5)、new是先調用構造函數再申請空間(如果需要)。

與第④條對應,我們在調用new的時候(例如int *p2 = new int;這句代碼 ),底層代碼的實現是:首先push 4字節(int類型的大小),随後call operator new函數分配了内存。由于我們這句代碼并未涉及到複雜類型(如類類型),所以也就沒有構造函數的調用。如下是operator new的源代碼,也是new實現的重要函數:

c語言前後區别(C語言和C的區别和聯系)18

我們可以看到,首先malloc(size)申請參數字節大小的内存,如果失敗(malloc失敗返回0)則進入判斷:如果_callnewh(size)也失敗的話,抛出bad_alloc異常。_callnewh()這個函數是在查看new handler是否可用,如果可用會釋放一部分内存再返回到malloc處繼續申請,如果new handler不可用就會抛出異常。

c語言前後區别(C語言和C的區别和聯系)19

6)、内存不足(開辟失敗)時處理方式不同。

malloc失敗返回0,new失敗抛出bad_alloc異常。

7)、new和malloc開辟内存的位置不同。

malloc開辟在堆區,new開辟在自由存儲區域。

8)、new可以調用malloc(),但malloc不能調用new。

new就是用malloc()實現的,new是C 獨有malloc當然無法調用。

10、作用域

C語言中作用域隻有兩個:局部,全局。C 中則是有:局部作用域,類作用域,名字空間作用域三種。

所謂名字空間就是namespace,我們定義一個名字空間就是定義一個新作用域。訪問時需要以如下方式訪問(以std為例)

std::cin<<"123" <<std::endl;

例如我們有一個名字空間叫Myname,其中有一個變量叫做data。如果我們希望在其他地方使用data的話,需要在文件頭聲明:using Myname::data;這樣一來data就使用的是Myname中的值了。可是這樣每個符号我們都得聲明豈不是累死?

c語言前後區别(C語言和C的區别和聯系)20

我們隻要using namespace Myname;就可以将其中所有符号導入了。

這也就是我們經常看到的using namespace std;的意思啦。

不學C語言能直接學C 嗎?

還是像前面所說,C 編程語言的第一大重要組成部分就是「面向過程編程」,而這正是C語言老大哥的領域。即使沒有學過C語言,一上來就直接學習C 的小夥伴,應該也難逃『面向過程』這一部分的内容。

從理論上來說,學C 前并不一定非得學C語言,但是有C語言底子再去學C 往往更具優勢,最起碼「面向過程編程」這一部分内容能夠輕車熟路。

c語言前後區别(C語言和C的區别和聯系)21

内容有點長,建議小夥伴們收藏觀看~

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2025 - www.tftnews.com All Rights Reserved