1. 為什麼很多人覺得c語言只要學會了指針基本上差不多掌握這門語言
從事嵌入式開發十幾年,只要使用的編程語言有三種,C/C++ Java三種,其中C語言使用的時間最長,這門編程語言的最大特別是語法細節簡介,但是靈活性非常強,從大的方面看要真正掌握一種編程語言,需要真正的項目實戰,只是停留在理論層面上很難認清編程語言背後的本質,記得剛學習C語言階段,基本上一個多月就把基礎語法學習完了,並且做了大量的實習題目,覺得這門編程語言就這么回事了。
於是從學校的圖書館裡面借了一本將近1000頁的linux內核講解書籍,開始先從戰略上藐視對手,在戰術上重視在開始幾十頁進展的還是比較順利,始終覺得掌握好了基礎的語法,後面的就是變通和靈活運用的問題了,還能變出什麼幺蛾子結果,看到後面簡直就是在閱讀天書了,才知道了自己認識的淺薄,只是掌握點語法皮毛就想著挑大樑這種想法在編程行業顯得非常的幼稚,編程行業除了理論之外實戰經驗顯得非常重要。
回到題目中的C語言的核心知識點指針,C語言關鍵語法點指針,數組,結構體,回調,遞歸,函數等等,剩下就是這些個概念在項目實戰中的應用了,指針對於初學者來講就是一種雙刃劍,如果真的掌握理解了,能在編程中提升非常大的效率,如果沒有掌握對於很多初學者來講就是一種折磨,很多人覺得學不好C語言版本的數據結構,其實很重要的一個障礙就是指針,如果對於指針了解清楚,再去切入數據結構的學習就會顯得輕松許多,指針作為C語言裡面最重要的語法一點不為過,但是認為掌握了指針C語言就會顯得非常膚淺。
任何一種編程語言的背後都是大量的編程模式以及編程的套路,這些只有在真正的項目實戰中才能掌握,而且對於一種編程語言越是做的時間長越是覺得自己的膚淺,更加不敢稱之為精通,倒是現在很多初生牛犢在簡歷上寫上精通幾種編程語言,越是乾的時間長越是忌諱提到精通兩個字眼,所以講只是掌握了指針就說掌握一門編程語言的一半顯得認識不足,真正掌握編程語言還是靠項目實戰,不是所謂幾個重點語法這么簡單的事情。
學習一種編程語言需要掌握幾個重點要素,首先掌握理論基礎,世要真正的明白,雖然編程語言是一種實踐性的語言,但實踐的前提是掌握理論基礎,很多人不懂C語言的指針就是因為沒有徹底明白指針的含義,只想著快點追趕進度,結果欲速則不達,越是重要的概念越是要徹底掌握明白;第二點就是實戰,在掌握理論基礎上就是通過項目實戰獲取經驗,紙上談兵永遠也不做不了真正的項目,想盡一切辦法去做項目實戰,沒有別的途徑,直面問題的本質,希望能幫到你。
很高興能回答你的問題
C語言作為編程老祖,很多軟體工具腳本都是用C語言或C++來編寫的。那麼C語言到底學成什麼樣才算學的比較好?
我上大學一年級的時候,就開始接觸C語言了,C語言自認為學的還可以。像數據、變數、循環、判斷等都是手到擒來。但學到第8章,也就是學到了指針那一塊,就感覺有一點懵了,老師也說指針是比較費腦力的,死記硬背是不可取的,需要理解它的含義。
在學習指針之前,基本都沒了解面向對象是什麼意思。但學到了指針就懂得面向對象與面向過程的差異。(簡單來說,前者就是以對象為基礎,設定其屬性啊,行為等。後者就是以完成它的過程為主,比如說:計算兩個數相加。前者可以設計為小貓計算兩個數,也可以是小貓2......,而後者就是計算,而且可以具體到是哪兩個數相加。)面向對象對於現在的編程語言還是很重要的。
個人覺得,指針與面向對象密切相關,導致在C語言中指針就變得尤其重要,像我後面學習的Python、java就沒有指針一說,但出現了很多類。相對C語言來說,多出了很多很多類。可能是指針被封裝起來了吧。
更多精彩,敬請期待!
指針遠遠不是C語言的全部,
只是在C語言學習道路上相對而言比較難理解的一塊。
畢竟從一個高級語言的角度去理解地址,比較抽象。
作為一個高級語言,數據類型,流程式控制制,函數這些才是高級語言的重點。
說差不多掌握這門語言,應該就是指的指針的難度,和學習的耗時。
也對,也不對,學會指針只是入門了。位運算與文件學會才能寫應用。
只要學過嵌入式開發對指針必定是秒懂,無非就是內存定址。脫離了硬體去學C只能學點皮毛。充其量也只能說會點語法而已。線程進程信號量系統調用各種通訊協議這些才是精華所在。
c語言是結構性(相對面向對象編程語言)高級編程語言。單純語言本身來講,語法結構大致類同。c語言的一大特點是對內存操作的靈活性,如果理解了對內存操作和管理的知識點,基本就掌握了這門語言。而指針便是c語言對內存操作的金鑰匙。要想掌握c語言,也必須要精通指針相關知識點。
如果不算數據結構、操作系統和演算法這些東西。純粹從語言角度來看,掌握指針技巧,確實可以認為基本掌握語言了。要想更加精進的話,可以考慮學習各個硬體平台了。
比如SIMD在各個CPU平台的實現等。做一些針對性的硬體優化是可以考慮的。多媒體庫就做了大量的硬體針對性優化。這個內容也算是核心技術的一部分了。核心技術的另一部分可以認為是演算法和操作系統知識的應用。
首先說明的是指針是C語言的一個難點,但是不是全部。就好比不會指針,很多編程技巧無法掌握,同樣掌握指針也不見得你能做什麼。很多編程技巧需要在實際項目中去體會和學習。等覺得自己像編譯器一樣思考,自己寫的每句代碼,都很清楚編譯器背後是怎麼處理的時候再說自己熟練掌握C語言了。
最後總結來說,掌握指針只是C語言"真正"入門的一個表現。
語言本身掌握不算難,重點是演算法,數據結構,編程思想...
我一般自己設計編譯器 c指針按我自己的想法來寫 怎麼的
2. c語言指針面試常見問題
c語言指針面試常見問題
指針的使用,一直是c語言面試題中必考的部分,因為指針本身使用的復雜性與普適性,所以考點非常多,而且也可以與其他知識相互結合,因此我們將會使用五篇專題的篇幅來介紹指針。
分析下面的程序,指出程序中的錯誤:
本題解析
沒有正確為str分配內存空間,將會發生異常。問題出在將一個字元串復制進一個字元變數指針所指地址。雖然編譯的時候沒有報錯,但是在運行過程中,因為越界訪問了未被分配的內存,而導致段錯誤。
相關知識點
在處理與指針相關的問題時,首先需要搞明白的就是內存,因為指針操作的就是內存。
第一個,就是內存的分區。這也是經常會被考察的一個考點。
寫出內存分為幾大區域
對於這個問題,有幾種不同的說法,有的說內存分為五大分區,有的說分為四大分區,我們先來看五大分區的說法:
認為內存分為五大分區的人,通常會這樣劃分:
1、BSS段( bss segment )
通常是指用來存放程序中未初始化的'全局變數和靜態變數 (這里注意一個問題:一般的書上都會說全局變數和靜態變數是會自動初始化的,那麼哪來的未初始化的變數呢?變數的初始化可以分為顯示初始化和隱式初始化,全局變數和靜態變數如果程序員自己不初始化的話的確也會被初始化,那就是不管什麼類型都初始化為0,這種沒有顯示初始化的就 是我們這里所說的未初始化。既然都是0那麼就沒必要把每個0都存儲起來,從而節省磁碟空間,這是BSS的主要作用)的一塊內存區域。BSS是英文Block Started by Symbol的簡稱。BSS段屬於靜態內存分配。 BSS節不包含任何數據,只是簡單的維護開始和結束的地址,即總大小。以便內存區能在運行時分配並被有效地清零。BSS節在應用程序的二進制映象文件中並不存在,即不佔用 磁碟空間 而只在運行的時候佔用內存空間 ,所以如果全局變數和靜態變數未初始化那麼其可執行文件要小很多。
2、數據段(data segment)
通常是指用來存放程序中已經初始化的全局變數和靜態變數的一塊內存區域。數據段屬於靜態內存分配,可以分為只讀數據段和讀寫數據段。字元串常量等,但一般都是放在只讀數據段中。
3、代碼段(code segment/text segment)
通常是指用來存放程序執行代碼的一塊內存區域。這部分區域的大小在程序運行前就已經確定,並且內存區域通常屬於只讀, 某些架構也允許代碼段為可寫,即允許修改程序。在代碼段中,也有可能包含一些只讀的常數變數,例如字元串常量等,但一般都是放在只讀數據段中 。
4、堆(heap)
堆是用於存放進程運行中被動態分配的內存段,它的大小並不固定,可動態擴張或 縮減。當進程調用malloc等函數分配內存時,新分配的內存就被動態添加到堆上(堆被擴張); 當利用free等函數釋放內存時,被釋放的內存從堆中被剔除(堆被縮減)
5、棧 (stack)
棧又稱堆棧, 是用戶存放程序臨時創建的局部變數,也就是說我們函數括弧「{}」 中定義的變數(但不包括static聲明的變數,static意味著在數據段中存放變 量)。除此以外, 在函數被調用時,其參數也會被壓入發起調用的進程棧中,並且待到調用結束後,函數的返回值 也會被存放回棧中。由於棧的先進先出特點,所以 棧特別方便用來保存/恢復調用現場。從這個意義上講,我們可以把堆棧看成一個寄存、交換臨時數據的內存區。
而四大分區的說法,則這么認為:
1、堆區:
由程序員手動申請,手動釋放,若不手動釋放,程序結束後由系統回收,生命周期是整個程序運行期間。使用malloc或者new進行堆的申請,堆的總大小為機器的虛擬內存的大小。
說明:new操作符本質上是使用了malloc進行內存的申請,new和malloc的區別如下:
(1)malloc是C語言中的函數,而new是C++中的操作符。
(2)malloc申請之後返回的類型是void*,而new返回的指針帶有類型。
(3)malloc只負責內存的分配而不會調用類的構造函數,而new不僅會分配內存,而且會自動調用類的構造函數。
2、棧區:
由系統進行內存的管理。主要存放函數的參數以及局部變數。在函數完成執行,系統自行釋放棧區內存,不需要用戶管理。整個程序的棧區的大小可以在編譯器中由用戶自行設定,VS中默認的棧區大小為1M,可通過VS手動更改棧的大小。64bits的Linux默認棧大小為10MB,可通過ulimit -s臨時修改。
3、靜態存儲區:
靜態存儲區內的變數在程序編譯階段已經分配好內存空間並初始化。這塊內存在程序的整個運行期間都存在,它主要存放靜態變數、全局變數和常量。
注意:
(1)這里不區分初始化和未初始化的數據區,是因為靜態存儲區內的變數若不顯示初始化,則編譯器會自動以默認的方式進行初始化,即靜態存儲區內不存在未初始化的變數。
(2)靜態存儲區內的常量分為常變數和字元串常量,一經初始化,不可修改。靜態存儲內的常變數是全局變數,與局部常變數不同,區別在於局部常變數存放於棧,實際可間接通過指針或者引用進行修改,而全局常變數存放於靜態常量區則不可以間接修改。
(3)字元串常量存儲在靜態存儲區的常量區,字元串常量的名稱即為它本身,屬於常變數。
(4)數據區的具體劃分,有利於我們對於變數類型的理解。不同類型的變數存放的區域不同。後面將以實例代碼說明這四種數據區中具體對應的變數。
4、代碼區:
存放程序體的二進制代碼。比如我們寫的函數,都是在代碼區的。
通過上面的不同說法,我們也可以看出,這兩種說法本身沒有優劣之分,具體的內存劃分也跟編譯器有很大的關系,因此這兩種說法都是可以接受的,搞明白內存的分區之後,指針的使用才能夠更加的靈活。
;3. C語言包括哪些知識點
數據類型,運算符與表達式;程序結構:順序,選擇,循環; 數組,函數,預處理命令,指針,結構體與共用體,文件,位運算;
當然,C程序的靈魂是演算法。
4. 有關C語言指針的問題,超難,高手進!!!
整個函數的作用是-->在以listelement * listpointer為單向鏈表頭的單向鏈表中的最尾段動態申請一個listelement結構的空間來存放要求加進單向鏈表的int data數據.並返回該鏈表的頭指針....
以下是對程序代碼的詳細解釋...
listelement * AddItem (listelement * listpointer, int data) {
//listpointer指向需要執行加入數據的單向鏈表的指針.這個指針可以指向任一條數據結構為listelement的單向鏈表
//data指的是要加入單向鏈表的具體數據
listelement * lp = listpointer; //使lp指向即將進行鏈表編歷的頭指針,這句為關鍵語句!
if (listpointer != NULL) { //如果鏈單不止一個有效項...則...
while (listpointer -> link != NULL)
listpointer = (listelement *) listpointer -> link; //這兩名加起來為一個循環體! 其作用是編歷整個鏈表的項.並保證listpointer指向鏈表中的最後一項!邏輯規定鏈表中的最後一項的listpointer -> link為NULL 其中listpointer = (listelement *) listpointer -> link中的(listelement *)為強制數據類型轉換!目的是100%確保link為指向listelement結構的指針...這句話其實在正常的邏輯下是多餘的.除非link除了指向本鏈表的下一個數據項外,還有別的作用! 但這樣的可能性很少....
listpointer -> link = (struct listelement *) malloc (sizeof (listelement)); //動態申請一個listelement結構空間,並把申請到的首地址作為listpointer -> link! 由於前面的循環體的作用,使得listpointer -> link確保為鏈單中的最後一項...
listpointer = listpointer -> link; //使listpointer指向最後一項的實體,以便加入指定data數據項....看,這句listpointer = (listelement *) listpointer -> link是多麼的相似!?(其執行結果肯定是一樣的) 從這里可以看出,在前面循環體內的(listelement *)肯定是多餘的!!!
listpointer -> link = NULL; //使listpointer在邏輯上成為本鏈表的最尾部!
listpointer -> dataitem = data; //加入數據
return lp; //返回本鏈表的頭指針! 這和函數的第一句是對應的,是關鍵語句,絕不能少的!
}
else { //如果鏈表為空,也就是一個數據項都沒有的話,則動態申請一個,並把data數據加到裡面保存,然後使剛動態生成的listpointer為鏈表頭指針! (以下的語句作用是就如此,我不多說了)
listpointer = (struct listelement *) malloc (sizeof (listelement));
listpointer -> link = NULL;
listpointer -> dataitem = data;
return listpointer;
}
}
PS:在高級語言里,指針的強制類型轉換是經常用到的技巧!但由於各編譯器的不同,會造成很多意想不到的邏輯錯誤!!!(很多時候,你以為確實是按自己的意思轉換成指定的類型了,但實際上卻完全不是這么一回事! 並這個錯誤有時是很難很難檢測到底是為什麼的!!!) 指針,用好了天下無敵,用不好就是一滴老鼠屎搞臭一鍋湯!!! 這樣情況的應用,用匯編是最不容易出錯的!
PS:舉個在G++編譯器里一個容易誤解的指針例子...兩個不同的指針定義-->char *lp=new char[255]; 和 char lp[255];
里具體語句的lp[1]的含義到底有什麼樣的區別!? 這個例子,相信很多人都會覺得是一樣沒區別的(這是在C++標准里說明的)...但實際上,如果是在G++編譯器里的話.定義為char lp[255];中的lp[1]的意義就是以lp為頭指針的下一個單元!在這里,是我們常規並正確的理解! 但是,如果寶義成char *lp=new char[255];的話,則在G++編譯器里lp[1]無解(結果是隨機亂指一通)!!!雖然編譯時不會出錯,但結果肯定是錯誤的! 解決的方法超級郁悶.只能通過lp++來一步步定址!(而不能通過lp[n]的方式直接定址,當然如果還有效率高的方法,但這在邏輯上很容易讓人混亂,那就是先把lp[0]轉成DWORD類型再加上n之後再強制轉成相應的指針類型!)
5. c語言指針程序題,程序如下,答案是3,6。我想知道為什麼答案是3,6而不是6,3希望您能幫我詳細解答一下。
呵呵,你被主函數中的a,b和子函數中的a,b所混淆了!
(1)主函數中的a,b是變數名,a=3,b=6,內容為3和6 。
(2)子函數中的a,b是指針變數,是指向整型變數的指針變數【(int * a,int * b)】。k也是指針變數,調用子函數fun時【fun(x,y)】,是將a,b的地址傳過來了,不是a,b的值!在子函數內部,
k=a;a=b;b=k;交換的是就是的地址(注意:這里的a,b實際上是x,y,也就是主函數中的&a,&b),也就是將主函數中的變數地址交換了而已,就是將變數換個地方而已,變數名和變數的值都沒有變!
指針變數是C語言中比較難的一個知識點,尤其是指向指針的指針、指向多維數組的指針。希望你多看書,多練習,認真領會。
6. c語言指針,下面這題看不懂,求解😭
while (*y++)
因為++運算符優先順序比*高,所以先對指針y加1,再取出指針y指向的 字元
如果取出的字元不為0( ) 就循環
因為字元串數組 a[]={hello} 是依字元'