天天看點

C語言學習筆記一、變量、函數二、指針三、補充四、C語言執行個體

C語言學習筆記

  • 一、變量、函數
    • 1. typedef
    • 2. size_t
    • 3. enum(枚舉)
  • 二、指針
    • 1. 指針基本概念:*&
    • 2. 函數指針與回調函數
      • 2.1 函數指針作為某個函數的參數
      • 2.2 回調函數·傳值調用函數
      • 2.3 回調函數·引用調用函數
  • 三、補充
    • 1. 字元串
    • 2. 結構體
      • 指向結構的指針
    • 3. 共用體
    • 4. 位域
  • 四、C語言執行個體

一、變量、函數

1. typedef

使用typedef為現有類型建立别名,定義易于記憶的類型名

typedef int size;
void measure(size*psz);
           

typedef 還可以掩飾複合類型,如指針和數組。

例如,你不用像下面這樣重複定義有 81 個字元元素的數組:

char line[81];
char text[81];
           

隻需這樣定義,Line類型即代表了具有81個元素的字元數組,使用方法如下:

typedef char Line[81];
Line text,line;
           

同樣,可以像下面這樣隐藏指針文法:

typedef char* pstr;
int mystrcmp(const pstr p1,const pstr p3);
           

const char*

char* const

表達的并非同一意思,

const char*

的意思是建立一個指向char類型的指針且不能更改指向位址上的值,而

char* const

則是不能更改指向的位址;

char* const p

: 定義一個指向字元的指針常數,即const指針,常量指針。

const char* p

:定義一個指向字元型常量的指針。

2. size_t

了解:無符号整型,作為大小的表示量。int可正可負,隻作為整數。

size_t 的定義在 stddef.h、stdio.h、stdlib.h、string.h、time.h 和 wchar.h 這些标準 C 的頭檔案中,包含以上任一頭檔案,則表明 size_t 将作為一個全局關鍵字。

在 32 位架構中被普遍定義為:

在 64 位架構中被定義為:

從定義可以看出,size_t 是一種無符号的整型(unsigned int、unsigned long、unsigned long long),取值範圍是目标平台下最大的可能範圍。

3. enum(枚舉)

枚舉是 C 語言中的一種基本資料類型,它可以讓資料更簡潔,更易讀。

枚舉文法定義格式為:

菜鳥教程展開>>

二、指針

1. 指針基本概念:*&

筆記:一個指針指向一個數組,用 ptr = &var[0] 與 ptr = var一樣,預設存儲該數組首位位址。

#include <stdio.h>

const int MAX = 3;

int main()
{
    int  var[] = { 10, 100, 200 };
    int  i, * ptr,*pt;

    /* 指針中最後一個元素的位址 */
    ptr = &var[MAX - 1];
    pt = var;
    for (i = 0; i < 2 ; i++)
    {
        pt = pt++;
    }
    for (i = MAX; i > 0; i--)
    {

        printf("存儲位址:var[%d] = %p\n", i - 1, ptr);

        printf("存儲值:var[%d] = %d\n", i - 1, *ptr);
        printf("存儲位址:var[%d] = %p\n", i - 1, pt);

        /* 指向下一個位置 */
        ptr--;
        pt--;
    }
    return 0;
}
           

2. 函數指針與回調函數

2.1 函數指針作為某個函數的參數

函數指針變量可以作為某個函數的參數來使用的,回調函數就是一個通過函數指針調用的函數。

簡單講:回調函數是由别人的函數執行時調用你實作的函數。

以下是來自知乎作者常溪玲的解說:

你到一個商店買東西,剛好你要的東西沒有貨,于是你在店員那裡留下了你的電話,過了幾天店裡有貨了,店員就打了你的電話,然後你接到電話後就到店裡去取了貨。在這個例子裡,你的電話号碼就叫回調函數,你把電話留給店員就叫登記回調函數,店裡後來有貨了叫做觸發了回調關聯的事件,店員給你打電話叫做調用回調函數,你到店裡去取貨叫做響應回調事件。

  • 執行個體

執行個體中

populate_array

函數定義了三個參數,其中第三個參數是函數的指針,通過該函數來設定數組的值。

執行個體中我們定義了回調函數

getNextRandomValue

,它傳回一個随機值,它作為一個函數指針傳遞給

populate_array

函數。

populate_array 将調用 10 次回調函數,并将回調函數的傳回值指派給數組。

#include <stdlib.h>  
#include <stdio.h>
 
// 定義回調函數
void populate_array(int *array, size_t arraySize, int (*getNextValue)(void))
{
    for (size_t i=0; i<arraySize; i++)
        array[i] = getNextValue();
}
 
// 擷取随機值
int getNextRandomValue(void)
{
    return rand();
}
 
int main(void)
{
    int myarray[10];
    /* getNextRandomValue 不能加括号,否則無法編譯,因為加上括号之後相當于傳入此參數時傳入了 int , 而不是函數指針*/
    populate_array(myarray, 10, getNextRandomValue);
    for(int i = 0; i < 10; i++) {
        printf("%d ", myarray[i]);
    }
    printf("\n");
    return 0;
}
           

代碼解釋:

int *array

int array[]

效果相同,但是兩者差別在于:

其實使用數組名

int a[]

定義也相當于指針

int *a

.比如,要通路

int a[5]

實際上是先獲得這個數組的頭指針

int*a

,然後在記憶體中偏移5個int的資料長度

int *(a+5)

,也就是從代碼的了解上,可以認為

int a[5]

int *(a+5)

等價,

作者:林揚飛 連結:https://www.zhihu.com/question/23278865/answer/28430556

2.2 回調函數·傳值調用函數

向函數傳遞參數的傳值調用方法,把參數的實際值複制給函數的形式參數。在這種情況下,修改函數内的形式參數不會影響實際參數。

預設情況下,C 語言使用傳值調用方法來傳遞參數。一般來說,這意味着函數内的代碼不會改變用于調用函數的實際參數。

/* 函數定義 */
void swap(int x, int y)
{
   int temp;

   temp = x; /* 儲存 x 的值 */
   x = y;    /* 把 y 指派給 x */
   y = temp; /* 把 temp 指派給 y */
  
   return;
}
           
菜鳥教程展開>>
補充:C語言return的用法詳解

2.3 回調函數·引用調用函數

通過引用傳遞方式,形參為指向實參位址的指針,當對形參的指向操作時,就相當于對實參本身進行的操作。

傳遞指針可以讓多個函數通路指針所引用的對象,而不用把對象聲明為全局可通路。

/* 函數定義 */
void swap(int *x, int *y)
{
   int temp;
   temp = *x;    /* 儲存位址 x 的值 */
   *x = *y;      /* 把 y 指派給 x */
   *y = temp;    /* 把 temp 指派給 y */
  
   return;
}
           
菜鳥教程展開>>

三、補充

1. 字元串

C 中有大量操作字元串的函數:

序号 函數 目的
1 strcpy(s1,s2); 複制字元串 s2 到字元串 s1。
2 strcat(s1,s2); 連接配接字元串 s2 到字元串 s1 的末尾。
3 strlen(s1,s2); 傳回字元串 s1 的長度。
4 strcmp(s1,s2); 如果 s1 和 s2 是相同的,則傳回 0;如果 s1<s2 則傳回小于 0;如果 s1>s2 則傳回大于 0。
5 strchr(s1,s2); 傳回一個指針,指向字元串 s1 中字元 ch 的第一次出現的位置。
6 strstr(s1,s2); 傳回一個指針,指向字元串 s1 中字元串 s2 的第一次出現的位置。

2. 結構體

struct tag { 
    member-list
    member-list 
    member-list  
    ...
} variable-list ;
           

tag

是結構體标簽。

member-list

是标準的變量定義,比如 int i; 或者 float f,或者其他有效的變量定義。

variable-list

結構變量,定義在結構的末尾,最後一個分号之前,您可以指定一個或多個結構變量。下面是聲明 Book 結構的方式:

struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;
           

指向結構的指針

您可以定義指向結構的指針,方式與定義指向其他類型變量的指針相似,如下所示:

現在,您可以在上述定義的指針變量中存儲結構變量的位址。為了查找結構變量的位址,請把 & 運算符放在結構名稱的前面,如下所示:

為了使用指向該結構的指針通路結構的成員,您必須使用

->

運算符,如下所示:

筆記:

struct A *p;

struct A {};

差別

//定義A為:内含整數的結構體//
struct A {
    int data;     
};
 
int main()
{
    struct A *b; //定義b為指向 滿足标簽A的結構體 的指針//
    struct A c; //定義c為滿足标簽A的結構體//
     
    b = &c;  //指針b中存的是c的位址//
 
    c.data = 100; 
 
    printf("%d\n", b->data);    
 
    return 0;
}
           
菜鳥教程展開>>

3. 共用體

展開>>補充:共用體和結構體的差別

4. 位域

#include <stdio.h>
#include <string.h>
 
/* 定義簡單的結構 */
struct
{
  unsigned int widthValidated;
  unsigned int heightValidated;
} status1;
 
/* 定義位域結構 */
struct
{
  unsigned int widthValidated : 1;
  unsigned int heightValidated : 1;
} status2;
 
int main( )
{
   printf( "Memory size occupied by status1 : %d\n", sizeof(status1));
   printf( "Memory size occupied by status2 : %d\n", sizeof(status2));
 
   return 0;
}
           

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

Memory size occupied by status1 : 8
Memory size occupied by status2 : 4
           

筆記:位數由0到32,增加4個位元組。位數超過32,增加4個位元組。即占用33位,消耗記憶體為8位元組。

菜鳥教程展開>>

四、C語言執行個體

繼續閱讀