天天看點

C語言 | 基礎知識點筆記

學習時間:8天;

學習範圍:《The C Programming Language》/Fishc工作室視訊/《C語言經典程式設計282例》;

函數

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

//參數傳值調用

在C語言中,被調函數不能直接修改主調函數中變量的值,而隻能修改函數私有的臨時副本的值

必要時,也能夠修改主調函數中的變量。需要向被調用函數提供待設定值的變量的位址(指針)。被調用函數則需要将對應的參數聲明為指針類型,并通過它間接通路變量。

如果是數組參數,當把數組名用作參數時,傳遞給函數的值是數組起始元素的位置或位址,并不複制數組元素的本身。在被調函數中,可以通過數組下标通路或修改數組元素的值。

C語言 | 基礎知識點筆記

————————————————————————————————————————————

變量

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

自動變量(局部變量) //在一個函數開頭或段開頭處說明的變量

作用域:

僅在定義它的函數内;

初始化:

不自動賦初值,使用前需要指派;

值的保持:

随函數的引用而存在和消失,不保持值;

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

外部變量(全程變量) //在函數外部定義的變量

優勢:解決函數單獨編譯的協調;與變量初始化有關;外部變量的值是永久的;解決資料共享;

作用域:整個程式;

初始化:0;

值的保持:永久保持

特點:

  1. c程式可以分别放在幾個檔案上,每個檔案可以作為一個編譯機關分别進行編譯。外部變量隻需在某個檔案上定義一次,其它檔案若要引用此變量時,應用extern加以說明(外部變量定義時不必加extern關鍵字)
  2. 在同一檔案中,若前面的函數要引用後面定義的外部(在函數之外)變量時,在函數裡加extern加以說明。

舉例:

C語言 | 基礎知識點筆記

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

靜态變量 - 内部 //在局部變量前加上static

作用域:僅在定義它的函數内;

初始化:0;

值的保持:當函數執行完,傳回調用點時,該變量并不撤銷,再次調用時,其值将繼續存在;

特點:采用靜态存貯配置設定(由編譯程式在編譯時配置設定,而一般的自動變量和函數形參均采用動态存貯配置設定,即在運作時配置設定空間);

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

靜态變量 - 外部 //在函數外部定義的變量前加static

優勢:可以實作資料隐藏

作用域:定義它的檔案(該檔案的私有變量),其他檔案上的函數不允許通路;

初始化:0;

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

寄存器變量 //隻有自動(局部)變量和函數參數才能進一步指定為寄存器存貯類

特點:

  1. 使用register變量可以提高存取速度,但寄存器變量的數目依賴于具體機器,聲明多了也隻有前幾個有效。
  2. 隻限于int,char,short ,unsigned和指針類型用寄存類。
  3. 不能對register變量取位址(即&操作)

————————————————————————————————————————————

常量

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

enum 枚舉常量

不同枚舉中的名字必須互不相同,同一枚舉中不同的名字可以是用相同的值;相對#define來說,優勢在于常量值可以自動生成

舉例:

  1. enum week {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY};

    /*

    week是新的資料類型,源于int,此時:

    MONDAY = 0

    TUESDAY = 1

    WEDNESDAY = 2

    THURSDAY = 3

    FRIDAY = 4

    SATURDAY = 5

    SUNDAY = 6

    */

  2. enum week {MONDAY = 1, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY};

    /*

    MONDAY = 1

    TUESDAY = 2

    WEDNESDAY = 3

    THURSDAY = 4

    FRIDAY = 5

    SATURDAY = 6

    SUNDAY = 7

    */

  3. enum escapes {BELL = \'\a\', BACKSPACE = \'\b\', TAB = \'\t\', NEWLINE = \'n\', VTAB = \'\v\', RETURN = \'\r\'};

    /*

    BELL = \'\a\',

    BACKSPACE = \'\b\',

    TAB = \'\t\',

    NEWLINE = \'n\',

    VTAB = \'\v\',

    RETURN = \'\r\'

    */

————————————————————————————————————————————

關鍵字

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

const //限定符,通過 const 對變量進行限定後,無法修改其值,數組同理。

C語言 | 基礎知識點筆記

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

register //請求編譯器盡可能的将變量存在CPU内部寄存器中,而不是通過記憶體尋址通路,以提高效率。

  1. register變量必須是能被CPU所接受的類型。這通常意味着register變量必須是一個單個的值,并且長度應該小于或者等于整型的長度。
  2. 不能通過 & 來取位址

————————————————————————————————————————————

數組

注意:數組名即數組的第一個元素的位址,是以使用scanf函數的時候可以不使用 &

// 調用數組a[i]的值時也可以寫成 *(a+i) 的形式,編譯的過程實際上先将其轉換成 *(a+i) 再求值。是以 a[i] 與 *(a+i) 是等價的,一個通過數組和下表實作的表達式可以通過指針可偏移量實作。注意:指針是一個變量, p=a或p++是合法的,但數組名不是變量,不可以執行上面的操作。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

字元數組 //scanf在讀取字元串的時候不使用取址操作符 &,同指針

char str[1000];

scanf("%s",str);

————————————————————————————————————————————

指針

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

位址運算符 & 隻能應用于記憶體中的對象(變量與數組元素)。它不能作用于表達式/常量/register類型的變量。

取值運算符 * ,在定義指針時表示定義的是個變量,在其他地方表示取指針變量的那個值

指針隻能指向某種特定類型的對象(例外情況:指向void類型的指針可以存放指向任何類型的指針,但它不能間接引用其自身)。

定義:

int a;

int *p;

p = &a;

scanf("%d",p);

printf("%d\n",*p);

//指向數組的普通指針(非數組指針)

#include <stdio.h>

int main(int argc, char const *argv[])

{

//char

char *p;//定義一個字元指針

char str[1000];//定義一個字元數組

scanf("%s", str);//字元數組輸入

p = str; //p指針指向str首位址

printf("%c %c\n", *p, *(p + 1)); //列印首位址的值與第二個位址的值

//int

int a[5] = {1, 2, 3, 4, 5};

int *q;

q = a;

//或寫成 int *q = a;

printf("%d %d\n", *q, *(q + 1));

return 0;

}

//指向指針的指針

定義:

#include <stdio.h>

int main(int argc, char const *argv[])

{

int num = 520;

int *p = &num;

int **pp = &p;//pp為指向指針的指針

return 0;

}

num 520 //int num中存放的值是520
p &num //指針p中存放的是num的位址
*p num 520 //對指針p解引用得到&num存放的值 == 520
pp &p //pp作為指向指針p的指針,存放的是p的位址
*pp p &num //pp解引用得到的是 p == &num
**pp *p num 520 //對pp二層解引用得到的是 *p == num ==520

舉例:

#include <stdio.h>

int main(int argc, char const *argv[])

{

char *str[] = {"aaa", "bbb", "ccc", "ddd", "eee", "fff"};

//定義這個指針數組,此時指針數組存放的都是指針,字元串是指向字元的指針,數組每個元素都是指針,數組又可以用指針的方式來通路,是以我們可以用指向指針的指針來通路指針數組;

char **p;//定義指針p為指向指針的指針

char **str2[4];//str2數組中存放了4個指向指針的指針

p = &str[5];//p指向"fff",取址得到字元串"fff"的位址,此時p的一個指向字元指針的指針

str2[0] = &str[0];//str2數組中的指向指針的指針分别指向str數組中的指針

str2[1] = &str[1];

str2[2] = &str[2];

str2[3] = &str[3];

printf("%s\n", *p);

for (int i = 0; i < 4; ++i)

{

printf("%s\n", *str2[i]);

}

return 0;

}

//指向常量的指針 (指針本身可以被修改)

//const int *p可以指向const int 和int,但都不可以通過*p指派

#include <stdio.h>

int main(int argc, char const *argv[])

{

int num = 520;

const int cnum = 820;

const int *p = &cnum;

printf("%d %d\n", &cnum, cnum);

printf("%d %d\n", p, *p);

p = &num;

//*p=1024; 此條無法通過編譯,*p read-only

num = 1024;

return 0;

}

//常量指針 (指針本身不可以被修改)

//int * const p定義了指向之後,無法指向其他量

//指向非常量的常量指針:指向的值可以被修改

//指向常量的常量指針:指向的值不可以被修改

//cmd下無法被編譯,unix和codeblocks可以編譯

#include <stdio.h>

int main(int argc, char const *argv[])

{

int num = 520;

const int cnum = 820;

int *const p =&cnum;

*p = 1024;

printf("%d\n", *p );

//p=&cnum; 常量指針指向num後,不可以修改指向

return 0;

}

//指向"指向常量的常量指針"的指針

#include <stdio.h>

int main(int argc, char const *argv[])

{

int num = 520;

const int cnum = 820;

const int *const p = &cnum;//定義一個指向常量的常量指針

const int *const *pp = &p;//定義一個指向"指向常量的常量指針"的指針

printf("%p %p\n", pp, &p);//列印p的位址,pp和&p相同

printf("%p %p %p\n", *pp, p, &cnum);//列印num的位址,*pp和p和&num相同

printf("%d %d %d\n", **pp, *p, cnum);//列印三者的值,820

return 0;

}

//參數指針

文法:double atof(char *);

/* atof的參數時一個指向char類型的指針*/

//void指針

将任意類型的指針可以轉換成為void指針;

但是void指針轉化為其他類型需要使用強制轉換;

#include <stdio.h>

int main(int argc, char const *argv[])

{

int num = 1234;

int *pi = &num;

char *ps = "abcd";

void *pv;

pv = pi; //pv變成指向整型的指針;

printf("%p %p\n", pi, pv); //兩個指針分别的位址;

//printf("%d\n", *pv);//嘗試解引用一個void指針,不知道void類型的寬度,編譯器無法直接完成

printf("%d\n", *(int *)pv); //将pv強制轉換成為int類型的指針,并解引用

pv = ps;

printf("%p %p\n", ps, pv);

//printf("%s\n", pv);//字元串隻需要指向首字元的位址就可以了,但是這樣寫是不規範的

printf("%s\n",(char *)pv);

return 0;

}

//NULL指針 //空指針,#define NULL ((void *)0) 指針指向0

#include <stdio.h>

int main(int argc, char const *argv[])

{

int *p1; //p1成為迷途指針,懸空指針,即沒有指定的指針

int *p2 = NULL;

printf("%p %p\n", p1, p2);//p1位址随機,p2位址 00000000

printf("%d %d\n", *p1, *p2); //unix下編譯得到 *p1的值是随機的,*p2傳回segmentation fault,因為對NULL指針解引用是非法的,程式崩潰報錯

return 0;

}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

指針運算

// *ip自增

文法:

  1. *ip += 1;
  2. ++*ip;
  3. (*ip)++;

//指針間指派

文法: iq = ip;

/* 如果iq和ip同樣是指向整型的指針,則将ip中的值copy到iq中,iq也将指向ip所指向的對象 */

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

指針傳遞

文法:

swap(a,b);

void swap(int *p,int *q)

特點:

  1. 調用方法傳參,僅改變指針p的位址 &p ;
  2. *p=12指派,僅改變記憶體塊的值 *p ;
  3. p=&a指向變量a,僅改變記憶體塊位置 p ;
  4. 調用方法結束,p的位址和記憶體塊都不變,但如果在調用過程中記憶體塊被修改,則值改變 ;

舉例:

#include <stdio.h>

void pointer(int *p)

{

printf("\nthe p is %p , addr is %d, *p is %d", p , &p, *p);

//Line 2 指針p傳入方法pointer中:在新的方法中生成了一個p的拷貝p1,新的位址 6356752,但值和指向的記憶體塊資料沒變

*p = 12;

printf("\nthe p is %p , addr is %d, *p is %d", p , &p, *p);

//Line 3 p1改變了其所指向的記憶體塊的值為12,記憶體塊 00F0FF2C 的值變成了22

int a = 11;

p = &a;

printf("\nthe p is %p , addr is %d, *p is %d", p , &p, *p);

//Line 4 p1的值指向a,即p1指向a 記憶體塊 0060FEFC,此時p1與p分别指向不同的記憶體塊了,不會互相影響

}

int main()

{

int b = 22;

int *p = &b;

printf("\nthe p is %p , addr is %d, *p is %d", p , &p, *p);

//Line 1 *p指向b的位址:獲得了p(記憶體塊資料)&p(位址)*p(值)

pointer(p);

printf("\nthe p is %p , addr is %d, *p is %d", p , &p, *p);

//Line 5 方法結束,調用方法結束後,p位址仍是調用前的位址,位址和值沒變(改變的僅僅是p的拷貝p1),但是p所指向的記憶體塊資料被p1所改變了,故*p為12

}

輸出:

C語言 | 基礎知識點筆記

其他傳遞方式(來源參考他人)

  1. 傳值方式 //和函數的值傳遞不是一個概念

    文法:

    swap(&a , &b);

    void swap(int *a , int *b)

    // 傳入的是變量a的位址 &a,函數接收到的是傳入位址的值

    // 使用指針方式修改指向記憶體塊的值,傳入的是 a、b變量位址的拷貝。

    注意:函數的值傳遞的方式是

    swap(a , b);

    void swap(int a , int b)

  2. 傳引用方式

    文法:

    swap(a,b);

    void swap(int &p,int &q)

    // 使用引用方式,傳入的是變量a、b,而不是拷貝,位址不變。

舉例:

#include <stdio.h>

void swap(int *a , int *b)

//方法一:傳值方式

{

printf("\n\n /*** Method 1 ***/");

printf("\n &a addr : %d , &b addr: %d", &a, &b);

printf("\n a memory : %d , b memory: %d", a, b);

printf("\n *a : %d , *b : %d", *a, *b);

int temp = *a;

*a = *b;

*b = temp;

}

void swap(int &a , int &b)

//方法二:傳引用方式

{

printf("\n\n /*** Method 2 ***/");

printf("\n &a addr : %d , &b addr: %d", &a , &b);

int temp = a;

a = b;

b = temp;

}

int main(int argc, char const *argv[])

{

int a = 3 , b = 5;

printf(" &a addr : %d , &b addr: %d", &a , &b);

printf("\n a : %d , b : %d", a , b);

swap(&a , &b); //方法一

printf("\n &a addr : %d , &b addr: %d", &a, &b);

printf("\n a : %d , b : %d", a , b);

swap(a , b); //方法二

printf("\n a : %d , b : %d\n", a , b);

return 0;

}

輸出:

C語言 | 基礎知識點筆記

————————————————————————————————————————————

數組指針和指針數組

注意:指派符号"="号兩邊的資料類型必須是相同的,通過這點可以排除在寫數組與指針時的錯誤;

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

數組指針 //指向數組的指針

注意:不同的資料類型占的位址數(位元組)不同,char:1,int:4,float:4,double:8

定義:

//一維

#include <stdio.h>

int main(int argc, char const *argv[])

{

//int,char同理

int temp[5] = {1, 2, 3, 4, 5};

int (*p)[5] = &temp;//指針p指向temp數組的首位址

int i;

for (i = 0; i < 5; ++i)

{

printf("%d ", *(*p + i));

//*p指向temp數組的首位址,*p+i代表後移幾個位元組的位址,*(*p+i)代表指向位址的值

}

return 0;

}

//二維,行指針

#include <stdio.h>

int main(int argc, char const *argv[])

{

int array[4][5] = {{1, 2, 3, 4, 5}, {11, 12, 13, 14, 15}, {21, 22, 23, 24, 25}, {31, 32, 33, 34, 35}, {41, 42, 43, 44, 45}};

int (*p)[5];//該語句是定義一個數組指針,指向含4個元素的一維數組。或直接寫成 int (*p)[5] = array;

p = array;//将該二維數組的首位址賦給p,也就是a[0]或&a[0][0]

//在這裡,數組指針p共有三個int指針,指派時意味着将p的三個指針指向 array第一行的三個元素;

for (int i = 0; i < 4; ++i)

{

for (int j = 0; j < 5; ++j)

{

printf("%2d ", *(*(p + i) + j));

}

printf("\n");

}

return 0;

}

另一種表達方式:

...

int (*p)[4][5]=&array;

...

printf("%2d ", *(*(*p + i) + j));

...

//都表示數組中i行j列一個元素

*(p+i) == p[i]

*(*(p+i)+j) == p[i][j] == *(p[i]+j) == (*(p+i))[j]

*(*(*(p+i)+j)) == p[i][j][k]

p++;//該語句執行過後,也就是p=p+1;p跨過行a[0][]指向了行a[1][]

C語言 | 基礎知識點筆記

大小:在32位系統下永遠是4位元組

例1:

#include <stdio.h>

int main(int argc, char const *argv[])

{

int a[10];

int *p, i;

for (i = 0; i < 10; ++i)

{

scanf("%d", &a[i]);

}

for (p = &a[0]; p < (a + 10); p++)

//p+i = a+i = &a[i] 這三者意思相同,是以循環結構使用 p < (a + 10),等價于 i < 10

{

printf("%d ", *p);

}

return 0;

}

例2:

#include <stdio.h>

int main()

{

//數組指針的大小必須與數組相同,否則編譯不通過,此處均為[5]

char a[5] = {\'a\', \'b\', \'c\', \'d\'};

//p1 和p2 都是數組指針,指向的是整個數組

//&a 是整個數組的首位址,a是數組首元素的首位址

char (*p1)[5] = &a;

//p1指向&a是對的,左右都是整個數組的首位址

char (*p2)[5] = a;

//p2指向a,編譯時會出現warming,但是"="兩邊的資料類型不一緻,左邊的是指向整個數組的指針,右邊的資料類型是指向單個字元的指針。

char (*p3)[5] = (char (*)[5])a;

//p2類型如果要正常使用的話則使用p3這種強制轉換,右邊強制轉換成為a整個數組的首位址

printf("a=%d\n", a);

printf("a=%c\n", a[0]);

printf("&a=%d\n", &a);

printf("p1=%c\n", **p1);

printf("p2=%c\n", **p2);

printf("p3=%c\n", **p3);

printf("p1+1=%c\n", **(p1 + 1));

printf("p2+1=%c\n", **(p2 + 1));

printf("p3+1=%c\n", **(p3 + 1));

return 0;

}

輸出:

出現的warming資訊為p2導緻,左右類型不一緻

C語言 | 基礎知識點筆記

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

指針數組 //用于存儲指針的數組

定義:

//一維

#include <stdio.h>

int main(int argc, char const *argv[])

{

//int

int a = 1;

int b = 2;

int c = 3;

int d = 4;

int e = 5;

int *p[5] = {&a, &b, &c, &d, &e};//數組裡面每一個元素都指向abcde的位址

for (int i = 0; i < 5; ++i)

{

printf("%d ", *p[i]);//循環列印每一個指針對應位址的值 *

}

//char

char *q[5] = {"aaa", "bbb", "ccc", "ddd", "eee"};

for (int j = 0; j < 5; ++j)

{

printf("%c ", *q[j]); //加*表示取出的是字元

}

for (int k = 0; k < 5; ++k)

{

printf("\n%s", q[k]);//不加*表示字元串

}

return 0;

}

//二維

int *p[3]; //定義的p數組中的三個元素都是int指針,分别是p[0]、p[1]、p[2],是以要分别指派。

int a[3][4];

p++; //該語句表示p數組指向下一個數組元素。注:此數組每一個元素都是一個指針

for(i=0;i<3;i++)

p[i]=a[i];

//都表示數組中i行j列一個元素

*(p+i) == p[i]

*(*(p+i)+j) == p[i][j] == *(p[i]+j) == (*(p+i))[j]

*(*(*(p+i)+j)) == p[i][j][k]

指派:*p=a; //這裡*p表示指針數組第一個元素的值,a的首位址的值。

大小:數組的大小由數組本身來決定,32位系統下每個指針占4位元組,大小不确定;

舉例:

#include <stdio.h>

int main()

{

int i;

char c1[] = "How";

char c2[] = "are";

char *c3 = "you"; //該指針變量指向字元串所在字元數組的首位址。

char *pArray[3]; //該數組元素可以指向char類型或數組類型

pArray[0] = c1; //指針變量pArray[0]指向了c1的首位址

pArray[1] = c2;

pArray[2] = c3;

for(i = 0; i < 3; i++)

printf("%s ", pArray[i]); //printf("%s ", pArray[0])等價于printf("%s ", c1)

return 0;

}

輸出:

C語言 | 基礎知識點筆記
C語言 | 基礎知識點筆記

出處: http://www.cnblogs.com/hongcha717/archive/2010/10/24/1859780.html

出處: http://www.cnblogs.com/mq0036/p/3382732.html

————————————————————————————————————————————

結構體

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

編譯器會将結構體的資料進行記憶體對其,如果定義 char a;int b;char c;

對其前:6個位元組

a b b b b c

對其後:12個位元組

a b b b b c

如果定義的是 char a;char c;int b;

則調整為

a c b b b b

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

定義

#include <stdio.h>

//第一種定義方法

struct Book //定義結構體名

{

char title[128];

char author[40];

float price;

unsigned int date;//無符号整型

char publisher[40];

} book;//book是結構體變量名

//第二種定義方法

struct Book2

{

float price2;

unsigned int date2;

} book2;

//第三種定義方法

struct Book3

{

int number;

int number2;

} book3 = {1, 2};

//結構體嵌套

struct Data

{

int year;

int month;

int day;

};

struct Nested

{

struct Data data;

char a;

} nested =

{

{2017, 4, 17},

\'i\'

};

int main(void)

{

//第一種初始化方法

struct Book book =//初始化結構體

{

"aaa",

"bbb",

12.0,

20170417,

"ccc"

};

//第二種初始化方法

struct Book2 book2 =//通過這種寫法隻初始化某一個變量

{

.price2 = 48.0

};

//scanf("%s",book.title);

//scanf("%s",book.author);

//...

printf("%s\n", book.title);

printf("%s\n", book.author);

printf("%f\n", book.price);

printf("%d\n", book.date);

printf("%s\n", book.publisher);

printf("- - - - - - - - \n");

printf("%f\n", book2.price2);

//...

printf("- - - - - - - - \n");

//結構體嵌套列印

printf("%d %d %d\n", nested.data.year, nested.data.month, nested.data.day);

return 0;

}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

結構體數組

#include <stdio.h>

//第一種定義方法

struct Way1

{

char a;

char b;

int c;

} way1 [3];

//第二種定義方法

struct Way2

{

char d;

char e;

int f;

};

struct Way2 way2 [10];

int main(int argc, char const *argv[])

{

//初始化結構體數組

struct Way1 way1[3] =

{

{\'a\', \'b\', 0},

{\'c\', \'d\', 1},

{\'e\', \'f\', 2}

}

return 0;

}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

結構體指針

#include <stdio.h>

struct Book

{

char title[128];

char author[40];

float price;

unsigned int date;

char publisher[40];

} book =

{

"aaa",

"bbb",

12.0,

20170417,

"ccc"

};

int main(void)

{

struct Book *pt;

pt = & book;//結構體的變量名并不是指向結構體的位址,定義結構體指針時必須使用 &

//第一種方法

printf("%s\n", (*pt).title);

printf("%s\n", (*pt).author);

printf("%f\n", (*pt).price);

printf("%d\n", (*pt).date);

printf("%s\n", (*pt).publisher);

printf("- - - - - - - - - - -\n");

//第二種方法

printf("%s\n", pt->title);

printf("%s\n", pt->author);

printf("%f\n", pt->price);

printf("%d\n", pt->date);

printf("%s\n", pt->publisher);

return 0;

}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

傳遞結構體變量

#include <stdio.h>

struct Date

{

int year;

int month;

int day;

};

struct Book

{

char title[128];

float price;

struct Date date;

};

struct Book getInput(struct Book book);

struct Book getInput(struct Book book)

{

printf("input the title:");

scanf("%s", book.title);

printf("input the price:");

scanf("%f", &book.price);

printf("input the date:");

scanf("%d %d %d", &book.date.year, &book.date.month, &book.date.day);

return book;

}

struct Book printBook(struct Book book);

struct Book printBook(struct Book book)

{

printf("%s\n", book.title);

printf("%f\n", book.price);

printf("%d-%d-%d", book.date.year, book.date.month, book.date.day);

}

int main()

{

struct Book b1, b2;

printf("input the first info\n");

b1 = getInput(b1);

printBook(b1);

return 0;

}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

傳遞指向結構體變量的指針 //基本結構同上

#include <stdio.h>

struct Date

{

int year;

int month;

int day;

};

struct Book

{

char title[128];

float price;

struct Date date;

};

void getInput(struct Book *book);

void getInput(struct Book *book)//不需要傳回值,直接定義成為void即可

{

printf("input the title:");

scanf("%s", book->title);

printf("input the price:");

scanf("%f", &book->price);

printf("input the date:");

scanf("%d %d %d", &book->date.year, &book->date.month, &book->date.day);

}

void printBook(struct Book *book);

void printBook(struct Book *book)

{

printf("%s\n", book->title);

printf("%f\n", book->price);

printf("%d-%d-%d", book->date.year, book->date.month, book->date.day);

//void類型沒有傳回值 return

}

int main(void)

{

struct Book b1, b2;

printf("input the first info\n");

getInput(&b1);//調用時直接取位址

printBook(&b1);

return 0;

}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

動态申請結構體

//使用malloc函數為結構體配置設定存儲空間,free函數釋放

#include <stdio.h>

#include <stdlib.h>

struct Date

{

int year;

int month;

int day;

};

struct Book

{

char title[128];

float price;

struct Date date;

};

void getInput(struct Book *book);

void getInput(struct Book *book)//不需要傳回值,直接定義成為void即可

{

printf("input the title:");

scanf("%s", book->title);

printf("input the price:");

scanf("%f", &book->price);

printf("input the date:");

scanf("%d %d %d", &book->date.year, &book->date.month, &book->date.day);

}

void printBook(struct Book *book);

void printBook(struct Book *book)

{

printf("%s\n", book->title);

printf("%f\n", book->price);

printf("%d-%d-%d", book->date.year, book->date.month, book->date.day);

}

int main(void)

{

struct Book *b1, *b2;

b1 = (struct Book *)malloc(sizeof(struct Book));

if (b1 == NULL)

{

printf("記憶體配置設定失敗\n");

exit(1);

}

printf("input the first info\n");

getInput(b1);//因為b1是指針,是以不需要取位址操作符

printBook(b1);

free(b1);

return 0;

}

————————————————————————————————————————————

預處理器

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

檔案包含 #include "檔案名" 或 #include <檔案名>

  1. 用" "引起來,則在源檔案所在的位置查找該檔案;
  2. 如果在該位置沒有找到檔案或用< >括起來的,則根據相應的規則查找該檔案,這個規則同具體的實作有關

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

兩個預處理語句 #ifdef 和 #ifndef

用法:

#ifndef HDR

#define HDR

/* hdr.h檔案的内容在這裡*/

#endif

/* 用來測試某個名字是否已經定義,等價于 */

#if !defined(HDR)

#define HDR

#endif

舉例:

/* 測試SYSTEM變量後确定包含某個檔案 */

#if SYSTEM == SYSV

#define HDR "sysv.h"

#elif SYSTEM == BSD

#define HDR "bsd.h"

#elif SYSTEM == MSDOS

#define HDR "msdos.h"

#else

#define HDR "default.h"

#endif

#include HDR

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

宏替換

  1. #define 名字替換文本

    用法:較長的替換文本可以在待續的行末尾加上反斜杠符 \

    舉例:

    1. 例:#define forever for(;;)

      /* 該句為無限循環定義了一個新名字forever */

    2. 例:#define max(A,B) ((A)>(B)?(A):(B))

      /* 形參A和B每次出現都将被替換成對應的實際參數,不過要适當使用括号來規範計算次序的正确性 */

    3. 例:#define dprint(expr) printf(#expr " = %g\n",expr)

      /* 當使用時dprintf(x/y);時被擴充為 printf("x/y" "= %g\n",x/y); */

    4. 例:#define paste(front,back) front ## back

      /*預處理器運算符## 為宏定義提供了連接配接實際參數的手段*/

      /* 在調用paste(name,1)時,将建立記好 name1*/

  2. #undef getchar

    int getchar(void){...}

    用法:通過#undef 取消名字的宏定義,這樣可以保證後續的調用是函數調用,而不是宏調用

————————————————————————————————————————————

getchar /putchar 輸入輸出

文法:

c = getchar(); // 擷取控制台輸入

putchar(c); //輸出

————————————————————————————————————————————

EOF,End Of File,檔案尾标志。 從數值上來看,就是整數-1

linux:在輸入回車換行後的空行位置,按 ctrl+d (先按ctrl鍵,不放,再按d鍵)

windows:在輸入回車換行後的空行位置,按 ctrl+z,再回車确認

————————————————————————————————————————————