C 初探
C vs Java
1. 類型, 運算符與表達式
1.1 基本數據類型
char, int, float, double, short int, long int ? (可以省略int)
signed 和 unsigned 可以限定 char 類型或任何整形
類型轉換
1.2 常量
整型常量: 默認為 int, ?L 表示 long 型, U 表示 unsigned 型, UL 表示 unsigned long 型
浮點型常量: 默認為 double, F 表示 float 型, L 表示 long double 型
整型常量還可以用八進制, 十六進制表示: 前綴 0 表示八進制, 前綴 0x 表示十六進制
八進制, 十六進制也可以用 L 表示 long 型, U表示 unsigned 型 e.g: 0XFUL?
?
字符常量: 將一個字符括在單引號中, 如 'x'. '\0' 表示值為0的字符, 即 null
轉移字符列表
| 轉義字符 | 意義 | ASCII碼值(十進制) |
| \a | 響鈴(BEL) | 007 |
| \b | 退格(BS) ,將當前位置移到前一列 | 008 |
| \f | 換頁(FF),將當前位置移到下頁開頭 | 012 |
| \n | 換行(LF) ,將當前位置移到下一行開頭 | 010 |
| \r | 回車(CR) ,將當前位置移到本行開頭 | 013 |
| \t | 水平制表(HT) (跳到下一個TAB位置) | 009 |
| \v | 垂直制表(VT) | 011 |
| \\ | 代表一個反斜線字符''\' | 092 |
| \' | 代表一個單引號(撇號)字符 | 039 |
| \" | 代表一個雙引號字符 | 034 |
| \0 | 空字符(NULL) | 000 |
| \ddd | 1到3位八進制數所代表的任意字符 | 三位八進制 |
| \xhh | 1到2位十六進制所代表的任意字符 | 二位十六進制 |
e.g: '\007', '\x7' 均表示響鈴
?
字符串常量: e.g: "hello, world"
字符串常量就是字符數組, 字符串的內部使用一個空字符'\0'結尾
注意字符常量與僅含一個字符的字符串常量的區別: 'x' 與 "x"
?
Consts:
const int days_in_week = 7; /*相當于final in Java*/
const 常用在函數的 prototype 中,說明函數的功能
void foo(const struct fraction* fract); ? // 表明foo函數并不會改變fract指針指向的內容
?
枚舉常量: 枚舉是一個常量整型值的列表 (名字與常量值之間建立聯系)
e.g: enum boolean {NO, YES} ;
在沒有顯示說明的情況下, 第一個枚舉名的值為0, 然后依次遞推. 如果指定了部分枚舉名的值, 則依最后一個遞推.
e.g: enum months { JAN = 1, FEB, MAR, APP, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };
?
1.3 運算符
?
?
2. 函數與程序結構
C 不支持函數定義的嵌套
參數傳遞傳遞的是 value (好好理解這句話:傳遞普通數據,傳遞指針,傳遞指針的指針)
作用域規則:
storage classes in C
C語言不像Java, Python, 不同文件中的變量都已 文件名.變量名 訪問. C 語言中不同文件不能定義相同名稱的外部變量.(無法通過編譯).?
如果要在外部變量的定義之前使用該變量, 或外部變量的定義與變量的使用不再同一個源文件中, 則必須在相應的變量聲明中強制性地使用關鍵字 external.
注意區分 聲明 與 定義. 變量聲明用于說明變量的屬性, 而變量定義還將引起存儲器的分配. 因此外部變量的定義必須指定數組的長度, 但聲明不一定.
// 定義 int sp; double val[MAXVAL];// 聲明 extern int sp; extern double val[];?
靜態變量(static):
用static來聲明一個變量的作用有二:
(1) 外部變量用static來聲明,則該變量的作用只限于本文件模塊.(這種不同文件可以使用相同變量名)
(2) 對于局部變量用static聲明,則是為該變量分配的空間在整個程序的執行期內都始終存在(但只初始化一次)
對于外部變量和靜態變量來說, 初始化表達式必須是常量表達式, 而自動變量沒有這要求.
?
宏定義 (#define)
#define 名字 替換文本
#define forever for(;;); // 無限循環 #define square(x) (x) * (x);?注意可能傳入的參數有副作用(比如含有自增運算符), 以及計算次序.
?
?
C 語言中 可以返回 any type?except arrays and functions. 但可以返回 pointer to array or pointer to function.
?
?
3. 指針與數組
Pointer:
Pointer: A variable that contains the address of a variable
int *x;
- Tells compiler that variable x is address of an int
x = &y;
- Tells compiler to assign address of y to x
- & called the "address operator" in this context
z = *x;
- Tells compiler to assign value at address in x to z
- * called the "dereference operator" in this context
pointers can point any kind of data, normally a pointer only points to one type
but void * is a type that can point to anything
?
x = (*p)++ ? x = *p; *p = *p + 1x = *p++ ? (*p++) ? *(p)++ ? *(p++) ? x = *p; p = p + 1
x = *++p ? p = p + 1; x = *p
盡量只用 *p++ , (*p) ++
?
?通過不同類型的 cast, 可以確切控制指針的位置
// assume p is a pointer point to a int p = p + 12; // move 48 bytes p = (int *)( ((char *)p) + 12); // move 12 bytes?
Array:
int ar[2]; int ar[] = {1, 2}; char string[] = "abc"; // String in C is just an array of characters?數組表示的字符串可能并不以 '\0' 結尾
數組的大小必須是常量,比如 int ar[n] 就不行,要想使用變量的數組,要在 heap 中分配
?
Array variable is a "pointer" to the first element, so array variable almost identical to pointers?
ar[0] sames as *ar ar[2] sames as *(ar+2)Q: 如果數組中的元素不是一個byte大小會怎么樣? A:?因為聲明指針時說明了 type, 所以 +1 就是增加相應類型的位數
?
當把數組名傳遞給一個函數時, 實際上傳遞的是該數組第一個元素的地址. ?即?int strlen(char s[]) ?等價于 int strlen(char *s) ?而且更習慣于后一種形式(因為清晰的表面了傳入的是指針)
?
Array vs Pointer
?
指向指針的指針
int n = 3; int *pn = &n; // pointer to n int **ppn = &pn; // pointer to address of n?
e.g:
void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp; }void swap(int **a, int **b) {int *temp = *a;*a = *b;*b = temp; }?e.g:
void inc_ptr(int *p) {p = p + 1; }int A[3] = {50, 60, 70}; int *q = A; inc_ptr(q); printf("%d\n", *q);// output: 50因為這里傳遞的是值, 所以函數內改變只是改變了拷貝. 要修改q的指向, 需要傳遞q的指針
void inc_ptr(int **p) {*p = *p + 1; }int A[3] = {50, 60, 70}; int *q = A; inc_ptr(&q); printf("%d\n", *q);// output: 60?
指針數組 ?
e.g: char *name[] = { "Illegal month", "Jan", "Feb", "Mar" };
注意區分指針數組與二維數組的區別(兩者在內存上的分配不同, 指針數組更自由, 其每一行的長度可以不同)
?
函數指針
int *f(); // f 是一個函數, 它返回一個指向 int 類型的指針 int (*f) (); // f 是一個指向函數的指針, 該函數返回一個 int 類型的對象C 中函數不能穿入函數做參數,但可以傳入函數指針做參數。(所以要支持Callback(回調)就傳入函數指針)
ps: 函數做指針時,不必用 & 和 *,當然用也沒錯
int strcmp_wrapper(void * pa, void * pb) {return strcmp((const char *)pa, (const char *)pb); }int (*fp)(void *, void *) = strcmp_wrapper; // 或 &strcmp_wrapperint ret = fp(str1, str2); // 或 (*fp)(str1, str2)?
函數指針應用舉例
以標準庫中的qsort為例, qsort的signature為
void qsort(void* arr, int num, int size, int (*fp)(void* pa, void* pb))qsort 使用舉例
int arr[] = {10, 9, 8, 1, 2, 3, 5}; /* callback */ int asc(void* pa, void* pb) {return (*(int *)pa - *(int *)pb); }/* callback */ int desc(void* pa, void* pb) {return (*(int *)pb - *(int *)pa); }qsort(arr, sizeof(arr)/sizeof(int), sizeof(int), asc); //&asc也行 qsort(arr, sizeof(arr)/sizeof(int), sizeof(int), desc); //&desc也行?
?
4. Structures?、union、typedef、bit fields
ps:C structure assignment is not a "deep copy". All members are copied, but not things pointed to by members.
?
Structure Member Alignment, Padding
(將structure 中的元素由 size 從大到小或從小到大排列可以減小總大小)
?
Bit Fields 用于Structure中, 目的是節省空間
/* define simple structure */ struct {unsigned int widthValidated;unsigned int heightValidated; } status1;/* define a structure with bit fields */ 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; }?
?
5. C Memory Management
?
static, global 變量儲存在 static data 區
局部變量 儲存在 stack 區, 并且當函數返回時釋放
?
C 內存管理是指管理 Heap
內存管理有如下幾個函數
| 1 | void *calloc(int num, int size); This function allocates an array of?num?elements each of which size in bytes will be?size. |
| 2 | void free(void *address); This function release a block of memory block specified by address. |
| 3 | void *malloc(size_t num); This function allocates an array of?num?bytes and leave them initialized. |
| 4 | void *realloc(void *address, int newsize); This function re-allocates memory extending it upto?newsize. |
切記檢查 malloc, calloc, realloc 的返回值是否為 NULL
?
e.g:??沒有cast也行,但編譯器會給出warnning
int *ip ip = (int *) malloc(sizeof(int)); typedef struct { ... } TreeNode; TreeNode *tp = (TreeNode *) malloc(sizeof(TreeNode)); free((void *) tp);?
ps:如果內存不夠時, malloc() 返回 NULL 指針。
free 內存時,必須保證傳遞給 free() 是 malloc() 返回的指針 (不能做修改)
?
一個實例:Binary Tree
typedef struct node {int key;struct node *left;struct node *right; } Node;Node *root = NULL;Node *create_node(int key, Node *left, Node *right) {Node *np;if ( (np = (Node *) malloc(sizeof(Node))) == NULL ) {printf("Memory exhausted!\n");exit(1);} else {np->key = key;np->left = left;np->right = right;return np;} }void insert(int key, Node **tree) {if ( (*tree) == NULL ) {(*tree) = create_node(key, NULL, NULL); return;}if (key <= (*tree)->key)insert(key, &((*tree)->left));elseinsert(key, &((*tree)->right)); }?
Memory Leak:more mallocs than frees
int *pi; void foo() {pi = malloc(8*sizeof(int));free(pi); }void main() {pi = malloc(4*sizeof(int));foo(); }?
?
?
6. I/O
Standard I/O
// 注意 IO 函數的返回值類型是 int int putchar(int); int getchar(int);int printf(char* format, arg1, arg2,...) int scanf(char* format, arg1. arg2,...) // 注意 scanf 的arg必須是地址或指針(所以傳遞數字時常加&, 傳遞字符串則沒事)?
?File I/O
FILE* fopen(char name[], char model[]) int fclose(FILE* fp);fopen 返回一個指向文件流的指針(如果不存在則返回 NULL )
Standard I/O 其實就是 FILE* (stdin, stdout)
?
int getc(FILE* fp); // 從文件流中讀取一個字符返回讀取值或EOF(注意返回值類型為 int)
getchar() 就是 getc(stdin)
?
char[] fgets(char line[], int maxlen, FILE* fp) // 讀取一行(包括換行符)??返回字符串的指針或EOF
?
int putc(int c, FILE* fp); int fputs(char line[], FILE* fp);?
main 函數參數輸入
int main(int argc, char* argv[])args: 參數數量 argv[]:參數
注意參數包含了程序名(第一個) ?
?
?
?
2015-09-19
?
轉載于:https://www.cnblogs.com/whuyt/p/4791206.html
總結
- 上一篇: 条款14:在资源管理类中心copying
- 下一篇: 360电话面试