谭浩强《c语言程序设计》第四版--重点难点总结
1、什么叫結構化程序設計,主要內容是什么?
* P33頁
2、while 和do–while的執行方式和區別?P111
* do 在循環體之前執行,這種循環體至少執行一次。
* while:先判斷再執行循環體;do–while 先執行再判斷;
* 重點:循環次數的準確計算。
* 使用環境:當循環體至少需要執行一次時;
* while(6) 表達式為真? c語言規定:0為邏輯假;非零為邏輯真;所以表達式計算結果非零也是邏輯真;
* 語法格式:do{}while();
* while 語句可以使用break和continue語句。break終止循環,continue終止本次循環;
3、預處理指令?
* #define
* #define A ** 任何文本替換。
* #define A a\
4、常變量和符號常量的區別?
* 常變量: const float pi=3.13159;
* 符號常量: #define PI 3.14159
* 常變量占據存儲空間;
* []用法區別?
5、什么是枚舉類型?有哪些應用?
* enum
* 變量只有幾種可能的取值。
* http://c.biancheng.net/view/2034.html
* 可用于狀態機或多分支代碼的選擇執行,比較直觀。
* 匯川M380代碼舉例:
* enum RUN_STATUS
* {
* RUN_STATUS_WAIT, // 等待啟動
* RUN_STATUS_ZERO, // 零頻運行
* RUN_STATUS_START, // 啟動
* RUN_STATUS_NORMAL, // (正常)運行
* RUN_STATUS_STOP, // 停機
* RUN_STATUS_JOG, // 點動運行
* RUN_STATUS_POS_CTRL, // 位置控制
*
* RUN_STATUS_TUNE, // 調諧運行
* RUN_STATUS_DI_BRAKE_DEC, // DI端子直流制動頻率減速
* RUN_STATUS_DI_BRAKE, // DI端子的直流制動(非啟動直流制動和停機直流制動)
* RUN_STATUS_LOSE_LOAD, // 掉載運行
* RUN_STATUS_SHUT_DOWN // shut down, 關斷
* };
* extern enum RUN_STATUS runStatus;
6、共用體類型?
* 同一個內存單元存儲不同的類型變量,變量覆蓋存儲。
* 方便內存的不同訪問形式;
* M380代碼舉例:
* union RUN_FLAG
* {
* Uint16 all;
* struct RUN_FLAG_BITS bit;
* };
* extern union RUN_FLAG runFlag;
7、DSP2812的整形,長整型等字節數為多少?
* 32位CPU的含義:內存編址位32位;即尋址位寬32位;
* C語言不確定不同數據類型的字節數,提高了C語言的通用性,具體字節數由編譯器決定。
* 意義:確定數據范圍,防止數據截斷及溢出。
* 位寬:
* #ifndef DSP28_DATA_TYPES
* #define DSP28_DATA_TYPES
* typedef int int16;
* typedef long int32;
* typedef long long int64;
* typedef unsigned int Uint16;
* typedef unsigned long Uint32;
* typedef unsigned long long Uint64;
* typedef float float32;
* typedef long double float64;
* #endif
* 程序特別采用typedef對數據類型位數進行解釋。
8、負數的二進制描述?
* 補碼存放原則。 對應的正數的二進制 正數取反加一。
* -14~~~14(0000 1110)~11110001~11110010
*
9、除法運算A/B,當B為0時?10、數據類型的混合運算?P54頁
* 如果運算符兩側的數據類型不同,則先自動進行類型轉換,使兩者成為同一種數據類型,然后進行運算。
* 強制類型轉換的括號問題。
11、強制類型轉換和自動類型轉換?
* (int)a,原始的a的類型未改變;
* 括號運算符優先級最高;
* 自動類型轉換是由低類型往高類型自動轉換;若要讓變量由高往低轉換,需要用強制類型轉換;
* 取余運算%,需要強制類型轉換,否則不合法;實參和形參對應必須采用強制類型轉換;
12,13、inti;i=3.68,i的值為多少?
* i為3.浮點數賦值給整形時,先對浮點數取整,再傳遞;
* 占字節多的整形變量賦值給字節少的整型時,只將低字節原封不動送到被賦值變量。“即會發生截斷問題”。
* 整型數據傳遞屬于按存儲形式直接傳送;實型與整型傳遞需要變換存儲形式;
14、int a,b,c=5;的賦值含義?
* a,b,c為整形變量,但只對c賦值;
* 需要對多個變量賦值的寫法:int a=5,b=5,c=5;
15、若a=4;b=5;求a&&b,a||b,a&b,a|b?
* 邏輯運算符:&& || 結果為真或假。 a,b為非零數,所以a&&b為1,a||b為1;
* 位運算符。 & | ^ ~ a&b為:0100&0101 .
* 異或,相同為0,不同為1;
* 位運算符的操作數要求為整型;
16、Max=(a>b)?a:b;
* 條件運算符:
* 運算符的優先級很低,是c語言唯一的一個三目運算符。
* 首先計算表達式1,若為真(非零)那么表達式的值為表達式2,表達式3不求值,否則為表達式3,此時表達式2不求值;
17、switch語句中若case語句沒有break,會出現什么問題?
* case是入口標號。執行完一個case標號后面的語句后,就從此標號開始執行下去,不再進行判斷;
* 因此若沒有break,將繼續執行;
* M380代碼舉例:
* case SYNC_SVC:
* case SYNC_VF:
* case ASYNC_VF:
* if(gMainStatus.RunStep == STATUS_SPEED_CHECK)
* {
* gOutVolt.Volt = gFeisu.VoltCheck;
* gMainCmd.FreqSyn = gFeisu.SpeedCheck;
* gMainCmd.FreqToFunc = gMainCmd.FreqSyn;
* gVFPar.FreqApply = gMainCmd.FreqSyn;
* gOutVolt.VoltPhaseApply = (gFeisu.SpeedLast > 0) ? 16384 : -16384;
* }
* break;
* switch(表達式),表達式的值必須為整型。
18,19、for語句的執行過程計算sum值。
* for(expression1;exp2;exp3),exp1為初始化部分,只在循環開始時執行一次;exp2為條件部分,在循環體每次執行前都要執行一次;exp3為調整部分,在循環體每次執行完畢后,在條件部分執行前執行。
* 等價于:
* exp1;
* while(exp2)
* {
* 循環體;
* exp3;
* }
* for語句中也可以使用break和continue。break指直接退出整合for循環;continue指結束本次循環,直接執行調整部分。
* for用于循環處理對比while的優點?
* for循環將操作循環的表達式收集在一次,當循環體較大時,該優點較突出;
20、如何為二維數組賦值?
* 二維數組: float A[4][4];行列引用都從0開始。A[4][4]的引用是錯誤的;
* 初始化方式1:
* A[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
* 初始化方式2:
* A[4][4]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
* 初始化方式3:
* A[4][4]={{1},{2},{3}};
* 部分賦值;
21、字符數組末尾’\0’的作用,常量數組末尾有無‘\0’?
* 為弱化字符數組的寬度,采用’\0’作為字符數組的結束標志;
22、有參函數調用,什么是實際參數,什么是形式參數?
* 主調函數吧實際參數的值傳遞給被調用函數的形式參數;
* 定義函數時,函數名后為形參列表;調用函數時:函數名后時實參列表;
* 類型名 函數名(形參列表)
* {
* 函數體
* }
* 有參函數調用采用值傳遞;指針作為形參,相當于傳址調用。會更改實參的值;
* 函數返回: return x; 或 return(x);返回值類型由函數類型決定。
23、定義函數時,需要在函數名前增加類型名,類型名與什么有關?
* 定義函數時需要指定函數的類型標識符。以便指定函數帶回來的值的類型。無返回值的函數類型用void。
* 類型名決定了函數返回值的數據類型。
24、函數的聲明?作用?怎么進行聲明?
* 當要被調用函數的定義位置在調用它的函數的后面,應該在主調函數中對被調用的函數做聲明。
* 函數聲明:把函數名,函數參數個數,參數類型等信息通知編譯系統,以便將進行合法性檢查。確保函數被正確調用。
* 進行原型聲明最安全的方式:
* 將原型置于一個單獨的文件,當其他源文件需要這個函數的原型時,采用#include 包含該文件;
* 避免多次拷貝錯誤,也方便維護。
* 舉例:M380–MotorSvcInclude.h
* /供外部引用函數聲明****/
* void ResetSVC(void);
* void SVCCalRotorSpeed(void);
* void SvcCalOutVolt(void);
* void SVCCalFlux_380(void);
* void SvcCalOutVolt_380(void);
* void SVCCalRotorSpeed_380(void);
* #include “MotorSvcInclude.h”
25,26、變量的定義方式?main里定義的變量能否在其他函數中應用?
* 局部變量和全局變量
* 定義變量的3種情況;
* 1) 在函數的開頭定義;
* 2)在函數內的復合語句內定義;
* if (tickerTempDeal >= TEMPERATURE_CALC_PERIOD / TEMPERATURE_CALL_PERIOD) // 時間錯開
* {
* Uint32 k;
* LINE_STRUCT aiLine = LINE_STRTUCT_DEFALUTS;
*
* Uint16 p = &funcCode.code.aiCalibrateCurve[2].before1; // 實測電壓
* #define MOTOR_T_SENSOR_AI_MAX_VOLTAGE_IDEA 3300 // 3300mv
* // 獲取溫度檢測的采樣電壓
* k = (4095L << 4) * tickerTempDeal / MOTOR_T_SENSOR_AI_MAX_VOLTAGE_IDEA;
* temperatureVoltageOrigin = tempSampleSum / k;
* // 電機溫度傳感器AI2采樣校正曲線
* aiLine.mode = 1; // 不限幅
* aiLine.y1 = ((int32)(int16)((p + 0)) * 0x7FFF) / MOTOR_T_SENSOR_AI_MAX_VOLTAGE_IDEA; // (理想)輸入電壓1,精密儀器測量電壓
* 3)在函數的外部定義;
* 1)2)都屬于局部變量,3)為全局變量;作用域為定義位置以后;
* main中定義的變量也只在main中有效,并不因為在中函數中定義二在整個文件或程序中有效;
* 局部變量由于作用范圍小,因此不同函數可以采用相同的局部變量名;全局變量在程序執行過程中都占用存儲單元;全局變量時程序耦合復雜,降低程序的可讀性和可維護性,因此應減少全局變量的使用。
27,28,29,30、什么是靜態存儲區,動態存儲區,動態存儲區存放哪些數據?
* 靜態存儲區指程序運行期間,由系統分配固定的存儲空間的方式。而動態存儲區是程序運行期間根據需要進行動態的分配存儲空間的方式。
* 全局變量存放在靜態存儲區;
* 函數形參,自動變量,函數調用的現場保護和返回地址存放在動態存儲區;即堆棧中。
* 變量定義由兩部分構成:存儲類型,數據類型。存儲類型:auto, static, register, extern
* auto
* 不聲明為static的局部變量、形參都是auto類型;auto可以省略;
* static
* 局部變量在函數調用結束后不消失,而保留原值,存儲單元不釋放;用static。即靜態局部變量;
* 局部變量加static后,作用域仍然在該代碼塊中或該函數中有效;
* 會降低程序可讀性;
* 全局變量 加 static
* 將外部變量的作用域限制在本文件中
* 靜態外部變量,便于程序的模塊化;
* register
* 寄存器變量存儲在CPU的硬件寄存器中,存取速度快;
* extern
* 外部變量聲明;用于作用域擴展;
* 全局變量作用域擴展到其他文件方法
* 在一個文件中定義外部變量;
* 在另一個文件中用extern對該變量聲明;
31、變量的定義和聲明的區別?
* 定義也稱:定義型聲明,聲明也稱:引用型聲明;
* 定義會建立存儲空間;
* 變量的定義只能出現一次,聲明可以出現多次;
* int a;為定義 ;extern int a;為聲明;
* 1. 不要把變量定義放入.h文件,這樣容易導致重復定義錯誤。
* 2. 盡量使用static關鍵字把變量定義限制于該源文件作用域,除非變量被設計成全局的。
* 3. 可以在頭文件中聲明一個變量,在用的時候包含這個頭文件就聲明了這個變量。
* function.c的神奇之處。
32、內部函數和外部函數的區別?
* 內部函數
* static 類型名 函數名(形參列表);
* 表示該函數只能被本文件中的其他函數調用;
* 外部函數
* 定義函數時,加extern表示為外部函數,省略extern則默認為外部函數,可供其他文件調用;
33,34、指針是什么?什么是指針變量?
* 指針就是變量的地址,或者函數首地址;地址形象化稱為指針;
* 指針的兩個信息:內存編號,指向的數據類型(只有指定數據類型,才能確定尋址方式);
* 指針是帶類型的地址;
* 如果用一個變量專門存放另一個變量的地址,則它稱為指針變量;
* DSP2812為32位處理器,意味著指針變量需要32位表示;
* 運算符: * (指針運算符) & (取地址運算符)
* 指針變量的定義和引用:
* int p;指:p為指向整型數據的指針變量; 而不是int p;
* 變量是p,而不是*p;
* p=&a;
* 例子: *100=25? 錯誤
* 正確寫法:
* *(int *)100=25; //*的對象必須是指針變量,因此先將100強制類型轉換為整形指針變量,再賦值,即將地址100中放置整型數據25。
* 指針變量作為形參實現傳址調用的應用
* MD380傳址調用代碼舉例:
* void inline UVWToAlphBetaAxes(UVW_STRUCT_Q24 * uvw, ALPHABETA_STRUCT * AlphBeta)
* {
* AlphBeta->Alph = ((llong)uvw->U * 23170L)>>15;
* AlphBeta->Beta = ((llong)((long)uvw->V - (long)uvw->W) * 13377L)>>15;
* }
* inline 關鍵字 :表示內聯函數。 內聯函數在可讀性方面與函數是相同的,而在編譯時是將函數直接嵌入調用程序的主體,省去了調用/返回指令,這樣在運行時速度更快。
* C語言允許直接訪問物理地址,可直接對硬件進行操作。C語言同時具有高級語言的功能,又具有低級語言的功能,C語言的這種雙重性,使c語言不僅成為系統描述語言優勢通用的程序設計語言。
35、采用指針引用數組變量:
* 指針可以進行加法和減法運算。計算結果是另一個指針。由于指針存放的是地址,所以指針加法的含義是指向n后的地址。n由指針變量的類型確定。
* p+=3指數組的第四個元素的地址;
36、int *p[4]; 和 int (p)[4]的區別是什么?
* int p[4]; 指針數組。
* []的優先級高于,所以P[4]首先是一維數組,之后和結合,表示對數組元素間接訪問操作后是一個整形。所以:每個元素中存放的是一個整形變量的地址;也就是說該數組存放了四個變量的地址。
* int (*p)[4] 一維數組的指針變量。
* *p表示p是一個指針;[4] 表示指針指向的對象的類型是具有4個元素的數組;int 表示該數組的元素是int類型的.
* (*p)[4]表示每個元素是一維數組的首地址,一共保存了4個一維數組的首地址。
37、什么是函數指針,函數指針的應用有哪些?
* 函數編譯時,會把函數的源代碼轉換為可執行代碼并分配存儲空間。這段代碼有一個起始地址。每次調用該函數時,從該入口開始執行。函數名就是該入口地址。因此函數名就是函數的指針。代表函數的起始地址。
* 可以定義一個指向函數的指針變量。存放某一個函數的起始地址。
* int (*p)(int,int);
* p=max;c=(*p)(a,b);
*
* 用函數名調用函數只能調用一個函數,而采用函數指針調用函數,可以通過函數指針的不同賦值調用不同的函數。
* 比如調用同步機,異步機的矢量控制代碼。
38、函數指針定義格式和引用格式?
* 類型名 (*指針變量名)(函數參數列表)
* eg: int (*p)(int ,int )
* 特征: 指針變量后有括號。說明是函數指針。
* 函數指針只能指向具有特定特征的函數。因而所有被同一指針運用的函數必須具有相同的參數和返回類型。
* 引用格式:
- 指針函數。 Int *p(int x,int y) p先與括號運算符結合,表示p為函數形式。再與 * 運算符結合表明p是指針。
- Int *p(int x,int y) 返回值為變量的地址。
- 含義:函數計算完成后返回一個地址作為返回參數。
- 運算符優先級中:括號運算符優先級最高。
40、什么是動態內存分配?
* malloc所分配的是一塊連續的內存,以字節為單位,并且不帶任何的類型信息free用于將動態內存歸還系統void* malloc(size_t size);void free(void* pointer);
* 返回指針的值是所分配內存區域中第一個字節的地址,當分配內存失敗時,返回空指針。
* 動態內存分配是C語言中的強大功能程序能夠在需要的時候有機會使用更多的內存
41、如何聲明結構體類型?
* 結構體是用戶自定義類型的一種。
* 是一種聚合數據類型。
* 聲明的幾種形式。
* 1.先聲明結構體類型,再定義該類型變量:struct UDP_Server_Thread_Para{void *pData;int Len;};UDP_Server_Thread_Para UDPThreadPara1,UDPThreadPara2;2.在聲明的同時定義變量:struct UDP_Server_Thread_Para{void *pData;int Len;}UDPThreadPara1,UDPThreadPara2;3.不指定類型名直接定義結構體類型變量:struct{void *pData;int Len;}UDPThreadPara1,UDPThreadPara2;42、什么是結構體數組,如何聲明結構體數組?
* struct STUDENT stu[10];
* 該結構體數組,共有 10 個元素,每個元素都是一個結構體變量,都包含所有的結構體成員。
43、P.student, (*p).student , p->student 的區別和聯系?
*
44、關鍵字 typedef的作用?
* typedef是在計算機編程語言中用來為復雜的聲明定義簡單的別名,它與宏定義有些差異。
* 在編程中使用typedef目的一般有兩個,一個是給變量一個易記且意義明確的新名字,另一個是簡化一些比較復雜的類型聲明typedef int int16_lib;typedef long int32_lib;typedef unsigned int Uint16_lib;typedef unsigned long Uint32_lib;typedef float float32_lib;typedef long double float64_lib;typedef long long int64_lib;typedef unsigned long long Uint64_lib;
軟件工程師的基本素養:
* 編程語言的熟悉,既編程速度的加快;
* 代碼質量的提高,既編寫出的代碼漏洞少、缺陷密度低;
* 以及編程風格改善,代碼易于閱讀、魯棒性好;
* 代碼安全性好,能考慮到多種安全場景,避免遺留安全方面的坑。
靜態測試 是對代碼進行掃描分析,檢測它的語法規則復雜度等是否符合要求,它主要是為軟件的質量保證提供依據,以提高軟件的可靠性和易維護性。靜態測試主要包括:
* 編程標準驗證;
* 數據流分析技術;
* 質量度量信息;
* 代碼結構可視化顯示;
* 測試外殼的創建
*
* 動態測試 是使被測代碼在相對真實環境下運行,從多角度觀察程序運行時能體現的功能、邏輯、行為、結構等的行為,以發現其中的錯誤現象。對于嵌入式系統,要想保證測試的真實性,就需要將被測代碼下載到目標板運行,并且測試系統不要影響目標系統的運行,就需一定硬件支持。動態測試主要包括:
* 功能的測試;
* 代碼覆蓋率 (CodeCoverage);
* 性能分析測試;
* 內存分析;
* 邏輯觸發執行跟蹤;
* 實時多任務操作系統分析。
總結
以上是生活随笔為你收集整理的谭浩强《c语言程序设计》第四版--重点难点总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 蔻享学术下载器:KouShare-dl
- 下一篇: linux安装docker部署java项