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]
,然後在記憶體中偏移5個int的資料長度
int*a
,也就是從代碼的了解上,可以認為
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位元組。
菜鳥教程展開>>