C 語言基礎

C 語言基礎

// 引入頭文件。裏面包含了重要的 printf。
#include <stdio.h>

// 入口函數。
// 參數一指輸入的參數個數,參數二保存了全部參數。
// 返回值爲 int 類型,通常 0 表明成功,負數表明失敗。
int main(int argc,char* argv[]){
    printf("Hello World!\n");
    return 0;  // 表明執行成功。
}
複製代碼

經過指令的編譯與執行linux

MAC 下的編譯使用 clang,Linux 下的編譯使用 gcc。數組

gcc/clang -g -o Hello xxx.c微信

  • -g 是 debug 模式,帶有調試信息的。markdown

  • -o 指明輸出文件的名字函數

  • xxx.c 源代碼oop

在 MAC 或 Linux 下使用 ./Hello 來執行ui

集成環境的運行,後臺其實也是這個步驟。編碼

經常使用基本類型

  • short(短整型)、int(整型)、long(長整型)spa

  • float(單精度浮點型,通常狀況使用 float。)、double(雙精度浮點型,精度高,適用於科學計算等。)操作系統

  • char(字符)、char*(字符串)

  • void(對類型不關心時)

基本運算

  • +、-
  • *、/、%
int main(int argc,char* argv[]){ 
    int a = 10;
    float b = 12.5;
    // 打印結果;a+b=22.500000 (float 類型)
    printf("a+b=%f\n",a+b);
    // 打印結果;... , a*b=125.000000 (float 類型)
    printf("a+b=%f\n,a*b=%f\n",a+b,a*b);
    
    char c = 'a';
    // 打印結果;c=f(c 爲字符 a,c 加數字能夠變爲另外一個字符,c+1=b,c+2=c,...)
    printf("c=%c\n",c+5);
    // 打印結果;c=102(f 的實際編碼的值就是 102)
    printf("c=%d\n",c+5);
    
    int d = 10;
    int e = d % 6; // 取餘
    int f = d / 6; // 取商
    // 打印結果;e=4,f=1
    printf("e=%d\n,f=%d\n",e,f);
    
    return 0;  // 表明執行成功。
}
複製代碼

變量與常量

  • int a = 0; // 變量,能夠再賦值。能夠不賦值初始值。

    變量在計算機中的物理意義,就是一個寄存器。寄存器是臨時存儲數據的,它的速度很是快。從內存中取一塊數據時,首先存儲到寄存器,當改變這個值時,刷新的是寄存器,可擦除。這樣能夠加快程序的執行速度。

  • const int len = 265; // 常量,不可改變。須要賦值初始值。

    在編譯程序時,程序中設定了一段靜態緩衝區,靜態緩衝區是受保護的,經過正常途徑是不可修改的。但若是知道內存的具體物理地址,也是能夠改變的。

數組

數組是有序的元素序列(C 語言的數組存放的是同一種類型的元素,索引從 0 開始),C 語言中定義數組須要告訴編譯器數組的長度。C 語言中數組的定義; char c[2], int arr[10]

int main(int argc,char* argv[]){ 
// int arr[10];
// arr[0] = 1;
// arr[1] = 2;
// printf("%d,%d\n",arr[0],arr[1]);
    
    int arr[10] = {1,2,3,};
    // 打印結果;1,2,3,0(默認狀況下,不賦值的狀況下,數組會初始化爲 0。)
    printf("%d,%d,%d,%d\n",arr[0],arr[1],arr[2],arr[3]);
    
    float f[2] = {1,2};
    // 打印結果;1.000000,2.000000
    printf("%f,%f\n",f[0],f[1]);
    
    return 0;
}
複製代碼

結構體

// 它是沒有保護的概念的(如 private 等)
struct st {
    int a; // 成員 a
    int b; // 成員 b
};
複製代碼
// 結構體能夠理解爲它是一個類
struct st{
    int a;
    float f;
};

int main(int argc,char* argv[]){
    struct st ss;
    ss.a = 12;
    ss.f = 10.2;
    // 打印結果;struct:12, 10.200000
    printf("struct:%d, %f\n",ss.a,ss.f);
    
    return 0;  // 表明執行成功。
}

複製代碼

枚舉類型

枚舉能夠認爲它是一個有限制的整型。通常狀況下的使用,是在有必定數值範圍的,好比某個屬性的取值只能爲 一、二、3。

enum em {
    red_color = 0,  // 值爲 0,若是值爲 1
    green_color,    // 值爲 1,則值爲 2
    black_color     // 值爲 2,則值爲 3
};
複製代碼
enum em {
    red_color = 5,
    green_color,
    black_color = 10,
    yellow_color
};

int main(int argc,char* argv[]){
    enum em ee;
    
    ee = green_color;
    // 打印結果;enum:6
    printf("enum:%d\n",ee);
    
    ee = yellow_color;
    // 打印結果;enum:11
    printf("enum:%d\n",ee);
    
    return 0;  // 表明執行成功。
}
複製代碼

指針

指針就是存放內存地址的變量。地址空間內的存的值,在 C 語言中,它除了能夠存放普通的數值,還能夠存放另外一個內存的地址,這個值就是指針,經過這個值就能夠訪問到其它地址,而後就能夠取出這個地址所存放的數據。因此,這個值能夠有多重含義,具體跟業務邏輯相關。

指針的做用

  • 提高執行效率。

    通常狀況下,將字符串傳入函數中,函數對字符串進行操做時,它是一個拷貝的過程,函數將字符串拷貝到本身的函數空間存放起來。屢次的拷貝會對整個 CPU 形成巨大的浪費。而指針,只須要向函數傳遞這個字符串所在的地址,函數經過指針訪問字符串。

  • 更強的控制力。

    由於它具備訪問地址的能力。像計算機的硬件實際到操做系統層都會有一個對應的映射地址,經過這個地址,C 語言就能訪問到硬件設備,並進行控制。C 語言是更底層的語言,它能夠訪問設備。

指針的操做

  • 一是對指針自己的操做。

    實際就是對地址的操做。好比,當獲取某個空間的指針後,能夠對這個指針進行加減乘除的操做,對其加一,就指向了下一個空間。

  • 二是對所指向的內容操做。

    指針指向某一個內存地址時,能夠獲取其內容,能夠對這個內容進行加減乘除的操做。

指針的定義與使用

type* var:

  • type 指類型,好比 int、void 等。
  • 而 * 表明這個變量是一個指針,能夠靠近類型 type 寫,表示這種類型的指針,關注指針是什麼類型的,也能夠靠近變量 var 寫,表示這個變量是一個指針,而對類型不關注。這兩種寫法對編譯器是沒有區別的,但在編寫代碼時,最好統一風格。

*var:表示獲取指針所指向的內容

堆內存的分配與釋放

分配內存:void* mem = malloc(size);

釋放內存:free(mem);

#include <stdio.h>
#include <stdlib.h> // malloc() 須要的頭文件

int main(int argc,char* argv[]){
    // malloc() 通常返回的是 void* 類型。
    // malloc() 在 <stdlib.h> 頭文件中。
    char* p = (char*)malloc(10); // 分配十個字符的空間
    *p = 'a';      // 第一個字符的位置
    *(p+1) = 'b';  // 第二個字符的位置
    // 將內存分配的地址告訴 printf,
    // printf 將 p 地址所指向的空間的內容以字符串的形式打印出來。
    printf("%s\n",p); // 打印結果;ab
    
    // 將 p 所指向的空間釋放掉
    // 系統管理層將內存又還給了堆空間
    free(p);
    *p = 'd';
    // 即便把空間釋放掉,但由於仍然掌握此空間的位置,知道 p 的指向。
    // 因此即便被釋放掉了,仍是能夠對其操做。
    printf("%s\n",p); // 打印結果;db
    
    // 因此爲了避免讓再訪問這個地址,要將其指向 NULL,設置爲無效地址。
    p = NULL;
// *p = 'e'; // crash
    
    return 0;
}
複製代碼

常見的內存空間

棧空間:棧的機制,後進先出。最大的特色是,在 C 語言中寫的函數,在函數內所分配的全部變量都是在棧空間分配的,當從函數退出時,從棧空間分配的資源會被自動釋放。(分配的資源是有限的,默認每一個函數棧空間的大小是 8兆。)

堆空間:須要明確的使用 malloc() 函數來分配資源,使用完內存後,要經過 free() 函數將資源釋放回堆空間,這樣別人使用時還能從堆空間分配資源。(分配的資源幾乎能夠認爲是無限的,適合須要大空間的時候。)

內存映射:像一些動態庫通常都是將它直接導入內存映射區,也是一段專門的空間。好比將某個文件直接映射到內存中,文件的內容與內存造成映射關係,當改變內存中的值時,會直接在系統內部自動更新到文件中。

Linux 內存地址的劃分:4G 32 位系統

0 ~ 0x08048000:這段是受保護空間,咱們的進程是不能訪問的。

code:存放的是進程所要執行的代碼段。

堆空間的增加是從下向上,棧空間是從上向下,每次分配空間是向下走的。堆空間與棧空間這樣的劃分是爲了減小衝突。

共享庫,或者叫內存映射區,當想經過內存改變文件時,就能夠將文件映射到 mmap 這段空間中。

內存泄漏

  • 不斷的向系統申請內存。
  • 申請的內存不用,也不釋放。

野指針:佔用別人的內存稱爲野指針。

條件判斷與循環

比較運算:>、<、>=、<=、==、!=

if/else 語句

if( a> b){ ​ ... }else{ ​ ... }

for 語句

for(int i =0; i<100; i++){ ​ ... }

while 語句

#include <stdio.h>
#include <unistd.h> // usleep() 須要的頭文件

int main(int argc,char* argv[]){
    while (1) {  // 死循環
        printf("while...\n"); // 一秒鐘打印一次
        usleep(1000000); // 微秒
    }
    return 0;
}
複製代碼

函數

C 語言中的命名通常以 Linux 的風格,單詞與單詞用下劃線鏈接,單詞通常都是縮寫。

// void 返回類型
// func 函數名稱
// int a 形參
void func(int a){
    ... // 函數不能太大,通常不超過 50 行。
}
複製代碼

函數指針:指向函數的指針變量。經過 C 語言的函數指針能夠實現 C++ 中的多態,就是定義的函數指針既能夠指向 a 函數,也能夠指向 b 函數,對外層來講,只須要調用這個函數指針就能夠了。(多態就是指一個函數能夠有不一樣的含義)

函數指針的格式:返回值類型 (*指針變量名) ([形參列表]);

int func(int x);  // 聲明一個函數
int (*f)(int x);  // 聲明一個函數指針。返回類型和形參必須與指定的函數一致。
f = func;  // 將 func 函數的首地址賦值給指針 f。而後調用 f 便可。
複製代碼
#include <stdio.h>

int func(int a){
    printf("a=%d\n",a);
    return 0;
}

int func1(int b){
    printf("b=%d\n",b+5);
    return 0;
}

int main(int argc,char* argv[]){
    int (*f)(int);
    // 在 C++ 中這就是多態。
    // 對上層來說,調用的都是 f 這個函數指針,但在底層返回的是不一樣的結果。
    f=func;
    f(2);
    f=func1;
    f(3);
    // 打印結果;a=2 b=8
    return 0;
}
複製代碼

文件操做

文件類型:FILE* file; (FILE* 在 Linux 下叫指針,在 Windows 下叫句柄。)

打開文件:FILE* fopen(path,mode);

關閉文件:fclose(FILE*);

#include <stdio.h>

void createfile(char* filename){
    // open/create file
    FILE* file = fopen(filename,"w");
    if (!file) {
        printf("Failed to create file (%s)\n",filename);
        return;
    }
    
    // 向建立好的文件內寫入內容。
    // 參數一指寫入的字符串,參數二指字符串中的每一項多大,參數三指一共有幾項,參數四指寫到哪一個文件
    size_t len = fwrite("aaaaa", 1, 5, file);
    if (len !=5) {
        // size_t 使用的打印爲 %zu。
        printf("Failed to write file,(%zu)",len);
        fclose(file);
        return;
    }
    
    printf("Successed to write file\n");
    fclose(file);
    printf("Successed to create file\n");
}

void read_data(char* filename){
    FILE* file = fopen(filename,"r");
    if (!file) {
        printf("Failed to create file (%s)\n",filename);
        return;
    }
    // 定義爲 1k 大小,並初始化爲 0。
    char buffer[1024] = {0,};
    // 參數:讀出的數據存放位置,長度,讀多少,從哪讀。
    size_t len = fread(buffer, 1, 10, file);
    if (len <= 0) {
        printf("Failed to read file!\n");
        fclose(file);
        return;
    }
    printf("read_data:%s\n",buffer);
    fclose(file);
    return;
}


int main(int argc,char* argv[]){
    // create file
// createfile("/Users/jianghouren/Downloads/1.txt");
    // read file
    read_data("/Users/jianghouren/Downloads/1.txt");
    return 0;
}
複製代碼

備註

參考資料:

慕課網-音視頻基礎(李超)

歡迎關注微信公衆號:非也緣也

相關文章
相關標籤/搜索