CH1 - 基礎

1.1

1
2
int x, y z;
y = z = 4 // y = 4 and z= 4

1.2

  1. & 運算 => 做二進位and運算
  2. | 運算 => 做二進位or運算
  3. && 和 || 皆為判斷式 => 回傳1或者是0

1.3

1
x = (y == z) ? 4 : 5;

y =4, z = 2, (問號前面的判斷式) false, x取後者, x = 5 if (true) ? x = 4 if (false) ? x = 5

1.4

1
::value = 2; 

在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

  1. const定義常量 (只讀不寫),具有不可變性。
  2. 對類型進行安全檢查。
  3. 不能引用(&)const值。
  4. 傳遞參數到函式中,但又不希望額外新增參數。 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的使用

  1. static在這function呼叫結束時,值維持不變(不會因為function結束而消失,具有繼承性)。
  2. static在當全域變數時,可以被所有函數訪問,但不能被該檔案外的其他函數訪問,是一個本地的全局變量。
  3. static function也只可被該檔案內的其他函數調用,不能被模塊外的其他函數訪問。
  4. static變數在class中也具有共享性,即多個obj共享一個static參數。
  5. 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

  1. class中的function不占內存,但virtual function佔用一個pointer的大小 = 4 bytes。
  2. int和「指針」占4 bytes,char占1 bytes,double占8 bytes。
  3. 繼承的函數也要另外的空間。
  4. static在function中,不算空間。
  5. union的大小取決於他所有的成員中佔用空間最大一個成員的大小。同類型取最高,不同類型需對齊。

CH3 - pointer

1
2
& = get value address (call by reference)
* = 取出pointervalue (取出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
  1. 引用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)

  1. stack: 呼叫函數的局部變數在此儲存,函數結束時自動釋放。
  2. 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

  1. 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

  1. 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

  2. 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(無號常整數)