1. 程式人生 > >開啟C語言【困難模式】(1)

開啟C語言【困難模式】(1)

前言

談到C語言,很多人都會笑笑,好像C語言看起來很平凡,很普通,很大眾。然而值得注意的是,這是一門極其底層的語言,可以直接調用匯編語句,使用系統函式。不論是系統開發,驅動開發,作業系統還是緩衝區溢位攻擊等,C語言永遠是理解萬物的基石。

說來慚愧,博主此刻距離C語言的第一堂課已兩年有餘,雖然還都記得,但在學習時淺嘗輒止,甚至使用VC大部分都只是點了一下“!”。那麼,就從這裡,開始重拾C語言,用C語言進行更多的開發和使用,也用一個資訊保安學生的角度重新去審視C語言自己應該注意些什麼。祝願自己在明年夏天找工作前儘快掌握更多底層知識,創造更多有價值的成果。

一些簡單的知識,博主不再記錄,只做有意義的事。

第一階段的學習參照《學通C語言的24堂課》,如需圖書資源請在下方評論。

第一部分 基礎篇

一、資料型別有:

1.基本型別:整型、字元型、實型(浮點型)和列舉型別。

2.構造型別:陣列型別、結構體型別和共用體型別。

3.指標型別:C語言的精華所在,指標的值表示某個記憶體地址。

4.空型別:關鍵字是void,對函式返回進行限定及對函式引數進行限定。

轉義字元:

1.\n:回車換行

2.\t:橫向跳到下一製表位置

3.\v:豎向跳格

4.\b:退格

5.\r:回車

6.\f:走紙換頁

7.\\:反斜線“\”

8.\a:鳴鈴

9.\ddd:1~3位八進位制數所代表的字元

10.\xhh:1~2位十六進位制數所代表的字元

define定義符號常量

讀到了扎克伯格的奮鬥史,如果說他對資訊的使用觸及了底線,我想在他在哈佛大學學習時期,已經有這樣的思想了。

二、表示式是C語句的主體,在C中表達式由操作符和運算元組成。表示式產生的作用有以下兩種情況:放在賦值語句的右側、放在函式的引數中。

賦值運算子=

強制型別轉換:(型別名)(表示式)

算術運算子:兩個單目運算子(正、負)和5個雙目運算子(加減乘除和取模)。在算術表示式中,加減乘除和日常數學裡的規則一樣。應當注意一下,在運算子結合性上,分為自左向右和自右向左兩種。同時要注意算術運算子的優先順序。

關係運算符。需注意的是==和=的區別。

邏輯運算子&&、||、!。

位邏輯運算子與表示式:

1.位邏輯運算子:&(位邏輯與)、|(位邏輯或)、^(位邏輯異或)、~(取反),值得注意的是這四個運算子只能用於整型表示式。通常用於對整型變數進行位的設定、清零和取反,以及對某些選定的位進行檢測。

2.檢查位的表示式:if(Field&BITMASK)。其中運算子用來對BITMASK變數的位進行檢測,檢測是否與Field變數的位有吻合之處。

逗號運算子:

表示式1,表示式2,……,表示式n

逗號表示式的求解過程是:先1,後2,再3,直到最後n。整個表示式的值是表示式n的值。

值得注意的是,a=2+5,3+5,4+5,a的值是7而不是9,這是因為賦值運算子的優先順序比逗號運算子的優先順序高。可以改為a=(2+5,3+5,4+5),a的值此時為9.

三、資料輸入/輸出函式

語句是用來向計算機系統傳送操作指令的。一個程式包含宣告部分和執行部分,執行部分為語句,而定義變數這種宣告部分則不是語句。

字元的輸入輸出 :putchar(ch)用於字元或轉義字元的輸出,getchar()用於字元的輸入

字串的輸入輸出:puts(char *str)用於字串的輸出,gets(char *str)用於字串的輸入。這裡括號裡的事一個字元陣列

printf格式輸出:

printf的附加格式:

scanf使用的格式字元:

值得注意的是字串結束標誌為‘\0’,常常用於緩衝區溢位的使用。

scanf的附加格式:

四、設計選擇/分支結構程式

if語句、if……else語句、else if語句

條件運算子

switch語句,最最關鍵的default,用於對自己還未想到的情況統一處理,忽略了它是很多漏洞出現的原因,無論是c、java、python,還是各種網路指令碼語言。上面的else也有此類作用。

談及if else和switch的比較,前者速度更快,但在處理五種以上的多種情況時,顯然在程式碼編輯和結構上不如switch。

五、迴圈控制

while語句

do……while語句

for語句,一般形式為for(表示式1,表示式2,表示式3)。我們更多關注它的變體:

如果省略了表示式1,則應在for語句之前就進行賦值;

省略表示式2,則會無限制的迴圈,設計一下可吃掉記憶體;

省略表示式3,也會無終止的迴圈,吃掉記憶體。

使用逗號表示式,則會在執行相應語句的時候,從左到右執行。

比較一下:

迴圈巢狀

轉移語句:

goto語句,無條件轉向語句,可以使程式立即跳轉到函式內部的任意一條可執行與。goto關鍵字後面帶一個識別符號,這個識別符號是同一個函式內某條語句的標號。

如:

//
//  main.cpp
//  cd練習
//
//  Created by 張立鵬 on 2018/12/22.
//  Copyright © 2018年 張立鵬. All rights reserved.
//

#include <iostream>

int main(int argc, const char * argv[]) {
    // insert code here...
    goto Show;
    printf("The message before ShowMessage");
Show:
    printf("ShowMessage\n");
    return 0;
}

上述函式中,第一個printf沒有得到執行,執行結果為:

 

break語句,可用於退出迴圈

continue語句,用於結束本次迴圈,進入下一次的迴圈操作。

六、陣列

陣列需要注意下標為0~n-1,事實上指標陣列超過了n-1後,就出現了溢位現象。

一維陣列

二維陣列

多維陣列

陣列排序方法:選擇、冒泡、二分、插入、交換。

要注意陣列元素之間的比對,=和equal之間有很大差別,前者是變數地址,後者是陣列元素包含的值。

七、字元陣列

字元陣列的結束標誌為\0,因此字元陣列等於“HELLO”時,實際上有六個元素,因為還有一個“\0”。

字串處理函式:

字串複製:strcpy(目的字元陣列名,源字元陣列名)。可以從字串或者字元陣列複製到字元數組裡面,目的字元陣列不可是字串。當然了,更不允許使用一個系統定義的賦值語句講一個字串常量或字元陣列直接付給一個字元陣列。

字串連線:strcat(目的字元陣列名,源字元陣列名)。

字串比較:strcmp(目的字元陣列名,源字元陣列名)。

字串的大小寫轉換。

獲取字串長度。

第二部分 提高篇

一、函式的應用

二、變數的儲存類別

三、指標

指標的自加,是進入下一個位元組,可以說p++即為p=p+4

也可以定義指標陣列,而在二維陣列和指標的結合中:

 

使用字元指標執行一個字串,即理論上將字串看作一個字元陣列,使用指標和陣列的結合來訪問字串。字串陣列和字元的結合使用,則把字串陣列成功變成了二維陣列來處理。這樣都是可行的,只是務必要注意\0這一字串結尾字元。

指向指標的指標

指標變數作為函式引數,需要注意的是指標作為形參,會真正對指向的變數進行操作,而普通變數只是呼叫,函式完畢後,仍未原值。指標變數做函式引數呼叫函式雖然不能改變實參指標變數的值,但可改變實參指標變數所指變數的值。

返回指標值的函式,可能並不能簡便易行,這裡只是說明其真實存在:


#include <iostream>
int *per(int a,int b);
int Perimeter;
int main(){
    int iWidth,iLength;
    int *iResult;
    printf("請輸入長方形的長:\n");
    scanf("%d",&iLength);
    printf("請輸入長方形的寬:\n");
    scanf("%d",&iWidth);
    iResult=per(iWidth, iLength);
    printf("長方形的周長是:\n");
    printf("%d\n",*iResult);
}
int *per(int a,int b){
    int *p;
    p=&Perimeter;
    Perimeter=(a+b)*2;
    return p;
}

結果:

請輸入長方形的長:

6

請輸入長方形的寬:

4

長方形的周長是:

20

Program ended with exit code: 0

 

指標陣列作main函式的引數

帶參的main()函式形式為:main(int argc,char *argv[])。從形式上看,包括一個整型和一個指標陣列。

四、結構體

將結構體變數換成陣列,就形成了結構體陣列,

結構體指標的使用:

//
//  main.cpp
//  Created by 張立鵬 on 2018/12/22.
//  Copyright © 2018年 張立鵬. All rights reserved.
//

#include <stdio.h>
#include <string.h>
struct Student{
    char cName[20];
    int iNumber;
    char cSex;
    int iGrade;
}student;
int main(){
    struct Student* pStudent;
    pStudent=&student;
    strcpy(pStudent->cName, "SuYuQun");
    pStudent->iNumber=1017;
    pStudent->cSex='M';
    pStudent->iGrade=3;
    
    printf("--The Student's information---\n");
    printf("Name:%s\n",student.cName);
    printf("Number:%d\n",student.iNumber);
    printf("Sex:%c\n",student.cSex);
    printf("Name:%d\n",student.iGrade);
    return 0;
}

指向結構體陣列的指標:

//
//  main.cpp
//  Created by 張立鵬 on 2018/12/22.
//  Copyright © 2018年 張立鵬. All rights reserved.
//

#include <stdio.h>
#include <string.h>
struct Student{
    char cName[20];
    int iNumber;
    char cSex;
    int iGrade;
}student[5]={
    {"WittPeng1",001,'M',3},
    {"WittPeng2",002,'W',3},
    {"WittPeng3",003,'M',2},
    {"WittPeng4",004,'M',3},
    {"WittPeng5",005,'W',3}
};
int main(){
    struct Student* pStudent;
    int index;
    pStudent=student;
    for(index=0;index<5;index++,pStudent++){
        printf("No.%d student:\n",index+1);
        printf("Name:%s\n",pStudent->cName);
        printf("Number:%d\n",pStudent->iNumber);
        printf("Sex:%c\n",pStudent->cSex);
        printf("Name:%d\n",pStudent->iGrade);
    }
    return 0;
}

結構體可做函式引數。

包含結構體的結構體。

五、共用體

共用體看起來很像結構體,但結構體定義了一個由多個數據成員組成的特殊型別,而共用體定義了一塊為所有資料成員共享的記憶體。共用體也稱聯合,使幾種不同型別的變數放在同一段記憶體單元中,共用體在同一時刻只能有一個值,屬於某一個數據成員。由於所有成員處於同一塊記憶體,因此共用體的大小就等於最大成員的大小。

//
//  main.cpp
//  Created by 張立鵬 on 2018/12/22.
//  Copyright © 2018年 張立鵬. All rights reserved.
//

#include <stdio.h>
enum Color{Red=1,Blue,Green} color;
int main(){
    int iColor;
    scanf("%d",&iColor);
    switch (iColor) {
        case Red:
            printf("The color is Red\n");
            break;
        case Blue:
            printf("The color is blue\n");
            break;
        case Green:
            printf("The color is green\n");
            break;
        default:
            printf("???\n");
            break;
    }
    return 0;
}

六、預處理命令

巨集定義

帶參的巨集定義:

例:

#include指令

條件編譯:只對其中某一部分內容滿足一定條件的時候才會進行編譯。

#if命令,一般形式為:

#if 常數表示式

         語句段

#endif

如果常數表示式為真,則編譯語句段,否則跳過這段程式。

#else語句

#elif語句

三、高階篇

一、儲存管理

記憶體組織方式:程式被組成4個邏輯段,可執行程式碼、講臺資料、動態資料(堆)、棧。

在堆的管理中,malloc函式和free函式來從堆中動態地分配和釋放記憶體。

calloc函式,原型為void * calloc(unsignned n,unsigned size),在記憶體中動態分配n個長度為size的連續記憶體空間陣列。calloc函式會返回一個指標,該指指向動態分配的連續記憶體空間地址。當分配錯誤時,返回NULL。

例如使用該函式分配一個整型陣列記憶體空間,程式碼為:

int* pArray;

pArray=(int*)calloc(3,sizeof(int));

realloc函式

free函式:

 

記憶體丟失

二、連結串列在C語言中的應用

資料結構的知識了。連結串列相對於陣列,插入和刪除很方便,但是查詢環節很麻煩。

三、棧和佇列

棧為先進後出,佇列為先進先出。

四、C語言中的位運算

一個位元組由8位二進位制組成。

位運算操作符:

迴圈移位:

位段:

位段型別是一種特殊的結構型別,其所有成員均以二進位制位為單位定義長度,並稱結構中的成員為位段。

關於位段需要分配多少位,要看這一位對應的情況有多少,和資訊位與情況種類的原理相同。

五、檔案操作技術

檔案的開啟:

檔案的關閉:

fclose(檔案指標)

檔案的讀寫:

檔案的定位:

六、圖形影象處理

getche用於從鍵盤上獲取一個字元。

圖形顯示

圖形模式下的文字輸出

(此部分博主沒有展示,需要相關資料的請於下方評論)

 

 

謝謝閱讀~