重溫C語言,這三十多個細節你把握住了?

      網友投稿 841 2022-05-29

      文章目錄

      前言

      基本篇

      1、編寫代碼文檔

      難度指數:1顆星 / 細節指數:5顆星 / 重要指數:5顆星

      C語言相對其他語言的優勢

      難度指數:1顆星 / 細節指數:1顆星 / 重要指數:3顆星

      C語言為什么不內置輸入輸出語句?

      難度指數:2顆星 / 細節指數:4顆星 / 重要指數:3顆星

      int main() 與 void main()的區別

      難度指數:1顆星 / 細節指數:3顆星 / 重要指數:2顆星

      可寫可不寫的花括號,憑什么要我寫?

      難度指數:1顆星 / 細節指數:2顆星 / 重要指數:2顆星

      `0==a` 與 `a==0`

      難度指數:1顆星 / 細節指數:4顆星 / 重要指數:2顆星

      T、‘T’、“T”的區別

      難度指數:3顆星 / 細節指數:2顆星 / 重要指數:4顆星

      short、long、unsigned

      難度指數:2顆星 / 細節指數:2顆星 / 重要指數:1顆星

      標準輸入輸出中的占位符

      難度指數:2顆星 / 細節指數:2顆星 / 重要指數:3顆星

      scanf讀取字符串

      常用ascii碼

      難度指數:1顆星 / 細節指數:3顆星 / 重要指數:4顆星

      浮點數的比較大小

      難度指數:1顆星 / 細節指數:2顆星 / 重要指數:2顆星

      提升篇

      刷新輸出

      難度指數:2顆星 / 細節指數:3顆星 / 重要指數:4顆星

      重溫C語言,這三十多個細節你把握住了?

      out of range

      難度指數:4顆星 / 細節指數:5顆星 / 重要指數:5顆星

      scanf 和 scanf_s

      難度指數:3顆星 / 細節指數:1顆星 / 重要指數:2顆星

      char* 與 char[n]

      難度指數:1顆星 / 細節指數:3顆星 / 重要指數:3顆星

      getchar() 與 putchar()

      難度指數:3顆星 / 細節指數:2顆星 / 重要指數:2顆星

      sprintf()做字符串拼接

      難度指數:2顆星 / 細節指數:2顆星 / 重要指數:4顆星

      設計原則:“需要知道”原則

      難度指數:3顆星 / 細節指數:4顆星 / 重要指數:4顆星

      作用域·鏈接

      難度指數:2顆星 / 細節指數:1顆星 / 重要指數:2顆星

      extern

      難度指數:2顆星 / 細節指數:2顆星 / 重要指數:3顆星

      argc 和argv

      難度指數:2顆星 / 細節指數:2顆星 / 重要指數:3顆星

      C/C++預編譯/條件編譯指令

      難度指數:2顆星 / 細節指數:2顆星 / 重要指數:3顆星

      指針篇

      難度指數:5顆星 / 細節指數:5顆星 / 重要指數:5顆星

      前言

      好久不見啦朋友們。

      前天參加了軟件設計師考試,說實話,有點emmm,但是我也發現很多基礎已經忘得差不多了,這就是傳說中的手生了嗎?

      手生到什么地步?前天晚上幫我朋友改代碼,甚至連scanf輸入double類型數據用什么方式我都想不起來了。

      所以,我就整理了一下我自己的學習路線。

      江東子弟多才俊,卷土重來未可知!

      拿著《C Primer Plus》梳理了一遍,發現還真的有不少細節平時沒有注意到,或者是沒有刻意的去注意。

      基本篇

      1、編寫代碼文檔

      (寫代碼不寫文檔,拖出去打屎)

      最開始接觸到代碼文檔不知道是什么時候了,但是讓我想寫代碼文檔絕對是在pycharm上。

      很方便,打三個引號,一個回車,什么都給你準備好了。

      然后我就想在VS上也找到類似的功能。起初沒找到,后來誤打誤撞試出來了:

      ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { ///

      /// /// /// /// ///

      1

      2

      3

      4

      5

      6

      7

      吶,看明白不?畫三個杠,不用回車,兩個

      之間寫你的函數功能描述,之間寫你的參數釋義,也可以寫在后面,return我就不多說啥了吧。

      C語言相對其他語言的優勢

      (連C語言的優勢都不清楚,學來干什么?)

      1、目前我們所學習的各種語言,基本都離不開C語言的影子,所謂萬變不離其宗,就是這個道理。

      2、C語言快,不接受反駁。不要說什么匯編更快,寫個我看看。

      3、可移植性強。就拿嵌入式這一塊來說,哪個語言能輕松移植?

      4、細節把控到位。C語言給了程序員極大的細節操作權限,連內存分配都給了。只是我們自己把握不住而已,C語言的水太深了。

      C語言為什么不內置輸入輸出語句?

      別說輸入輸出了,不包任何頭文件,我不知道還能寫什么C代碼。

      為什么要這樣呢?像Python那樣都內置了不好嗎?

      這也是C語言為什么能做嵌入式,而Python做不了的一個重要原因。

      C語言的一個基本設計原則是避免不必要的成分

      我們不可否認,并不是所有項目都需要輸入輸出的。

      兒童節快樂呀各位

      int main() 與 void main()的區別

      不知道有多少小伙伴接觸過這個 void main(),反正我剛開始學C的時候,那個老師是教我們寫這個的,當時就跟我們說,如果沒有什么返回值,就寫這個就好啦。

      后來,遇到我的授業恩師的時候,他叫我們說,不要寫void main()了,打開編輯器,寫完頭文件依賴之后,先把下面這個框架寫上:

      int main(){ return 0; }

      1

      2

      3

      4

      就算沒有什么返回值,也寫一個return 0;,錯不了的。

      有些編譯器會允許void main()的形式,但是還沒有任何標準考慮接受它,所以編譯器可以不接受這種形式,這就是一個在平臺移植中存在的一個隱患。

      多寫一行return 0;很難嗎?

      可寫可不寫的花括號,憑什么要我寫?

      有的小伙伴可能不知道,在循環語句、分支語句中,如果代碼塊兒只有一行的情況下(或者循環下面只有一個分支語句),則那個花括號是可寫可不寫的。

      比方說:

      while(1) printf('1\n')

      1

      2

      那這個花括號寫不寫呢?

      不寫會有什么好處?

      1、代碼看起來行數會短一丟丟

      2、少寫兩個括號

      不寫有什么壞處?

      當下基本不會有什么壞處,當下咱的頭腦坑定是清醒的,知道為什么不寫。

      但是修改代碼的時候呢?如果要在這種循環下動刀,卻又忽略了這個括號呢?

      我前兩天就遇到了,浪費我五分鐘去調試。

      所以啊,又不是說什么很必要的,為什么不寫?寫兩個括號會累著?

      0==a 與 a==0

      這個又屬于那種舉手之勞,但是暴雷的時候不知死活的問題了。

      一般這個細節老師在講分支循環的時候都會說吧,如果少寫了一個等號,0=a是會報錯的,但是a=0是會崩潰的。

      不過現在還好,有的編輯器就會警告,前提是要使用夠好的編輯器,碧如VS。

      像我以前用TXT編程的時候,這個問題就只能靠自己去挖掘了。

      細節之處見真章。

      T、‘T’、“T”的區別

      這就涉及到字符和字符串的概念了。

      這也是一段時間不敲C代碼會很容易忘掉的一個點。

      首先,T如果經過賦值,它既是一個變量。否則它什么也不是。

      其次,‘T’是一個字符,一個char,不是一個字符串。

      緊接著,“T”是一個字符串,不是一個char。

      什么是字符串,可以理解為char的數組,不過在字符串結尾的時候會帶上一個‘\0’。

      short、long、unsigned

      不要再覺得這三個很神秘了,它們只不過是修飾詞而已了。

      short,

      可能

      占用比int類型更少的空間,用于僅需小數值的場合,可以簡寫為short。同int 類型一樣,是一種有符號類型。

      long,

      可能

      占用比int類型更大的空間,用于使用大數值的場合,可簡寫為long。同int類型一樣,是一種有符號類型。

      long long,

      可能

      占用比long更大的空間,用于更大數值的場合,可簡寫為long long,同int類型一樣,是一種有符號類型。

      unsigned,用于只使用非負的場合。將原本分配給負數的空間大小都分配給了正數。

      標準輸入輸出中的占位符

      %d —— 以帶符號的十進制形式輸出整數 %o —— 以無符號的八進制形式輸出整數 %x —— 以無符號的十六進制形式輸出整數 %u —— 以無符號的十進制形式輸出整數 %c —— 以字符形式輸出單個字符 %s —— 輸出字符串 %f —— 以小數點形式輸出單、雙精度實數 %e —— 以標準指數形式輸出單、雙精度實數 %g —— 選用輸出寬度較小的格式輸出實數

      1

      2

      3

      4

      5

      6

      7

      8

      9

      如果是打印short,用%u,打印long,用%ld,以免在移植過程中造成不必要的麻煩。

      scanf讀取字符串

      和讀取單個字符不同,讀取字符串的時候,是不需要加上&符號的。

      常用ascii碼

      其實上網一搜就有了,但是有的比較重要的還是要記一下的。

      ESC -- 27 0 -- 48 A -- 65 a -- 97

      1

      2

      3

      4

      浮點數的比較大小

      對于浮點數的比較,只能用<和>,舍入誤差可能造成兩個邏輯上應該相等的數不相等。。

      提升篇

      刷新輸出

      printf()什么時候真正把輸出傳送給屏幕?printf()語句將輸出傳送給一個被稱為緩沖區的中介存儲區域,緩沖區中的數據再不斷地被傳送給函數。

      標準C規定在以下情況下講緩存區內容輸送給屏幕:

      1、緩沖區滿

      2、遇到換行符

      3、后面跟了一個scanf語句

      可能在平時看來沒有什么關系,但是我們在寫服務器代碼的時候就會有這種問題出來,有時候會導致消息隊列被卡死,有時候會導致數據無法及時的被排出。

      這里拓展一下緩沖區,為什么需要緩沖區?

      首先,將若干個字符作為一個塊傳輸比逐個發送這些字符耗費的時間少。

      其次,如果輸入有誤,就可以使用回刪來更正錯誤。

      當最終按下回車簡單的時候,就可以發送正確的輸入。

      緩沖分為兩類,完全緩沖I/O和行緩沖I/O,對完全緩沖輸入來說,緩沖區滿時被清空,這種類型的緩沖常出現在文件傳輸中。緩沖區的大小取決于操作系統。

      對于行緩沖來說,遇到一個換行符就將清空緩沖區,鍵盤輸入是標準的行緩沖,因此按下回車鍵將清空緩沖區。

      out of range

      我就不吭聲兒,哪個寫C/C++的朋友沒有遇到過這個問題。

      越界。

      一個潛在的問題是:出于執行速度考慮,C并不檢查您是否使用了正確的數值下標,當程序運行的時候,這些語句把數據放在可能被其他數據使用到的位置上,因而可能破壞程序的結果,甚至使得程序結果崩潰。

      scanf 和 scanf_s

      在使用VS的時候,會發現編譯器不通過scanf,給的理由是不安全、即使已經#include

      這時候,它就會推薦我們去使用scanf_s。

      解決方法一:

      點擊項目->項目屬性,點開屬性頁面

      點擊C/C++ -> 預處理器 -> 預處理器定義 -> 點擊右側的下拉列表 -> 點擊下拉列表里的<編輯>

      在預處理器定義中添加字段 _CRT_SECURE_NO_WARNINGS

      然后點擊確定,就可以使用scanf了

      但是僅限于這一個項目,其他的項目還是不能使用,因此需要對所有要使用scanf的項目進行逐個修改

      方法二:使用scanf_s

      scanf()不會檢查輸入邊界,可能造成數據溢出。

      scanf_s()會進行邊界檢查。

      因為帶“_s”后綴的函數是為了讓原版函數更安全,傳入一個和參數有關的大小值,避免引用到不存在的元素,防止hacker利用原版的不安全性(漏洞)黑掉系統。

      scanf_s()參數與scanf()不同:

      例如scanf_s(“%s”,&name,n),整形n為name類型的大小,如果name是數組,那n就是該數組的大小。

      char* 與 char[n]

      這二者,最大的區別就在于,一個是動態空間分配,一個是靜態空間分配。

      如果說,使用了char *a,這時候要使用a,要手動分配空間。

      而且,當我們使用sizeof(a)的時候,得出的結果是指針的大小,這是一個坑。

      要獲取a的大小,使用len()函數。

      這里把后面一個問題一并寫進來吧,

      結構體中是應該放 char* 還是char[] 呢?

      要知道,結構體不為字符串分配任何存儲空間,所以自己掂量掂量。

      如果沒有什么特殊需求,還是放char[],如果要定制,那就char*。

      反正這倆我都試過,一個是定長包,相對簡單,一個是不定長包,雖然困難了點,可以克服。

      getchar() 與 putchar()

      getchar的用法

      getchar()是stdio.h中的庫函數,它的作用是從stdin流中讀入一個字符,也就是說,如果stdin有數據的話不用輸入它就可以直接讀取了,第一次getchar()時,確實需要人工的輸入,但是如果你輸了多個字符,以后的getchar()再執行時就會直接從緩沖區中讀取了。

      實際上是 輸入設備->內存緩沖區->程序getchar

      putchar的用法

      (1)輸出:putchar函數只能用于單個字符的輸出,向終端輸出一個字符,且一次只能輸出一個字符。

      (2)格式:對于變量來說,格式為:putchar(ch);對于常量來說,格式為:putchar(‘ch’),對于轉義字符來說,格式為:putchar(’\n’)。

      sprintf()做字符串拼接

      字符串的處理一直是很重要的問題,C語言中的字符串拼接又不像Python里面直接一個加號就能解決的。

      那么要怎么處理呢?這里采用 sprintf() 的方式來做這件事情。

      int sprintf(char *str, const char *format, ...);

      1

      參數釋義:

      str -- 這是指向一個字符數組的指針,該數組存儲了 C 字符串。 format -- 這是字符串,包含了要被寫入到字符串 str 的文本。它可以包含嵌入的 format 標簽,format 標簽可被隨后的附加參數中指定的值替換,并按需求進行格式化。format 標簽屬性是 %[flags][width][.precision][length]specifier,具體講解如下:

      1

      2

      不多說,上案例:

      char s[40]; sprintf(s,"%s%d%c","test",1,'2'); /*第一個參數就是指向要寫入的那個字符串的指針,剩下的就和printf()一樣了

      1

      2

      設計原則:“需要知道”原則

      為什么我覺得這個部分值得這么多星星呢?可能有的朋友覺得不值。

      寫幾個項目,再優化,就知道了。

      “需要知道”原則,類似于“單一職責原則”,盡可能保持每個函數內部工作對該函數的私密性,只共享那些需要共享的變量。

      作用域·鏈接

      一個C變量具有以下鏈接之一:外部鏈接、內部鏈接或空鏈接。

      具有代碼塊作用域或者函數原型作用域的變量具有空鏈接,意味著它們是由其定義所在的代碼塊或函數原型所私有。

      重點來了:具有文件作用域的變量可能有內部鏈接或外部鏈接,一個具有外部鏈接的變量可以在一個多文件的程序的任何地方使用,一個具有內部鏈接的變量可以在一個文件的任何地方使用。

      那怎樣知道一個文件作用域變量具有內部鏈接還是外部鏈接?可以看看在外部定義中是否使用了存儲類說明符static。

      extern

      把變量的定義聲明放在所有函數之外,即創建了一個外部變量。為了使程序更加清晰,可以在使用外部變量的函數中通過使用extern關鍵字來再次聲明它。

      如果變量是在別的文件中定義的,那么使用extern來聲明該變量就是必須的。

      argc 和argv

      在Linux底下編程的時候,經常會看到如下的一行代碼:

      int main(int argc,char*argv[]){}

      1

      有時候,這個argv還會在main函數實現中被用到,那么就會有小伙伴不知道是干嘛用的,或者說知道是干嘛用的,不知道怎么用。

      我也困惑過,所以寫下來。

      main(int argc,char *argv[ ]) argv為指針的指針 argc為整數 char **argv or: char *argv[] or: char argv[][]

      1

      2

      3

      4

      5

      6

      7

      假設程序的名稱為CX,

      當只輸入CX,則由操作系統傳來的參數為:

      argc=1,表示只有一程序名稱。

      argc只有一個元素,argv[0]指向輸入的程序路徑及名稱:./CX

      當輸入==./CX CanShu_1==,有一個參數,則由操作系統傳來的參數為:argc=2,表示除了程序名外還有一個參數。

      argv[0]指向輸入的程序路徑及名稱。 argv[1]指向參數para_1字符串。

      1

      2

      當輸入==./CX CanShu_1 CanShu_2== 有2個參數,則由操作系統傳來的參數為:argc=3,表示除了程序名外還有2個參數。

      argv[0]指向輸入的程序路徑及名稱。 argv[1]指向參數para_1字符串。 argv[2]指向參數para_2字符串。

      1

      2

      3

      4

      5

      以此類推.

      C/C++預編譯/條件編譯指令

      實在不想再長篇大論了,偷個懶吧:講通C/C++預編譯/條件編譯指令 #ifdef,#ifndef,#endif,#define,…

      指針篇

      開發成長之路(3)-- C語言從入門到開發(講明白指針和引用,鏈表很難嗎?)

      精品專欄打造計劃

      C 語言 Python

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:淺談HBase的數據分布
      下一篇:Unix基礎之環境變量
      相關文章
      亚洲第一页在线播放| 67pao强力打造67194在线午夜亚洲| 亚洲手机中文字幕| 久热综合在线亚洲精品| 国产精一品亚洲二区在线播放| 国产成人亚洲精品影院| 亚洲精品和日本精品| 亚洲福利在线播放| 亚洲国产天堂久久综合| JLZZJLZZ亚洲乱熟无码| 国产成人99久久亚洲综合精品| 亚洲黄黄黄网站在线观看| 亚洲国产成人影院播放| 亚洲XX00视频| 久久精品国产精品亚洲下载| 青青草原亚洲视频| 久久亚洲国产精品一区二区| 亚洲成AV人片在线观看| 久久久久亚洲av无码专区导航| 亚洲麻豆精品果冻传媒| 亚洲午夜国产精品| 国产精品亚洲综合久久 | 亚洲日韩国产精品第一页一区| 中文字幕亚洲一区二区三区 | 亚洲国产专区一区| 亚洲午夜久久久久久噜噜噜| 亚洲日产韩国一二三四区| 亚洲av无码专区国产乱码在线观看| 亚洲av无码不卡一区二区三区| 亚洲韩国—中文字幕| 亚洲人和日本人jizz| 亚洲色欲色欲www在线播放| 欧美激情综合亚洲一二区| 亚洲欧洲日本在线| 国产精品久久久亚洲| 亚洲男人天堂影院| 亚洲熟妇丰满xxxxx| 亚洲Av无码乱码在线znlu| 亚洲午夜未满十八勿入网站2| 亚洲av色福利天堂| 亚洲一区二区三区在线|