CH1 - 基礎#
1.1#
1
2
|
int x, y z;
y = z = 4 // y = 4 and z= 4
|
1.2#
- & 運算 => 做二進位and運算
- | 運算 => 做二進位or運算
- && 和 || 皆為判斷式 => 回傳1或者是0
1.3#
y =4, z = 2, (問號前面的判斷式) false, x取後者, x = 5
if (true) ? x = 4
if (false) ? x = 5
1.4#
在C中無法編譯通過,C++可。(改變全局變數值)
1.5 i++/++i 區別#
1
2
3
|
int i = 8;
printf("%d\n", ++i); // 9
printf("%d\n", i--); // 9, 先印9, i = 8
|
效率沒有區別, 自定義++i較佳
1.7 不使用中間變量將a,b值進行交換#
1
2
3
4
5
6
7
8
9
10
11
12
13
|
void swap2( int a, int b ) {
a = a + b;
b = a - b;
a = a - b;
}
// 使用XOR完成交換 1xor1 = 0, 1xor0 = 1.
void swap3( int a, int b ) {
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
|
1.8 extern的使用#
對於extern變量來說,僅僅是一個變量的聲明,其並不是在定義分配內存空間。如果該變量定義多次,會有連接錯誤。其聲明的函數或變量可以在其他module中使用。
1.9 main()執行完還執行其他語句嗎#
使用atexit(function_name), 註冊程式終止要被調用的函數。
CH2 - macro, inline, const, static, sizeof#
2.2 用#define定義最大和最小值#
1
2
|
#define MAX(x,y) ( ((x) > (y)) ? (x) : (y) )
#define MIN(x,y) ( ((x) < (y)) ? (x) : (y) )
|
define: compile時代入 (沒數據類型)
const: run-time時代入 (有數據類型,進行安全檢查)
macro 與 inline
相同之處:是把呼叫的位址換成函式主體,這樣執行速度較快,多半用於需要多次呼叫的程式。
相異之處:macro 是pre-compile,會在程式編譯成為機器語言之前先編譯完成,是一種文字替換的概念。而inline就像一般函式一樣,是compiler決定的。
1
2
3
4
5
6
7
8
|
// macro example
#define SIZE 1024 // 定義常數
#define SQUARE(x) ((x) * (x)) // 定義函式
//inline example
inline int square(int x){
return x*x;
}
|
macro 與 inline 都是用空間換取時間
function 則是用時間換取空間
2.7 const的使用#
#2-12
- const定義常量 (只讀不寫),具有不可變性。
- 對類型進行安全檢查。
- 不能引用(&)const值。
- 傳遞參數到函式中,但又不希望額外新增參數。
void fun(A a);
void fun(A const & a); 引用a但加const保持不變性
1
2
3
4
5
|
int b = 10;
const int * a1 = &b; // 不允許修改值(修飾int),但指向位置可以修改
int const * a1 = &b;
int * const a2 = &b; // 不允許修改位置(修飾指標),但值可以修改
const int * const a3 = &b; // 皆不能修改
|
2.10 static的使用#
- static在這function呼叫結束時,值維持不變(不會因為function結束而消失,具有繼承性)。
- static在當全域變數時,可以被所有函數訪問,但不能被該檔案外的其他函數訪問,是一個本地的全局變量。
- static function也只可被該檔案內的其他函數調用,不能被模塊外的其他函數訪問。
- static變數在class中也具有共享性,即多個obj共享一個static參數。
- static function在class中也具有共享性,即便我們沒有產生 instance 出來,我們也隨時可以取用這個 function。
1
2
3
|
static局部變數 vs 普通局部變數: static只初始化一次,下一次依據上一次結果值
static全局變數 vs 普通全局變數: static只初始化一次,防止在其他文件中被引用
static function vs 普通function: static function在內存中只有一份,普通function每個被調用都維持一份複製品
|
2.13 使用sizeof計算變數所占的bytes大小#
char str[] = “hello”;
char * p= str;
int n = 10;
sizeof(str) = 5 + 1 (’\0’) = 6;
sizeof(p) = 4;
sizeof(n) = 4; 32位winnt平台下,指針和int都為4 bytes
- class中的function不占內存,但virtual function佔用一個pointer的大小 = 4 bytes。
- int和「指針」占4 bytes,char占1 bytes,double占8 bytes。
- 繼承的函數也要另外的空間。
- static在function中,不算空間。
- union的大小取決於他所有的成員中佔用空間最大一個成員的大小。同類型取最高,不同類型需對齊。
CH3 - pointer#
1
2
|
& = get value address (call by reference)
* = 取出pointer之value (取出address指向的value)
|
3.1 引用 &#
1
2
3
4
5
|
int a = 10;
int b = 20;
int &rb = a; // 引用只能在聲明的時候賦值
rb = b;
cout << a << endl; // a = 20
|
- 引用vs pointer: 引用初始完後不能被改變,pointer可以隨時指向別的對象。
3.10 用pointer賦值#
1
2
3
4
5
6
|
char a[] = "hello world";
char * ptr = a;
printf( "%c\n", *(ptr+4) ); // o
printf( "%c\n", ptr[4] ); // o
printf( "%c\n", a[4] ); // o
printf( "%c\n", *(a+4) ); // o
|
3.12 Pointer比較#
1
2
3
4
5
6
7
8
9
10
|
char str1[] = "abc"; // str1 != str2 記憶體位置不一樣
char str2[] = "abc";
char * str7 = "abc"; // str7 == str8 記憶體位置一樣
char * str8 = "abc";
char * str3 = "AAA";
str3[0] = 'B'; // 不合法,str3指向常量,不能操錯。pointer不能直接賦值,要初始化。
int * a[10]; // 指針數組,數組中每一個元素都是指針
int * a = new int[10]; // 一個指針,指向一個數組。
|
3.21 指針數組找錯#
1
2
3
4
5
6
|
char * str[] = { "Weclone", "to", "Fortemedia", "Nanjing" }; // A,B,C,D
char **p = str + 1; // p移動指向B
str[0] = (*p++) + 2; // p移動指向C,str[0] = 空
str[1] = *(p+1); // p不移動,str[1] = D
str[2] = p[1] + 3; // 指向D往後3個元素,Jing
str[3] = p[0] + ( str[2] - str[1] );
|
3.25 函數指針#
1
2
3
4
5
6
7
|
int max( int x, int y ) {
return x > y ? x : y;
}
int (*p) (int,int);
int max( int, int );
p = &max;
|
1
2
3
4
5
6
7
8
9
|
int main() {
int (*op[2]) (int a, int b);
op[0] = add1;
op[1] = add2;
cout << op[0]( 0, 0 ) << op[1]( 0, 0 );
}
int add1( int a1, int b1 ) { return a1+b1 };
int add2( int a2, int b2 ) { return a2+b2 };
|
3.30 有了malloc/free,還需要new/delete#
malloc/free是標準庫函數,無法執行constructor與destructor
1
2
3
4
5
6
|
char * name = "test";
char * coptyName() {
char * newname = new char[strlen(name) + 1]; // 字符串已0作為結束符。
strcpy( newname, name );
return newname;
}
|
3.35#
棧內存 (Stack) & 堆內存(Heap)
- stack: 呼叫函數的局部變數在此儲存,函數結束時自動釋放。
- heap: new/malloc在此的動態內存分配。
CH4 - String#
[[8 - String to Integer (atoi)]]
4-5 strcpy實作#
1
2
3
4
5
6
7
8
9
10
11
12
13
|
char * DIY_strcpy( char * strDest, char * strSrc ) {
if ( strDest == NULL || strSrc == NULL ) return NULL;
char * strDestStart = strDest;
while ( *strSrc != '\0' ) {
*strDest = *strSrc;
strSrc++;
strDest++;
}
*strDest = '\0';
return strDestStart;
}
|
4-6 memset vs memcpy vs memcmp#
- memset
複製字符 c(一個無符號字符)到參數 str 所指向的字符串的前 n 個字符。
1
2
3
4
5
6
7
8
9
10
11
12
|
#include <stdio.h>
#include <string.h>
int main ()
{
char str[50];
strcpy(str,"This is string.h library function");
puts(str);
memset(str,'$',7);
puts(str);
return(0);
}
|
This is string.h library function
qqqqqq string.h library function
-
memcpy vs strcpy
memcpy可複製其他類型的數據,strcpy則只用來複製字符串(’\0’)而結束。
1
2
3
4
5
6
7
8
9
10
|
#include <string.h>
#include <stdio.h>
void main()
{
char *s="pannyloveworld";
char s1[10];
s1[9]='\0';
memcpy(s1,s+5,9); // (dest, start_index, 長度)
printf("%s",s1);
}
|
Output: loveworld
-
memcmp vs strcmp
皆為比較字串的大小,memcmp為比較內存塊
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[15];
char str2[15];
int ret;
memcpy(str1, "abcdef", 6);
memcpy(str2, "ABCDEF", 6);
ret = memcmp(str1, str2, 5);
// 比較str1和str2前n個字節AIIC碼值的大小; ret > 0 = str1 > str2, ret < 0 = str1 < str2
// 大寫ascii值較小
if (ret > 0) printf("str1 is big than str2");
else if (ret < 0) printf("str2 is big than str1");
else printf("str1 is equal to str2");
return(0);
}
|
Output: str1 is less than str2
4-11 計算字串長度#
1
2
3
4
5
|
int strlen2( char * src ) {
char * temp = src;
while ( *src++ != '\0' );
return ( src - temp - 1 );
}
|
4-18 aaabb = aaa3b2#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void transformation() {
char str[200];
scanf( "%s", str );
char * p = str;
char * q = str + 1;
int count = 1;
int len = strlen(str);
char * buf = (char*)malloc(len+1);
while ( *q != '\0' ) {
if ( *q == *p ) {
q++;
p++;
count++;
}
else {
sprintf( buf, "%d", count );
strcat( buf, q );
*q = '\0';
strcat( str, buf );
q++;
p = q;
q = p + 1;
count = 1;
}
}
sprintf( buf, "%d", count );
strcat( str, buf );
printf( "%s\n", str );
}
|
字串記得初始化
1
2
3
|
char * str3 = NULL;
str3 = new char[strlen(str1)+strlen(str2)+1]
str3[0] = '\0'; // 記得new完的字串要初始化。
|
4-19 實作strcat#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
// strcat(原本,追加)
char * mystrcat( char * str1, char * str2 ) {
char * dest = str1;
while ( *str1 != '\0' ) str1++;
while ( *str2 != '\0' ) {
*str1 = *str2;
str1++;
str2++;
}
*str1 = '\0';
return dest;
}
char * mystrcat2( char str1[], char str2[] ) {
char * dest = str1;
int i = 0;
while ( str1[i] != '\0' ) i++;
int j = 0;
while ( str2[j] != '\0' ) {
str1[i] = str2[j];
i++;
j++;
}
str1[i] = '\0';
return dest;
}
int main() {
char * dest = NULL;
char str1[40] = "Hello ";
char str2[40] = "World!";
char * str3 = "Hello ";
char * str4 = "World!";
dest = (char*)malloc(256);
*dest = '\0';
// dest = mystrcat2( str1, str2 );
dest = mystrcat( mystrcat( dest, str3 ) , str4 );
printf( "dest: %s\n", dest );
}
|
CH5 - Bit operation#
5-3 set/remove 特定bit#
bit 3 = 2的3次方 = 從右數來第四位。
1
2
3
4
5
|
int main() {
int i = 20, j = 28;
i = i | ( 1 << 3 ); // i = 28 (3 = n)
j = j & ~( 1 << 3 ); // j = 20 (3 = n)
}
|
5-4 計算一個char有多少bit被設置1#
1
2
3
4
5
6
7
8
9
|
int main( ) {
int a = 63, count = 0;
while ( a ) {
a = a & a - 1;
count++;
}
printf( "%d\n", count );
}
|
5-8 用define聲明一個常數#
1
|
#define SECONDS_PER_YEAR ( 60 * 60 * 24 & 365) UL(無號常整數)
|