哪一種計算機語言最適合入門?是C語言嗎?可是我覺得指針難死了!?

大學學的計算機入門語言是C語言,可是C語言感覺指針太難了,稀里糊塗不明白,真的適合入門嗎?我表示懷疑。

20151125晚補充

有太多的指針概念,

比如

指針數組,數組指針,

常量指針,指針常量,

一級指針,二級指針,

函數指針,

*p

*p

p++

(*p)++ 等等,

概念太多了,崩潰死了,不覺得難嗎?


連指針都覺得難,上帝想讓你學C#。

而且C#是在所有領域(包括寫操作系統)都有所成就的語言裡面,唯一對初學者友好的語言。學了絕對不會浪費。


看這個:

C 語言指針怎麼理解? - 知乎用戶的回答


個人是Pascal入門的,大學學的c,後來興趣了解了下JavaScript和Python

入門最簡單的無疑是Pascal,無論是語句,還是指針之類的設定,Pascal都很清晰,但是Pascal問題是現在你能找到的代碼越來越少了,而學習編程需要你不停地看代碼、做題目,提高需要的資料很難找到,而且Pascal在工程方面的應用也越來越少了

嘲諷題主大可不必。題主你最大的問題,是沒有形成程序化的思維。很多人不能在學習初期形成這種思維。就我高中的經驗看,一起學習編程,在學習各門科目表現都差不多的人中,形成程序化的思維的人3分鐘就能寫出來的東西在沒形成的人那裡可能要10分鐘。而且這種事情和智商毫無關係。

什麼是程序化的思維呢?我們拿排序舉個例子吧。排序就那麼幾個模塊,你要先考慮好需要這些步驟,然後寫寫語句,兩三分鐘就可以寫完。

你在寫程序的時候,你要記住的是你要做哪些事情(演算法),至於語句怎麼寫多練習幾遍就順手了。語句是事先你的演算法的一個工具而已。學習語言最大的問題是,很多人是記演算法需要哪些語句,然後就又記語句又記演算法昏了頭。其實很多人很難一下子兩個都記住。你可以把你看的指針相關的內容用Xmind這類軟體這樣寫下來,然後把不必要的步驟縮小,只關注必要的步驟,然後一步步去實現這些步驟。這樣或許會好很多。


C語言接觸底層所以必然是CS首選。如果不是CS的當我沒說。

你覺得C的指針麻煩?說實在的那真是最簡單的了……瞅瞅隔壁C++,人家uniq_ptr,share_ptr,指向函數指向變數指向類……剩下的部分才是C指針;Java?C#?那叫是個玩意就是個『指針』

嗯Python倒是簡單,看起來好像沒有指針。其實呢?人家是只有『指針』,全是引用綁定,還不區分類型,腦子不清楚分分鐘拖你下水。

嘛彙編倒是沒指針,也夠底層,只有地址和數據嘛……可是這個『數據』可以是個地址喲~指向的地址的數據還可以是地址喲~可以一會兒地址一會兒數據喲~~~

至於C這種一本書兩百來頁就能寫清楚的語言……能比它簡單的也就剩下個brainfuck了


看了題主的問答記錄,說實話,感覺這問題不太像是你問的...不過就題論題吧。

你問,哪一種計算機語言最適合入門。然而對於「適合入門」,我們根本沒有一個清晰的定義。什麼叫適合入門?是上手容易嗎?是能做出「像樣」的東西,能帶來成就感嗎?是會對以後的學習產生正面影響的嗎?還是說是能夠提高自己思維能力的?如果你對「適合入門」的認識不同,那對應的語言肯定也不一樣。

在思考應該從什麼計算機語言入門之前,是不是更應該想一想這個問題——我們為什麼要學習計算機語言?好難啊,不學行不行?所以有一些人就覺得語言就是工具,思想才是最重要的,編程的事是體力活。(我真的沒有黑學校里的某些教授!)而另一些人則走到了另一個極端,他們認為計算機科學的一切都是語言,於是他們拚命地掌握了若干門語言,當然也包括墜吼的PHP,覺得自己就算得上牛人了。然而計算機語言的目的是什麼?是解決問題。那我可以說解決問題人也可以嘛而且人還更智能,會求積分會算逆矩陣,有什麼不好?你會說,因為計算機快呀。那我說,我可以給一個人說,你幫我做做這題,他會做就做了,但是我給計算機說就不行。為啥?因為它無法理解它要做什麼。寫程序的工作就在於此。所謂計算機語言,就是描述計算機要做什麼的一種形式。

那為什麼還有這麼多種語言之分呢?簡言之,它們出現的時間不同、背景不同、目的不同。不同的語言擁有不同的抽象層次。寫程序的過程,就像是語法分析里的遞歸下降,你解決這個問題的思想在高層次,在雲端,你要把它「落實」成計算機可以識別的概念,你需要從雲端「下落」,在不同的高度有不同的語言,比如2000m是Python,1300m是Java,500m是C等等。之所以Python給人的印象比C來的容易,是因為它的高度比C高,你從你的「思想」下落到語言實際需要的距離更短。如果你再下落1500m從Python的位置到C的位置,你需要更多更細緻的工作。當然,這樣說來位置低的語言貌似是一無是處,其實不是,底層語言給人的感覺就有點像是手工打造,而高級的語言代表著機械化的生產。隨著工業水平的演進,肯定是越來越多的東西可以,也需要,用機器去自動化生產的。只有這樣,整個行業的生產力才能提高嘛。不過,儘管越來越少,手工打造的精細產品還是需要的啊。

雖然如此,我還是覺得對於一個真正想從事計算機行業而不是僅僅做一個計算機愛好者的人,C語言應當是第一課,不論你以後是不是還喜歡它。原因嘛,上面的大牛們說得很多了。

你說你覺得指針難死了,那我默認,按照一般C語言教材的編排順序,指針以前的東西你都了解得差不多了。首先,如果我們搞不清楚一個工具,那麼有三種可能:

  • 你不清楚指針有什麼用
  • 你不清楚指針該怎麼用
  • 你不清楚指針為什麼能這樣用

想一想,你是哪一種呢?

首先,我們來看一看指針有什麼用?

講道理的話,如果你到目前沒有發現指針有什麼用,那就不用,挺好的。你看C++程序員做個軟體也基本不會把C++的語言特性都用上是吧。你有數組,有結構體,有函數,什麼事情做不成呢?是吧。直到有一天,你遇見了這樣一個問題:

試編寫一個函數swap(x, y)使得其能夠交換x和y兩個變數的值

這個……很簡單嘛。我開始寫:

void swap(int x, int y)
{
int tmp = x;
x = y;
y = tmp;
}

然後你調用一下,發現……咦,怎麼沒用。啊好難過好難過,怎麼回事?

你上網求助,發現大神們告訴你要用指針寫,像這樣:

void swap(int * x, int * y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}

然後調用的時候swap(a, b);就行了。哇啊啊啊好神奇!

於是,指針的第一個用處出來了:它能使得函數有能力交換兩個變數的值。

怎麼做到的呢?我們來看看。

我相信你已經知道了,每一個變數都有屬於自己的一塊空間,那這塊空間在哪裡呢?答案是內存,哦不,準確一點說是虛擬內存 (Virtual Memory) 里。那計算機怎麼知道我要找的是變數b的空間而不是a的空間呢?是因為每一個變數所屬的空間都有一個惟一的地址,計算機只要通過這個「地址」,就可以找到裡面的值了。這種根據一個地址就能直接訪問到一塊內存空間的方式,我們叫做隨機讀取。具體它是如何做到的,可以去看看Charles Petzold的《編碼》一書,裡面甚至從最基本的電路一步一步講起,構造一台最基本的計算設備。還有一個問題是,如果我的變數佔有多個空間(位元組),但是一個地址只能對應一個空間,那我們又有兩個問題:

  • 如果我們要用一個地址代表整個變數所佔的內存空間(假設4個位元組),我這四個空間是從前向後排還是從後向前排?比方說我變數的值是AE 01 08 82,那我在內存里從前向後的排序到底是82 08 01 AE還是AE 01 08 82?
  • 我怎麼知道我叫這個名字的變數占幾個空間?

第一個問題顯然又是信仰之爭。所謂從前向後的,我們叫做大端序 (big-endian);另一種,我們叫做小端序 (little-endian),大端序與小端序的轉換在網路傳輸的時候會用到,Intel的CPU大多採用的都是小端序。而第二個問題,由於C里每個變數都有自己的類型,所以編譯器會根據不同類型的各自尺寸生成相應的代碼。

說這麼多幹什麼呢?只是為了讓你更好地明白,你在程序里定義的變數乃至函數代碼,全都是存儲在隨機存儲器(內存)里的。每個變數都有自己的起始地址,即屬於自己的一塊位置。

那指針是什麼呢?指針當然也是變數咯,指針也跟其他類型的變數一樣,有自己的一塊空間,空間里的二進位位構成了一個值。這個值可以是任意的,你甚至可以把它當作整數來用。(沒記錯的話,指針的本質類型應該是unsigned long)而指針跟其它變數類型的根本性不同在於,它有一個取值的運算符,即*符號。因為它可以取值,所以指針類型的變數就不僅可以有自己的值,也可以「操縱」其它變數的值了。無論是多麼複雜的指針,本質上它們的存在都跟這個*操作有關。

回到我們開始說的那個swap函數。為什麼第一種寫法無法達成交換兩個變數值的效果?原因跟指針無關,跟函數參數的傳遞方式相關。原因可以用一句話來解釋:你的swap函數里出現的x和y,跟你傳參數進去時候的a和b,根本沒有指向同樣的內存地址。當函數調用的時候,a和b被複制了一份給了x和y變數。你在swap函數里對x和y進行的所有操作,都是對這兩塊新的內存地址里的值進行操作,影響不到a和b的內容。你不是沒有交換東西,只是被交換了的x和y在swap函數調用結束之後空間就被回收了而已。這種「把傳進去的參數複製一份」的方式叫做值傳遞。而在其他一些語言比如C++或者Visual Basic裡面,還存在一種傳參數的方式叫引用傳遞,即函數裡面的參數和傳進去的參數,指向同樣的內存地址。在C裡面,我們不存在引用傳遞,因此要模擬引用傳遞的效果,只能用指針來實現。

第二個函數調用的方法有點不太一樣,是swap(a, b),比起上一個版本多了符號。這個符號的意思是「取地址」,函數的形式參數是兩個指針,在調用的時候本質上也是值傳遞,只不過這次複製的不是a和b的值,而是a和b的地址。在函數內部,我的x和y兩個指針也是兩塊獨立的空間,有各自的內存地址。只是它們的值對應了a和b兩個變數的地址,所以我用*操作,就可以完成「操控」的效果了。

有人說指針是C語言的精髓,不是因為這個語法本身有多麼強大,而是因為它彌補了C語言語法里的一些缺憾,或者說使一些操作變得更容易完成了。像知乎上的大牛說過,指針對C不是奢侈品而是必需品。如果你習慣了其它語言的思維方式,面對指針就像一個撒哈拉長大的人看到傘這種東西一樣,必然覺得它很奇怪。而C語言的領域就像是上海,時常下雨,你沒傘是不行的。

當然咯,函數傳參數的時候,複製是有開銷的。所以如果函數調用的時候要傳進去的那個參數特別特別大,你也可以用以指針作為參數的方式,這樣無論如何,只會複製一個指針的長度。如果你不希望這個參數在函數里被修改的話,可以採用指向常量的指針,比如:

void foo(const int * ptr)
{
*ptr = 4;
}

如果你試圖修改一個指向常量的指針指向地址的值(好拗口),編譯器是會報錯的。

指針的作用之二,體現在C語言的字元串。

如果接觸過其它語言的人,看見C的字元串心情大概會是像日了狗一樣。因為C語言根本就沒有一個像樣的字元串類型。所謂能夠「代替」字元串的東西,也只有字元指針和字元數組了。字元數組想必你清楚,一個元素是一個字元,能夠用雙引號括起來的常量字元串初始化,要輸出的話結尾得有""……那字元指針又是什麼呢?

在我看譚浩強的書的時候,我死活沒弄清楚字元指針到底有什麼用。我後來才明白,這玩意兒在C語言里地位實在特殊。你可以用const char * p = "Zhihu"來初始化一個字元指針,也可以中途「更換」它的值,但是不能像字元數組一樣對其間某個元素進行修改,原因在於它其實指向的是可執行文件常量段的一塊地址。更具體的內容可以看看我寫過的這個。

另外一個有必要說的就是函數指針了。函數指針本質上還是一個指針,只不過它指向的內容不是變數而是一塊代碼的地址。有什麼用呢?最經典的大概就是C標準庫里的qsort函數了:

void qsort (void* base, size_t num, size_t size,
int (*compar)(const void*,const void*));

這個函數的作用是給一個數組排序。注意最後的compar參數,聲明方式很詭異,它是一個函數指針,放在這裡的意思是qsort需要用戶給它傳一個函數進去,這個函數的作用是比較兩個元素以給排序作為參照。前面的void*意思是指向「任何類型」數據的指針。void指針和函數指針在這裡的應用,其實也算是C語言裡面實現泛型的一種嘗試了吧。當然,在C++里,我們有更優雅的方法。

說起指針,我不知道你們用的C語言教材在指針這一章有沒有讓你們寫一個叫做鏈表的東西。可能你不知道這個有什麼用,我要存一系列東西可以用數組嘛,而且還能隨機存取,比你鏈錶快。而且C99標準都允許用變數來定義數組了哦。

其實鏈表這個東西雖然看起來沒什麼大用,但其是動態內存管理的一種體現。數組雖可用變數聲明,一定義長度還是固定的;數組雖然能開大,但是棧空間畢竟是有限的,太大了會爆掉。所以,用指針搭配malloc等一系函數可以在C中實現動態內存的管理,很多數據結構的視線也需要用到指針。但C語言里動態定義的內存都需要自己去管理釋放,所以也有人說C是內存管理的地獄。

唔...說到這裡突然不知道往下還能講什麼了。其實C的各種聲明,看起來很恐怖,實際上,《C專家編程》一書里作者提出了這樣的規則:

理解C語言聲明的優先順序規則

  1. 聲明從它的名字開始讀取,然後按照優先順序順序依次讀取。
  2. 優先順序從高到底依次是:
    1. 聲明中被括弧括起來的那部分
    2. 後綴操作符:( ) 表示這是一個函數而 [ ] 表示這是一個數組
    3. 前綴操作符:星號 * 表示「指向...的指針」
  3. 如果const和(或)volatile關鍵字的後面緊跟類型說明符(如int、long等),那麼它作用於類型說明符。在其他情況下,const和(或)volatile關鍵字作用域它左邊緊鄰的指針星號。

從這個出發,很多C語言的複雜聲明都不是問題了。

我們回到你題目里說到的東西,你之所以覺得難,是因為你在沒有用到的情況下主動灌輸這些概念。學高數的時候,這章的概念不太理解,做做題還能明白。可是程序設計語言里的概念,如果自己沒有一個切實體會,再加上本來這就是與之前接觸的東西截然不同的一個思維方式,覺得無法理解是顯然的。如果不是準備什麼面試,你沒有必要強迫自己去分析複雜聲明。只有當你用到它的時候去查,知識才能變成自己的東西。C語言的指針本質就是這個星號 * ,參透了這個星號也就可以說參透了C指針。它並不神秘。很多代碼之所以寫得神秘,或是因為它使用了某些你不清楚的演算法,或是因為它利用了一些不為人知的語言/系統特性。

你說覺得不難的去看Linux源代碼,這話恕我不能同意。不是常有人調侃嗎,數學書上的每個字我都認識,但就是看不懂。用在這裡也是這個意思。我們說C語言「難」往往不是因為這門語言本身複雜(如C++),而是它廣泛運用的領域本來就門檻很高。操作系統或者編譯器,涉及到的東西實在太多,超出了C語言語法所涵蓋的範疇。C語言的語法相當簡單清晰。但在這簡單清晰之中,卻能玩出許許多多的花樣,你若有興趣就去感受大牛們如何玩轉C語言的,而不是看完指針之後抱怨「為什麼要這樣設計,難死了!」。

(另外推薦一本書,《深入理解C指針》,可能在會的人眼中看起來講的無非是那點東西,但對新手還是用處良多的)

(順道安利一下我的回答軟體工程學生怎樣學好 C 語言? - 邱超凡的回答)


我覺得最適合入門的語言是Pascal,語法上非常接近自然語言,語言特性也比較全面,設計也很精良,作為入門語言再適合不過了。信息學競賽支持Pascal不是沒有道理的。


講真,這樣的話我只能告訴你,適合新手的編程語言是OCaml。

它裡面的ref讓你很直觀的就能理解了。前提是你能理解前面所有的東西。

type "a ref = { mutable contents: "a };;

let ref x = { contents: x };; (* x *)
let (!) r = r.contents;; (* *r *)
let (:=) r x = r.contents &<- x;; (* *r = x *)

===================================

指針都覺得難。

T
T
const T*
T* const
const T
const T
std::shared_ptr&
std::weak_ptr&
std::unique_ptr&
std::experimental::observer_ptr&
boost::instructive_ptr&

以及

T^
cli::pin_ptr&
cli::interior_ptr&

是不是感到很絕望?

如果你覺得Linux代碼很難讀懂,來我們一起看Boost代碼吧。

=================統一解答評論分割線====================

1. 這些東西都比「指針」簡單。

好的,請解釋以下基本概念:

  • 垃圾回收
  • 右值/右值引用
  • 所有權
  • 移動
  • borrow(鑒於還沒有統一的中文翻譯,只好這樣寫)
  • 引用計數
  • 循環引用

以及

  • 代理對象(Proxy)

2. 題主問的是簡單的適合入門的編程語言。我回答的不合題意。

但是請你們看題目具體的描述,謝謝。

3. Linux並不比Boost簡單

廢話,一個發展了二十多年的操作系統內核,肯定有很多積累,要說它簡單絕對不可能。

但是,Linux本身複雜的原因並不在於C語言,而是由操作系統這樣一個系統軟體自身決定的。更何況Linux這種沒事兒誰都可以插一腳的項目。所以,Linux的難度在於資源管理、調度和各種優化的實現,而不是「指針」怎麼用。同樣地你也可以看看xnu和WRK。

然而你再看Boost在做什麼事?

擴展C++。

4. 這說明C++太複雜了

並不是這個意思。只是反諷一下題主,自己(和選擇的教材/導師)水,反而怪C語言,就像拉不出屎怪地球引力小一樣。

另外,C++也是一門新手友好的語言。當然主要看你學的是哪一方面。

C++: From Novice to Professional

5. 懂這就很牛逼嗎?

當然不是。但是連1中我提到的超過一半的概念都不懂的話,還是不要隨便評論了吧。

6. C++不適合時代了,大家寧可用C也不用這個

GCC"s move to C++ [LWN.net]

7. 然後呢?

並沒有然後。不想看就摺疊我吧。

8. T^是什麼?

C++/CLI


指針就是地址

int* p = a //取地址放進指針裡面

int b = *p //用指針的地址求值

搞懂這兩句話就行,其他都是浮雲


c真不算很難,c++才算比較麻煩。c的基本語法相當的簡單,多看看書,每個語法都要多寫點代碼試試看看,很快就明白了。有問題,除了看書,跟同學討論,還可以多 google , baidu 。

比如指針的問題,度娘如是說:徹底搞定C語言指針詳解,一定要多看人家寫的代碼,自己也試一下。

而且,在學校時最有空,你可以花上半年甚至一年去學一門不太複雜的語言,而且真的是純粹的學習,沒有任何的工作壓力,只要應付一下考試就好了。如果真的喜歡編程,還是在學校把c/c++學好吧,以後用到的可能性極高,當然,還可以學學java。

工作以後,你可能需要在三個月內用一門新的語言開發一個新的項目,而且沒人教啊!

在學校學c/c++比不學c/c++,只學java好處在哪呢,舉個例子吧,我遇到好多java程序員,java熟的不要不要的,但是讓他學c/c++,各種不爽,打死都不學(這樣就可以少干點臟活了^_^,畢竟很多性能瓶頸都要用c++解決)。

反而,學c/c++的,大部分工作後能很快會學會java,c#。因為這兩種語言真是各種爽,不用頭文件了,不用指針了,不用delete了 ......

==================================

所謂「臟活」,是指那些本來不打算用c++,但是碰到性能問題解決不了的時候,不得已而用之的活。很多c#,java程序員不肯幹這種事情(以不會c++為借口),只有抓c++程序員來干。

==================================

是否適合入門要看你的目標是什麼。

對於想當程序員的學生,用c入門挺好的,然後學c++,java。當然,你也可以直接學更複雜一點的c++,java。雖然難,但是難不過數學分析,只要多花時間一定能學會。如果你會c++或者java,水平還不錯,是很容易找到編程的工作的。

對於不想當程序員的同學,python也許更加合適,學好了也許可以找個測試的工作,編程的工作比較難找。

對立志搞科學研究的人,學Matlab更合適。這玩意做科學計算,畫各種二維三維圖簡直逆天的簡單,而且真的很容易學。


學racket嘛!學racket吧!


不想學c的話,學scheme(或racket)吧,或者可以看看最近才到beta版的Kotlin語言(JVM上的語言,填了一些java的坑,有IDE支持)。順便推薦一下programming language, application and interpration這本書。 學C語言的話推薦tcpl和csapp。本渣覺得C語言確實是個大坑。。。

邏輯混亂純粹是因為這是失眠強答的……(手動挖鼻孔表情)


C 其實挺簡單的,前提是你得接受它是個高級彙編的事實。C 的指針就是個內存位置,數組和指針基本一回事,記住這一點就行了。

另外不要用譚浩強。


去看golang或者c++。這兩種語言,不用指針照樣能玩。我的意思是把指針僅僅看作一種類型,而不是去用指針操作。

c語言離了指針,基本就廢了。如果你只是覺得指針不能理解,先看別的,等學完組成原理再回來看。另外把你手裡的教材扔了,看 C語言程序設計現代方法 (豆瓣) 。


不,C不適合入門。但剛學到指針就這樣的話,那真不是語言的事了。


我大學的時候也是C語言的課,課本雖然不是譚浩強的,但是也好不到哪去

慶幸的是,當時大一暑假,比較積極,聽說C語言很難過,想去圖書館裡去借一本書預習預習,就找啊找,感覺貌似沒有什麼C語言的書,感覺都是C++的

本著大而全的原則,我找了一本最新最後的書,是外國人編寫的,翻譯過來的《標準C++編程寶典》

回家後就開始看,卡殼就跳過,暑假就翻了一遍,後來上課和考試概念就比較清晰了。

-------------------------------------------------------------------------------

所以,建議lz為了應付考試,可以找一本外國人編寫的教材來看

無論是對於編程風格的培養,一些基本概念的解釋,尤其是代碼示例都是遠遠好於國內教材的。

如果真心想以編程為生的話,java是不二選擇

如果想以編程為業餘愛好,或者輔助主專業的話,linux+python非常合適。

當然有C語言基礎,基本上所有的編程語言都不難學,C++例外。


C 非常適合入門。因為這門語言基本沒有抽象泄漏。


每個行業都有適合的人群。

軟體行業的篩選規則是:

能否先放下疑惑繼續學習,等有了基礎再重新來過。

Only people who die very young learn all
they really need to know in kindergarten.

——Expert C Programming


當然是 Lisp ,你看現在所有的高級語言都在朝 1958 年的 LISP 發展嘛(逃


額,我能說最簡單的其實是PHP么


看你對適合入門怎麼理解了。可能A更容易上手,但是B能讓你學習到一些以後用得到的概念,而這些概念你學習A是接觸不到的。如果是我的話我肯定會覺得B才是「適合入門」的語言。

從這個角度來說,對計算機相關專業(任何需要學習體系結構,操作系統,編譯器這三門課中的一門的專業)來說目前看起來C語言還是個合適的入門語言,其他專業我不確定,可能java更合適吧。


推薦閱讀:

各位覺得主流編程語言中哪個編程語言最容易學習?
有什麼好的 Haskell 中文書籍?
關於C語言中漢字排序的問題?
LABVIEW 有哪些反人類的編程特性?
c++類成員變數為什麼不能做成員函數的默認實參?

TAG:編程語言 | 編程入門 |