重學C語言_資料結構與基礎語法

夏2同學發表於2020-11-11

c語言標準

2011年12月8日,國際標準化組織(ISO)和國際電工委員會(IEC) 旗下的C語言標準委員會(ISO/IEC JTC1/SC22/WG14)正式釋出了C11標準。

C11標準是C語言標準的第三版,前一個標準版本是C99標準。

目前程式設計學習使用最多的標準是C99,它是1999年釋出的。

環境安裝

要想執行C語言程式,電腦裡面必須得有GCC,也就是C語言的編譯器。

  • 驗證有沒有gcc
  • cmd裡面敲gcc -v

如果有GCC

Windows 上的安裝

為了在 Windows 上安裝 GCC,您需要安裝 MinGW。為了安裝 MinGW,請訪問 MinGW 的主頁 www.mingw.org,進入 MinGW 下載頁面,下載最新版本的 MinGW 安裝程式,命名格式為 MinGW-.exe。

  1. 訪問官網
http://www.mingw.org/
  1. 點選download

  2. 點選logo

image-20201111083930032

  1. 點選logo進行下載

image-20201111084748211

  1. 新增到環境變數

image-20201111084918410

當然,你也可以使用IDE裡面自帶的編譯器,一般codeblocks等編輯器都自帶MinGW。

Hello world!

#include <stdio.h> 
int main()
{
   /* 我的第一個 C 程式  檔名 hello.c */
   printf("Hello, World! \n");
   return 0;
}

編譯執行這一段程式碼。

gcc hello.c

它會自動生成一個a.exe檔案 (LINUX平臺為 a.out)

通過 ./a.exe 就可以執行。

註釋

// 單行註釋
/*
 * 多行註釋
 */

識別符號

用來標識變數、函式。

  • 由字母、數字、下劃線組成
  • 數字不能打頭陣
  • 不能出現特殊符號($、@ 不能出現)
  • 區分大小寫

C資料型別

整數型別

char、int、short、long、long long都是整數型別

他們都可以有unsigned的字首。(unsigned 無符號)

char 的值範圍 -128到127 (-128的二進位制 10000000)

unsigned char 的值範圍是 0 到 255

浮點數型別

double 和 float

定義常量

在 C 中,有兩種簡單的定義常量的方式:

  1. 使用 #define 前處理器。
  2. 使用 const 關鍵字。
#define identifier value
or
const type variable = value;
// const int 

C語言修飾符

auto

所有區域性變數的預設值

{
    int variable;
	等價於
	auto int variable;
}

static

可以修飾區域性變數 和 全域性變數。

c 語言中,把變數定義在 大括號外面就是全域性變數。

static int count = 10;
等價於
int count = 10;

void main(){
	// do something
}

extern

extern 儲存類用於提供一個全域性變數的引用,全域性變數對所有的程式檔案都是可見的。當您使用 extern 時,對於無法初始化的變數,會把變數名指向一個之前定義過的儲存位置。

詳細見菜鳥教程

c - if 判斷

定義:C 語言把任何非零非空的值假定為 true,把null 假定為 false

image-20201111100240179

C - 迴圈

  • 有while,for,do while迴圈

  • break 結束迴圈

  • continue 停止本次迴圈,執行下一步

C - 函式

語法:

return_type function_name( parameter list )
{
   body of the function
}
  • **返回型別:**一個函式可以返回一個值。return_type 是函式返回的值的資料型別。有些函式執行所需的操作而不返回值,在這種情況下,return_type 是關鍵字 void
  • **函式名稱:**這是函式的實際名稱。函式名和引數列表一起構成了函式簽名。
  • **引數:**引數就像是佔位符。當函式被呼叫時,您向引數傳遞一個值,這個值被稱為實際引數。引數列表包括函式引數的型別、順序、數量。引數是可選的,也就是說,函式可能不包含引數。
  • **函式主體:**函式主體包含一組定義函式執行任務的語句。

函式引數

如果函式要使用引數,則必須宣告接受引數值的變數。這些變數稱為函式的形式引數

形式引數就像函式內的其他區域性變數,在進入函式時被建立,退出函式時被銷燬。

函式引數:

  • 傳值 (不會修改原來的值)
  • 傳地址

函式宣告:

  • 如果呼叫外部函式,必須得提前宣告
  • 如果main在呼叫的函式前面,必須得提前宣告

函式的形參名不重要,所以函式宣告時可以忽略。

#include <stdio.h>
#include <stdlib.h>
int sum(int,int);
// int sum(int a,int b);  // 這兩種都可以

int main()
{
    int x=3,y=5;
    printf("%d",sum(x,y));
    return 0;
}

int sum(int a,int b){
    return a+b;
}

當形參和全域性變數同名的時候,形參的值在函式體內部會覆蓋掉全域性變數。

傳遞陣列給函式作為引數

方式 1

形式引數是一個指標:

void myFunction(int *param) { . . . }

方式 2

形式引數是一個已定義大小的陣列:

void myFunction(int param[10]) { . . . }

方式 3

形式引數是一個未定義大小的陣列:

void myFunction(int param[]) { . . . }

建議採用方式1或者3

陣列作為函式的返回值

C 語言不允許返回一個完整的陣列作為函式的引數。

但是,您可以通過指定不帶索引的陣列名來返回一個指向陣列的指標。

// int[] getArr() //這種語法是錯誤的

int * getArr( )
{
  static int  r[10] = {1,2,3};;  // 必須使用static來修飾,否則報錯
  return r;
}

初始化區域性變數和全域性變數

當區域性變數被定義時,系統不會對其初始化,您必須自行對其初始化。定義全域性變數時,系統會自動對其初始化,如下所示:

資料型別初始化預設值
int0
char‘\0’
float0
double0
pointerNULL

正確地初始化變數是一個良好的程式設計習慣,否則有時候程式可能會產生意想不到的結果,因為未初始化的變數會導致一些在記憶體位置中已經可用的垃圾值。

作用域

  • 全域性變數
  • 區域性變數
  • 形式引數

c語言中是塊級作用域,即變數只服務於大括號內部。

{
    int a; // 外面訪問不到這個
}

函式體定義的形參等價於函式體內部定義的區域性變數。

void func(int x){
    // 等價於函式體裡面寫 int x;
}

當區域性變數和全域性變數重名的時候,優先獲取的是區域性變數的值。

C - 陣列

定義: 陣列是用來儲存一系列資料,它是一系列相同型別的變數。

語法:type arrayName [ arraySize ];

初始化陣列

在 C 中,您可以逐個初始化陣列,也可以使用一個初始化語句,如下所示:

double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};

大括號 { } 之間的值的數目不能大於我們在陣列宣告時在方括號 [ ] 中指定的元素數目。

如果您省略掉了陣列的大小,陣列的大小則為初始化時元素的個數。因此,如果:

double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};

如果您只賦值,其中一部分,那麼剩餘的值將採用預設值。

int arr[5] = {1,2,3}; // [1,2,3,0,0] int的預設值是0

獲取陣列的Length

int arr[5] = {1,2,3};
int len = sizeof(arr) / sizeof(arr[0]);  // 5

使用size運算子通過計算就可以獲得陣列的長度,但是這還是很不方便。

可以進一步使用巨集定義。

#define GET_ARRAY_LEN(array,len) {len = (sizeof(array) / sizeof(array[0]));} 
int main (){
    int arr[5] = {1,2,3};
    int len;
    GET_ARRAY_LEN(arr,len); // 此時len = 5
}

千萬不要把sizeof(arr) / sizeof(arr[0])封裝到函式裡面,你獲取的長度將永遠是1。

深坑,請勿踩雷!~

二維陣列

多維陣列最簡單的形式是二維陣列。一個二維陣列,在本質上,是一個一維陣列的列表。宣告一個 x 行 y 列的二維整型陣列,形式如下:

type arrayName [ x ][ y ];

其中,type 可以是任意有效的 C 資料型別,arrayName 是一個有效的 C 識別符號。一個二維陣列可以被認為是一個帶有 x 行和 y 列的表格。下面是一個二維陣列,包含 3 行和 4 列:

int x[3][4];

C 中的二維陣列

因此,陣列中的每個元素是使用形式為 a[ i , j ] 的元素名稱來標識的,其中 a 是陣列名稱,i 和 j 是唯一標識 a 中每個元素的下標。

初始化二維陣列

多維陣列可以通過在括號內為每行指定值來進行初始化。下面是一個帶有 3 行 4 列的陣列。

int a[3][4] = {  
 {0, 1, 2, 3} ,   /*  初始化索引號為 0 的行 */
 {4, 5, 6, 7} ,   /*  初始化索引號為 1 的行 */
 {8, 9, 10, 11}   /*  初始化索引號為 2 的行 */
};

內部巢狀的括號是可選的,下面的初始化與上面是等同的:

int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};

訪問二維陣列元素

二維陣列中的元素是通過使用下標(即陣列的行索引和列索引)來訪問的。例如:

int val = a[2][3];

C - 列舉

語法:enum 列舉名 {列舉元素1,列舉元素2,……};

enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};

這樣看起來是不是更簡潔了。

**注意:**第一個列舉成員的預設值為整型的 0,後續列舉成員的值在前一個成員上加 1。我們在這個例項中把第一個列舉成員的值定義為 1,第二個就為 2,以此類推。

可以在定義列舉型別時改變列舉元素的值:

enum season {spring, summer=3, autumn, winter};

沒有指定值的列舉元素,其值為前一元素加 1。也就說 spring 的值為 0,summer 的值為 3,autumn 的值為 4,winter 的值為 5

列舉變數的定義 - 例項化

前面我們只是宣告瞭列舉型別,接下來我們看看如何定義列舉變數。

我們可以通過以下三種方式來定義列舉變數

1、先定義列舉型別,再定義列舉變數

enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};
enum DAY day;

2、定義列舉型別的同時定義列舉變數

enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;

3、省略列舉名稱,直接定義列舉變數

enum
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;

C - 指標

定義:指標是一個變數,其值為另一個變數的地址。

語法: type * variable

備註:這個*是宣告指標運算子,不是乘號,更不是對地址取值

#include <stdio.h>
 
int main ()
{
   int  var = 20;   /* 實際變數的宣告 */
   int  *ip;        /* 指標變數的宣告 */
   ip = &var;  /* 在指標變數中儲存 var 的地址 */
   printf("var 變數的地址: %p\n", &var  );
   /* 在指標變數中儲存的地址 */
   printf("ip 變數儲存的地址: %p\n", ip );
   /* 使用指標訪問值 */
   printf("*ip 變數的值: %d\n", *ip );
   return 0;
}

空指標

在變數宣告的時候,如果沒有確切的地址可以賦值,為指標變數賦一個 NULL 值是一個良好的程式設計習慣。

#define NULL 0        // NULL 指標是一個定義在標準庫中的值為零的常量。

例項:

#include <stdio.h>  
int main () {   
    int  *ptr = NULL;    
    printf("ptr 的地址是 %p\n", ptr  );    
    return 0; 
}

當上面的程式碼被編譯和執行時,它會產生下列結果:

ptr 的地址是 0x0

取值和取地址運算子

// * 取值運算子
// & 取地址運算子

int main()
{
    int a = 1;
    int *p;
    p = &a;
    printf("%d",*p); // 1
    return 0;
}

相關文章