# C語言複習 ## C語言標準函式庫 ```c #include <string.h> char * strcpy(char * destination, const char * source); char * strncpy(char *dest, const char *src, size_t count); void * memcpy(void *dest, const void *src, size_t length); void * memset(void *dest, int value, size_t num); int strcmp(const char *str1, const char *str2); // return 0 if str1 == str2 else 1 int strlen(const char *str1); // not include '\0' ``` 特定大小 ```c // In <stdint.h> typedef signed integer type int8_t; // optional typedef signed integer type int16_t; // optional typedef signed integer type int32_t; // optional typedef signed integer type int64_t; // optional typedef unsigned integer type uint8_t; // optional typedef unsigned integer type uint16_t; // optional typedef unsigned integer type uint32_t; // optional typedef unsigned integer type uint64_t; // optional ``` ```c // In <limits.h> INT_MIN //整型最小值:-2147483648,即 -(231) INT_MAX //整型最大值:+2147483647 ,即231 - 1 ``` 找出結構偏移位置 ```c #include <stdio.h> #include <stddef.h> struct containers { char c; int i; }; int main(){ struct containers s; printf("%ld", (size_t)((char *)&s.i - (char *)&s)); printf("%ld", (size_t) &((struct containers *)0)->i); printf("%ld", offsetof(struct containers, i)); } ``` --- ```c struct __attributed__(packet){ char a; int b; char c; }; ``` ## Bitwise operation ```c uint32_t a = 0x00000001; printf("%x", a); // 16 進制可用 %x 來輸出 ``` ### 計算絕對值不使用 branch ```c int v; unsigned int r; int const mask = v >> sizeof(int) * CHAR_BIT -1; r = (v+mask)^mask; or r = (v ^ mask) - mask; ``` ### Max function 不使用 branch ```c uint32_t Max(uint32_t a, uint32_t b) { return a ^ ((a ^ b) & -(a < b)); } ``` ### 返回 A or B 中的最大值: ```c int max(int a, int b){ return (a+b+abs(a-b))/2; } ``` ### 最大公因數計算 ```c uint32_t gcd32(uint32_t u, uint32_t v) { if(!u || !v) return u | v; int shift; for (shift=0; !((u | v) & 1); shift++){ u/=2; v/=2; } while (!(u & 1)) u /= 2; do{ while (!(v & 1)) v /= 2; if (u < v){ v -= u; } else{ uint32_t t = u - v; u = v; v = t; } }while(v); return u * (1 << shift); } ``` ### Detect NULL ```c #define DETECT(X) \ (((X) - 0x01010101) & ~(X) & 0x80808080) ``` 偵測是否為 0 ### XOR swap 交換兩個記憶體空間的數值 ```c void xorSwap(int *x, int *y){ *x ^= *y; *y ^= *x ; *x ^= *y; } ``` ### counting leading zero iteration version ```c int clz(uint32_t x){ int n =32, c = 16; do{ uint32_t y = x >> c; if(y) {n -= c; x = y;} c>>=1; }while (c); return (n - x); } ``` binary search technique : ```c int clz(uint32_t x){ if (x == 0) return 32; int n = 0; if (x <= 0x0000FFFF){ n += 16; x <<= 16; } if (x <= 0x00FFFFFF){ n += 8; x <<= 8; } if (x <= 0x0FFFFFFF){ n += 4; x <<= 4; } if (x <= 0x3FFFFFFF){ n += 2; x <<= 2; } if (x <= 0x7FFFFFFF){ n += 1; x <<= 1; } return n; } ``` byte-shift version : ```c int clz(uint32_t x) { if (x == 0) return 32; int n = 1; if ((x >> 16) == 0) { n += 16; x <<=16; } if ((x >> 24) == 0) { n += 8; x <<= 8; } if ((x >> 28) == 0) { n += 4; x <<= 4; } if ((x >> 30) == 0) { n += 2; x <<= 2; } n = n - (x >> 31); return n; } ``` ### Integer bits inverse for loop 形式 : ```c int func(unsigned int x) { int val = 0; int i = 0; for (i = 0; i < 32; i++){ val = (val << 1) | (x & 0x1); x >>=1; } return val; } ``` [bit-wise 形式](https://stackoverflow.com/questions/21511533/reverse-integer-bitwise-without-using-loop) : ```c new = num; new = ((new & 0xffff0000) >> 16) | ((new & 0x0000ffff) << 16); new = ((new & 0xff00ff00) >> 8) | ((new & 0x00ff00ff) << 8); new = ((new & 0xf0f0f0f0) >> 4) | ((new & 0x0f0f0f0f) << 4); new = ((new & 0xcccccccc) >> 2) | ((new & 0x33333333) << 2); new = ((new & 0xaaaaaaaa) >> 1) | ((new & 0x55555555) << 1); ``` ### quicksort ```c #define SWAP(a,b) \ do{ \ typeof(*a) _temp = *(a); \ *(a) = *(b); \ *(b) = _temp; \ }while(0) // void quicksort(int *arr,int first,int last){ // int pivot = *(arr + first); // int front = first + 1; // int behind = last; // if(first >=last) // return; // while(front <= behind){ // if(*(arr + front) <= pivot && front <= last) // front++; // if(*(arr + behind) > pivot && behind > first) // behind--; // if(front < behind) // SWAP((arr + front),(arr + behind)); // } // SWAP((arr + first),(arr + behind)); // quicksort(arr, first, behind-1); // quicksort(arr, behind+1, last); // } void quicksort(int *arr, int *fr, int *be){ if(fr >= be) return; int *front = fr + 1; int *behind = be; int *pivot = fr; while(front < behind){ while (*front < *pivot && front < be) { front++; } while(*behind > *pivot && behind >= pivot + 1) behind--; if (front < behind) SWAP(front,behind); } SWAP(pivot,behind); quicksort(arr,fr,behind - 1); quicksort(arr,behind + 1,be); } ``` ### heapsort ## C 語言觀念 ### 函式指標 函式透過宣告宣告成函式指標: ```c void (*fptr)(type argv1, type argv2) = &func; //or void (*fptr)(type argv1, type argv2) = func; fptr(argv1, argv2); //or (*fptr)(argv1, argv2); ``` 常用地方: * 函式 sort 時傳入判斷準位 * multithread 傳函式進入建立 thread 的 API 中 * callback function ### 指標判讀 & const * a)一個整型數 (An integer) * b)一個指向整數的指標 (A pointer to an integer) * c)一個指向指標的指標,它指向的指標是指向一個整型數 (A pointer to a pointer to an integer) * d)一個有10個整數型的陣列 (An array of 10 integers) * e)一個有10個指標的陣列,該指標是指向一個整數型的(An array of 10 pointers to integers) * f)一個指向有10個整數型陣列的指標 (A pointer to an array of 10 integers) * g)一個指向函數的指標,該函數有一個整數型參數並返回一個整數 (A pointer to a function that takes an integer as an argument and returns an integer) * h)一個有10個指標的陣列,該指標指向一個函數,該函數有一個整數型參數並返回一個整數 (An array of ten pointers to functions that take an integer argument and return an integer) :::info 陣列存取權限高於 * 位置存取, 因此解讀 (e) 為陣列元素有 10 個, 每個元素是一個整數指標。 而 (f) 可解讀為有一個指標,這個指標為有 10 元素的整數陣列。 ::: ```c int a; int *ptr; int **ptr; int array[10]; int *array[10]; // e int (*ptr)[10]; // f int (*ptr)(int); int (*ptr[10])(int); ``` ```c const int *foo; // 一個pointer 指向 const int 變數 int const *foo; // 同上 int * const foo; // 一個 const pointer 指向 int 變數 int const * const foo; //兩個都是 const ``` ### inline 函式 inline 函式像巨集依樣將函式展開編譯,加速執行速度。 inline 與 #define 差別: * inline 只對參數執行一次計算 * inline 參數型別會被檢查並做必要的型別轉換 * Macro 定義通常不使用於 複雜的函數 * 用 inline 後編譯器不一定會實作,僅為建議 ### Struct 結構 簡單的定義結構: ```c struct students{ int id; char name[20]; int chinese; int english; int math; int social; int science; }; //使用時: struct students someone; ``` 定義結構的同時宣告變數(全域變數共用一實體,可直接使用): ```c struct students{ int id; char name[20]; int chinese; int english; int math; int social; int science; }someone; //使用時: someone.chinese = 10; ``` 定義 struct 也宣告 struct 別名: ```c struct students{ int id; char name[20]; int chinese; int english; int math; int social; int science; } typedef struct students Student; //使用時: Student b_class; ``` 定義 struct 時直接取別名: ```c typedef struct{ int id; char name[20]; int chinese; int english; int math; int social; int science; }Student; //使用時: Student b_class; ``` ### Union 聯合在同一時間同僅能儲存其中一個屬性,故以下程式會引發錯誤: ```c #include <assert.h> typedef union sample_t sample_t; union sample_t { float f; int i; char ch; }; int main(){ sample_t s; s.i = 3; assert(s.i == 3); s.f = 5.0; assert(s.i == 3); // Error! return 0; } ``` * union 中的大小由最大的成員的大小決定 * 對某一個成員賦值,會覆蓋其他成員的值(若所佔字節不同,僅會覆蓋對應字節) * union 的存放順序是全部成員都從低位置開始存放的。 ### GNU extension 的 typeof typeof 允許我們傳入一個變數,代表的會是該變數的型態, typeof 通常會用在定義巨集上,因為巨集裡無法得知參數型態 ```c #define max(a, b) \ {(typeof(a) _a = a; \ typeof(b) _b = b; \ _a > _b ? _a : _b;) \ } ``` 看以下程式碼: ```c #define max(a, b) ({ \ typeof (a) _a = (a); \ typeof (b) _b = (b); \ _a > _b ? _a : _b; \ }) ``` [來源](https://hackmd.io/@sysprog/linux-macro-minmax),提到一樣是 GNU 的 extension ({}) 使得回傳的是最後一個敘述 ```_a > _b ? _a : _b;``` 的數值。 ### Arraysize() 的錯誤 參考以下程式碼: ```c #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) int main(void) { int a[10]; int *a_ptr = a; printf("%d\n", ARRAY_SIZE(a)); printf("%d\n", ARRAY_SIZE(a_ptr)); return 0; } ``` 若傳入的是 a ,則 arraysize = 10 正確。但若傳遞的是 a_pt 這個 pointer ,則會算出這個 pointer 的大小除以 *(pointer) 的型態大小,錯誤! [你所不知道的 C 語言:前置處理器應用篇](https://hackmd.io/@sysprog/c-prog/%2Fs%2FS1maxCXMl) [面試考古參考](https://hackmd.io/aXZ0ZLqoQVej8Le7MI6k3w?view) https://www.dcard.tw/f/tech_job/p/239480651