資料型態 | Size (Byte) | 格式 |
---|---|---|
(unsigned) short | 2 | %d |
(unsigned) int | 4 | %d |
(unsigned) long | 4 (32-bits) 或 8 (64-bits) | %d |
(unsigned) long long | 8 | %d |
float | 4 | %f |
double | 8 | %f |
long double | 12 | %f |
char | 1 | %c |
(unsigned) char | 1 | %c |
unsigned 資料型態格式為%u
#include <stdio.h>
int main(int argc, const char * argv[]) {
// printf("%d\n", sizeof(unsigned long)); 會導致警告,
// 因为 sizeof 回傳的是 size_t 類別,而 %d 是用於格式化 int 類別的格式符。
printf("%zu\n", sizeof(unsigned long));
return 0;
}
//output
8
Program ended with exit code: 0
size_t
is an unsigned data type,對於 32-bit 的系統而言,size_t 的大小為 4 bytes,而 64-bit 的系統則為 8 bytes。(%zu is used for size_t values)
跳脫字元:
\n: 換行
\r: 將游標移至目前所在行的起始位置
\t: 水平TAB
\a: 警告。讓系統發出警告聲
\\: 在字串中顯示反斜線
\': 在字串中顯示單引號
\": 在字串中顯示雙引號
\?: 在字串中顯示問號
#include <stdio.h>
int main(int argc, const char * argv[]) {
// short -> int
short s_1 = 10;
int i_1 = (int)s_1;
printf("s_1 size: %zu Bytes\ni_1 size: %zu Bytes\n", sizeof(s_1), sizeof(i_1));
//int -> short
int i_2 = 10;
short s_2 = (short)i_2;
printf("\ni_2 size: %zu Bytes\ns_2 size: %zu Bytes\n", sizeof(i_2), sizeof(s_2));
//int -> float
int i_3 = 10;
float f_1 = (float)i_3;
printf("\nf_1 = %f\n", f_1);
//float -> int
float f_2 = 10.5;
int i_4 = (int)f_2;
printf("i_4 = %d\n", i_4);
//overflow
const int i_5 = 32768;
short s_3 = (short)i_5;
printf("\n%d overflow occur! short range is -32768 ~ 32767\n", s_3);
int i_6 = -15;
unsigned short us_4 = (unsigned short)i_6;
printf("%u overflow occur! unsigned short range is 0 ~ 65535\n", us_4);
double d_1 = 3.5e38; // d_1 = 3.5*10^38
float f_3 = (float)d_1;
printf("%f overflow occur! float range is -3.4e38 ~ 3.4e38\n\n", f_3); //inf: 無窮大
}
//output
s_1 size: 2 Bytes
i_1 size: 4 Bytes
i_2 size: 4 Bytes
s_2 size: 2 Bytes
f_1 = 10.000000
i_4 = 10
-32768 overflow occur! short range is -32768 ~ 32767
65521 overflow occur! unsigned short range is 0 ~ 65535
inf overflow occur! float range is -3.4e38 ~ 3.4e38
Program ended with exit code: 0
#include <stdio.h>
int main(int argc, const char * argv[]) {
//一維陣列
int i_arr[] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
printf("%d ", i_arr[i]);
}
printf("\n");
int i_arr2[5];
i_arr2[0] = 6;
i_arr2[1] = 7;
i_arr2[2] = 8;
i_arr2[3] = 9;
i_arr2[4] = 10;
for (int i = 0; i < 5; i++) {
printf("%d ", i_arr2[i]);
}
printf("\n");
printf("\n");
//二維陣列,行size一定要寫
float f_arr[][3] = { // f_arr[列][行]
{1.1, 1.2, 1.3},
{2.1, 2.2, 2.3},
{3.1, 3.2, 3.3}
};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%f ", f_arr[i][j]);
}
printf("\n");
}
printf("\n");
}
//output
1 2 3 4 5
6 7 8 9 10
1.100000 1.200000 1.300000
2.100000 2.200000 2.300000
3.100000 3.200000 3.300000
Program ended with exit code: 0
#include <stdio.h>
int main(int argc, const char * argv[]) {
char str[] = "Hello World!";
// str 實際上是由13個字元組成的字串 -> H,e,l,l,o, ,W,o,r,l,d,!,\0
printf("%zu\n", sizeof(str));
printf("%s\n", str);
char str2[][4] = {
"cat", // c, a, t, \0
"dog", // d, o, g, \0
"pig" // p, i, g, \0
};
printf("%s %s %s\n", str2[0], str2[1], str2[2]);
}
//output
13
Hello World!
cat dog pig
Program ended with exit code: 0
會將輸入的內容以string的格式儲存在緩衝記憶體 (Buffer) 中,在依對應的轉換詞(eg. %d, %f, %c, etc.),存入指定的記憶體位置。
會將 %d 替換成 input 的內容,再以 string 的格式存入緩衝記憶體 (Buffer) 中,並打印出來。也就是說打印出來的內容皆是string的型態。
#include <stdio.h>
int main(int argc, const char * argv[]) {
int input;
scanf("%d", &input); // 輸入並指派給 input
printf("output = %d\n", input); // 輸出
int input2, input3, input4;
scanf("%d%d%d", &input2, &input3, &input4);
printf("output = %d %d %d\n", input2, input3, input4);
// 輸入/輸出字串
char input5[10];
scanf("%s", input5); // 不需加&,另外,輸入空白鍵會被當作是\0
printf("output = %s\n", input5);
//print integer.
int a = 100;
printf("%d\n", a);
// print long integer.
long b = 100;
printf("%ld\n", b);
// print %md, m -> 含 a 本身共 m 格,a 前補 space。
printf("%20d\n", a);
// print float number.
float c = 3.141592;
printf("%f\n", c);
// print %mf, m -> Round float number to m place.
printf("%.4f\n", c);
}
//output
10
output = 10
11 12 13
output = 11 12 13
Hello World
output = Hello
100
100
100
3.141592
3.1416
Program ended with exit code: 0
自行宣告字串來取代掉 scanf 使用的 buffer,也就不用在程式執行時才輸入input。
#include <stdio.h>
int main(int argc, const char * argv[]) {
int input1;
float input2;
char input3[4];
char input[20] = "10 3.14 abc";
sscanf(input, "%d%f%s", &input1, &input2, input3);
printf("%d, %f, %s\n", input1, input2, input3);
}
//output
10, 3.140000, abc
Program ended with exit code: 0
自行宣告字串來取代掉 printf 使用的 buffer,將要列印出的內容存入自行宣告的字串中。且不會列印出來。
#include <stdio.h>
int main(int argc, const char * argv[]) {
float f_1 = 3.14;
char output[20];
sprintf(output, "out = %f", f_1);
printf("%s\n", output); //印出output字串的內容
}
//output
out = 3.140000
Program ended with exit code: 0
s → string (已不再使用,因為gets沒有辦法限制輸入的長度,這可能導致緩衝區溢出,從而引發安全漏洞。)
char *fgets(char *str, int n, FILE *stream)
#include <stdio.h>
int main(int argc, const char * argv[]) {
printf("輸入字串:");
char str[10];
fgets(str, 10, stdin); //stdin: 從鍵盤輸入
printf("輸出字串:%s\n", str);
printf("%c, %d, %d\n", str[6], str[7], str[8]);
// str[7] 會輸出 10 對應到 ASCII table 為換行鍵,即 Enter 鍵
// 所以 str: a, b, c, , d, e, f, \n, \0
}
//output
輸入字串:abc def
輸出字串:abc def
f, 10, 0
Program ended with exit code: 0
#include <stdio.h>
int main(int argc, const char * argv[]) {
char str1[] = "I love coding.";
char str2[] = "And you?";
printf("printf的效果:\n");
printf("%s", str1);
printf("%s", str2);
printf("\nputs的效果:\n");
puts(str1);
puts(str2);
}
\\output
printf的效果:
I love coding.And you?
puts的效果:
I love coding.
And you?
Program ended with exit code: 0
int fputs(const char *str, FILE *stream)
#include <stdio.h>
int main(int argc, const char * argv[]) {
char str1[] = "I love coding.";
char str2[] = "And you?";
fputs(str1, stdout); // stdout: 印到螢幕上
fputs(str2, stdout);
printf("\n----------------------\n");
puts(str1);
puts(str2);
}
//output
I love coding.And you?
----------------------
I love coding.
And you?
Program ended with exit code: 0
c → char
int getc(FILE *stream) / int putc(int char, FILE *stream)
#include <stdio.h>
int main(int argc, const char * argv[]) {
char c;
c = getc(stdin);
putc(c, stdout); // 印出的是字元
printf("\n字元 %c 對應到ASCII code: %d\n", c, c);
}
//output
5
5
字元 5 對應到ASCII code: 53
Program ended with exit code: 0
getchar() = int getc(stdin) / putchar(int char) = int putc(int char, stdout)
#include <stdio.h>
int main(int argc, const char * argv[]) {
char c;
// c = getc(stdin);
c = getchar();
// putc(c, stdout);
putchar(c);
printf("\n字元 %c 對應到ASCII code: %d\n", c, c);
}
//output
5
5
字元 5 對應到ASCII code: 53
Program ended with exit code: 0
+ , - , * , / , % , & , | , ^ , ~ , << , >>
注意:浮點數不能取餘數 (%)
bit操作術語:pull hight: 0 → 1 / pull down: 1 → 0
#include <stdio.h>
int main(int argc, const char * argv[]) {
unsigned short hex = 0x55AA;
// 將 hex 的 bit_9 pull hight
unsigned short bit_9 = 0x01 << 9;
hex = hex | bit_9;
printf("result = %x\n", hex); // 57aa
// 再將 hex 還原成 55AA ,及對 hex 的 bit_9 pull down
hex = hex & ~bit_9;
printf("result = %x\n", hex); // 55aa
}
//output
result = 57aa
result = 55aa
Program ended with exit code: 0
>, >=, <, <=, ==, !=, !, &&, ||
#include <stdbool.h>
state | value | |
---|---|---|
True | 1 | |
False | 0 | s |
#include <stdio.h>
int main(int argc, const char * argv[]) {
int age;
scanf("%d", &age);
if (age <= 0 || age > 100) {
printf("請輸入正確的年齡\n");
}
else if (age < 13) {
printf("兒童票\n");
}
else if (age >= 13 && age < 65) {
printf("成人票\n");
}
else {
printf("敬老票\n");
}
return 0;
}
#include <stdio.h>
int main(int argc, const char * argv[]) {
int age;
scanf("%d", &age);
switch (age) {
case -10000 ... 0:
case 101 ... 9999:
printf("請輸入正確的年齡\n");
break; // 一般情況不可省略
case 1 ... 12: // 1 ~ 12
printf("兒童票\n");
break; // 一般情況不可省略
case 13 ... 64: // 13 ~ 64
printf("成人票\n");
break; // 一般情況不可省略
default: // other
printf("敬老票\n");
break; // 一般情況可省略,因為程式在進入到default時,也是準備要結束switch case
}
return 0;
}
#include <stdio.h>
int main(int argc, const char * argv[]) {
// 印九九乘法表
int i = 1;
int j = 1;
while (i <= 9) {
while (j <= 9) {
printf("%d * %d = %2d ", j, i, j * i);
j++;
}
j = 1;
i++;
printf("\n");
}
return 0;
}
//output
1 * 1 = 1 2 * 1 = 2 3 * 1 = 3 4 * 1 = 4 5 * 1 = 5 6 * 1 = 6 7 * 1 = 7 8 * 1 = 8 9 * 1 = 9
1 * 2 = 2 2 * 2 = 4 3 * 2 = 6 4 * 2 = 8 5 * 2 = 10 6 * 2 = 12 7 * 2 = 14 8 * 2 = 16 9 * 2 = 18
1 * 3 = 3 2 * 3 = 6 3 * 3 = 9 4 * 3 = 12 5 * 3 = 15 6 * 3 = 18 7 * 3 = 21 8 * 3 = 24 9 * 3 = 27
1 * 4 = 4 2 * 4 = 8 3 * 4 = 12 4 * 4 = 16 5 * 4 = 20 6 * 4 = 24 7 * 4 = 28 8 * 4 = 32 9 * 4 = 36
1 * 5 = 5 2 * 5 = 10 3 * 5 = 15 4 * 5 = 20 5 * 5 = 25 6 * 5 = 30 7 * 5 = 35 8 * 5 = 40 9 * 5 = 45
1 * 6 = 6 2 * 6 = 12 3 * 6 = 18 4 * 6 = 24 5 * 6 = 30 6 * 6 = 36 7 * 6 = 42 8 * 6 = 48 9 * 6 = 54
1 * 7 = 7 2 * 7 = 14 3 * 7 = 21 4 * 7 = 28 5 * 7 = 35 6 * 7 = 42 7 * 7 = 49 8 * 7 = 56 9 * 7 = 63
1 * 8 = 8 2 * 8 = 16 3 * 8 = 24 4 * 8 = 32 5 * 8 = 40 6 * 8 = 48 7 * 8 = 56 8 * 8 = 64 9 * 8 = 72
1 * 9 = 9 2 * 9 = 18 3 * 9 = 27 4 * 9 = 36 5 * 9 = 45 6 * 9 = 54 7 * 9 = 63 8 * 9 = 72 9 * 9 = 81
Program ended with exit code: 0
// 無窮迴圈寫法:
while(1) {
printf("in loop\n");
}
#include <stdio.h>
int main(int argc, const char * argv[]) {
// 印九九乘法表
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= 9; j++) {
printf("%d * %d = %2d ", j, i, j*i);
}
printf("\n");
}
return 0;
}
//output
1 * 1 = 1 2 * 1 = 2 3 * 1 = 3 4 * 1 = 4 5 * 1 = 5 6 * 1 = 6 7 * 1 = 7 8 * 1 = 8 9 * 1 = 9
1 * 2 = 2 2 * 2 = 4 3 * 2 = 6 4 * 2 = 8 5 * 2 = 10 6 * 2 = 12 7 * 2 = 14 8 * 2 = 16 9 * 2 = 18
1 * 3 = 3 2 * 3 = 6 3 * 3 = 9 4 * 3 = 12 5 * 3 = 15 6 * 3 = 18 7 * 3 = 21 8 * 3 = 24 9 * 3 = 27
1 * 4 = 4 2 * 4 = 8 3 * 4 = 12 4 * 4 = 16 5 * 4 = 20 6 * 4 = 24 7 * 4 = 28 8 * 4 = 32 9 * 4 = 36
1 * 5 = 5 2 * 5 = 10 3 * 5 = 15 4 * 5 = 20 5 * 5 = 25 6 * 5 = 30 7 * 5 = 35 8 * 5 = 40 9 * 5 = 45
1 * 6 = 6 2 * 6 = 12 3 * 6 = 18 4 * 6 = 24 5 * 6 = 30 6 * 6 = 36 7 * 6 = 42 8 * 6 = 48 9 * 6 = 54
1 * 7 = 7 2 * 7 = 14 3 * 7 = 21 4 * 7 = 28 5 * 7 = 35 6 * 7 = 42 7 * 7 = 49 8 * 7 = 56 9 * 7 = 63
1 * 8 = 8 2 * 8 = 16 3 * 8 = 24 4 * 8 = 32 5 * 8 = 40 6 * 8 = 48 7 * 8 = 56 8 * 8 = 64 9 * 8 = 72
1 * 9 = 9 2 * 9 = 18 3 * 9 = 27 4 * 9 = 36 5 * 9 = 45 6 * 9 = 54 7 * 9 = 63 8 * 9 = 72 9 * 9 = 81
Program ended with exit code: 0
// 無窮迴圈寫法:
for(;;) {
printf("in loop\n");
}
#include <stdio.h>
int main(int argc, const char * argv[]) {
// for迴圈特殊寫法:
int i, j, k;
for (i = 0, j = 0, k = 0; k <= 5; i++, j++, k++) {
printf("%2d %2d %2d\n", i, j, k);
}
return 0;
}
//output
0 0 0
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
Program ended with exit code: 0
#include <stdio.h>
int main(int argc, const char * argv[]) {
int int_array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i = 0; i < sizeof(int_array) / sizeof(int); i++) {
printf("%d, ", int_array[i]);
}
printf("\n");
return 0;
}
// output
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
Program ended with exit code: 0
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[]) {
char str[] = "Hello World!";
printf("str的長度(含 \\0):%zu\n", sizeof(str) / sizeof(char));
printf("str的長度(不含 \\0):%zu\n", strlen(str));
// 法一
for (int i = 0; i < strlen(str); i++) {
printf("%c, ", str[i]);
}
printf("\n");
// 法二
for (int i = 0; str[i] != 0; i++) { // 因為字串最後一個字元都是0
printf("%c, ", str[i]);
}
printf("\n");
return 0;
}
//output
str的長度(含 \0):13
str的長度(不含 \0):12
H, e, l, l, o, , W, o, r, l, d, !,
H, e, l, l, o, , W, o, r, l, d, !,
Program ended with exit code: 0
#include <stdio.h>
int main(int argc, const char * argv[]) {
int int_2Darray[][10] = {
{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},
};
int col_size = sizeof(int_2Darray[0]) / sizeof(int);
int row_size = (sizeof(int_2Darray) / sizeof(int)) / col_size;
printf("col_size = %d, row_size = %d\n", col_size, row_size);
for (int i = 0; i < row_size; i++) {
for (int j = 0; j < col_size; j++) {
printf("%2d, ", int_2Darray[i][j]);
}
printf("\n");
}
return 0;
}
//output
col_size = 10, row_size = 3
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,
Program ended with exit code: 0
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[]) {
char str2D[][11] = {
"JIMMY HSU",
"JEREMY LIN",
"WEBBER SU",
};
int col_size = sizeof(str2D[0]) / sizeof(char);
int row_size = sizeof(str2D) / sizeof(char) / col_size;
printf("col_size = %d, row_size = %d\n", col_size, row_size);
// 法一:多印了空格
for (int i = 0; i < row_size; i++) {
for (int j = 0; j < col_size; j++) {
printf("%c, ", str2D[i][j]);
}
printf("\n");
}
printf("--------------------------------\n");
// 法二
for (int i = 0; i < row_size; i++) {
for (int j = 0; j < strlen(str2D[i]); j++) {
printf("%c, ", str2D[i][j]);
}
printf("\n");
}
return 0;
}
//output
col_size = 11, row_size = 3
J, I, M, M, Y, , H, S, U, , ,
J, E, R, E, M, Y, , L, I, N, ,
W, E, B, B, E, R, , S, U, , ,
--------------------------------
J, I, M, M, Y, , H, S, U,
J, E, R, E, M, Y, , L, I, N,
W, E, B, B, E, R, , S, U,
Program ended with exit code: 0
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[]) {
int a = 1, b = 2;
if (a > b) goto point1;
else goto point2;
point1:
printf("point1:a > b\n");
return 0;
point2:
printf("point2:a <= b\n");
return 0;
}
//output:
point2:a <= b
Program ended with exit code: 0
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[]) {
int i = 0;
LOOP:
printf("%d\n", i);
if (i < 5) {
i++;
goto LOOP;
}
}
//output
0
1
2
3
4
5
Program ended with exit code: 0
#include <stdio.h>
#include <string.h>
void sayHi(char object[][50], int size) {
for (int i = 0; i < size; i++) {
printf("Hi, %s.I'm your dad!\n", object[i]);
}
}
int main(int argc, const char * argv[]) {
char friends[][50] = {
"Jimmy Xu",
"Jeremy Lin",
"Webber Su",
"Jack Liu"
};
int arr_size = sizeof(friends) / sizeof(char) / (sizeof(friends[0]) / sizeof(char));
sayHi(friends, arr_size);
return 0;
}
//output
Hi, Jimmy Xu.I'm your dad!
Hi, Jeremy Lin.I'm your dad!
Hi, Webber Su.I'm your dad!
Hi, Jack Liu.I'm your dad!
Program ended with exit code: 0
#include <stdio.h>
#include <stdbool.h>
bool isBigger(float a, float b){
return a > b;
}
int main(int argc, const char * argv[]) {
printf("%d\n", isBigger(10.5, 20));
return 0;
}
//output
0
Program ended with exit code: 0
#include <…> 用於新增系統目錄下的header檔,而#include "…"用於新增檔案目錄底下的header檔(自創的library)。
main.c (使用library中的function)
#include <stdio.h>
#include "myLibrary.h"
int main(int argc, const char * argv[]) {
char friends[][50] = {
"Jimmy Xu",
"Jeremy Lin",
"Webber Su",
"Jack Liu"
};
int arr_size = sizeof(friends) / sizeof(char) / (sizeof(friends[0]) / sizeof(char));
sayHi(friends, arr_size);
printf("%d\n", isBigger(10.5, 20));
}
//output
Hi, Jimmy Xu.I'm your dad!
Hi, Jeremy Lin.I'm your dad!
Hi, Webber Su.I'm your dad!
Hi, Jack Liu.I'm your dad!
0
Program ended with exit code: 0
myLibrary.h (負責宣告有哪些function)
#ifndef myLibrary_h
#define myLibrary_h
#include <stdbool.h>
void sayHi(char object[][50], int size);
bool isBigger(float a, float b);
#endif /* myLibrary_h */
myLibraby.c (負責實作myLibrary.h中的function)
#include <stdio.h>
#include "myLibrary.h"
void sayHi(char object[][50], int size) {
for (int i = 0; i < size; i++) {
printf("Hi, %s.I'm your dad!\n", object[i]);
}
}
bool isBigger(float a, float b){
return a > b;
}
注意:巨集不是變數,在執行期間不會被改變。當我們用 gcc 或 cl (Microsoft 開發工具裡頭的 C 編譯器) 編譯給定的 C 程式時,會呼叫 cpp (伴隨在 gcc 專案的 C preprocessor) 一類的程式,先行展開巨集 (macro) 或施加條件編譯等操作,再來才會出動真正的 C 語言編譯器 (在 gcc 中叫做 cc1)。
#include <stdio.h>
#define MAX_SIZE 10
#define ADD(x) (x + 1)
#define SUB_without_brackets(a, b) a - b // 括號陷阱
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int main(int argc, const char * argv[]) {
char students[MAX_SIZE];
printf("%zu\n", sizeof(students)); // 10
printf("%d\n", ADD(8)); // 9
printf("%d\n", SUB_without_brackets(21, 9)); // 12
printf("%d\n", MAX(21, 9)); // 21
// 括號陷阱
int res = 2 * SUB_without_brackets(20, 10) / 4; // 2 * 20 - 10 / 4 = 38
printf("%d\n", res); // 38
}
//output
10
9
12
38
21
Program ended with exit code: 0
## 相連符號
#include <stdio.h>
#define A(x) Value_##x
#define B(x, y) x##y
int main(int argc, const char * argv[]) {
int A(1) = 9;
int A(a) = 21;
printf("%d, %d\n", Value_1, Value_a);
int B(a, 1) = 21;
int B(b, 1) = 9;
printf("%d, %d\n", a1, b1);
}
//output
9, 21
21, 9
Program ended with exit code: 0
# 引入字串
#include <stdio.h>
#define A(x) #x
int main(int argc, const char * argv[]) {
char str[] = A(Hello World!);
printf("%s\n", str);
}
//output
Hello World!
Program ended with exit code: 0
\ 換行要加的
#include <stdio.h>
#define COMPARE(a, b, ans) \
if (a > b) ans = 1; \
else if (a < b) ans = 0; \
else ans = -1;
int main(int argc, const char * argv[]) {
int res;
int a = 21;
int b = 9;
COMPARE(a, b, res);
printf("%d\n", res);
}
//output
1
Program ended with exit code: 0
#if
#elif
#else
#endif
#include <stdio.h>
#define SWITCH 0
int main(int argc, const char * argv[]) {
// 反灰的部分等同於註解
#if SWITCH == 0
printf("offical_mode\n");
#elif SWITCH == 1
printf("develop_mode\n");
#else
printf("test_mode\n");
#endif
}
//output
offical_mode
Program ended with exit code: 0
#ifdef
#ifndef
#include <stdio.h>
#define MAJOR "CSIE"
int main(int argc, const char * argv[]) {
// 反灰的部分等同於註解
#ifdef MAJOR
printf("You have defined MAJOR!\n");
#else
printf("You haven't defined MAJOR!\n");
#endif
#ifndef SUBJECT
printf("You haven't defined SUBJECT!\n");
#else
printf("You have defined SUBJECT!\n");
#endif
}
//output
You have defined MAJOR!
You haven't defined SUBJECT!
Program ended with exit code: 0
就是把資料型別重新取名字
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned char uint8; //char -> 1 byte -> 8 bits
typedef unsigned short uint16; // short -> 2 bytes -> 16 bits
typedef unsigned int uint32; // int -> 4 btyes -> 32 bits
typedef unsigned long long uint64; // long long -> 8 bytes -> 64 bits
typedef char* String; // 字元陣列
#define STRING_COPY(s, x) strcpy(s, #x)
int main(int argc, const char * argv[]) {
uint8 a = 255;
printf("uint8_MAX = %u\n", a);
uint16 b = 65535;
printf("uint16_MAX = %u\n", b);
uint32 c = 4294967295;
printf("uint32_MAX = %u\n", c);
uint64_t d = 9223372036854775807;
printf("uint64_MAX = %llu\n", d);
String s = (String)malloc(50);
STRING_COPY(s, Hello World!); // strcpy(s, "Hello World!");
printf("%s\n", s);
}
//output
uint8_MAX = 255
uint16_MAX = 65535
uint32_MAX = 4294967295
uint64_MAX = 9223372036854775807
Hello World!
Program ended with exit code: 0
#include <stdio.h>
struct Student {
char name[50];
char major[30];
int age;
};
void show_student(struct Student student) {
printf("Name: %s\n", student.name);
printf("Major: %s\n", student.major);
printf("Age: %d\n", student.age);
}
int main(int argc, const char * argv[]) {
struct Student Jimmy = {"Jimmy", "Computer Science", 22}; // struct init
show_student(Jimmy);
printf("------------------------------\n");
// 對 struct 單一元素初始化
struct Student Jeremy = {.name = "Jeremy"};
show_student(Jeremy);
}
//output
Name: Jimmy
Major: Computer Science
Age: 22
------------------------------
Name: Jeremy
Major:
Age: 0
Program ended with exit code: 0
#include <stdio.h>
#include <string.h>
struct Student {
char name[50];
char major[30];
int age;
};
struct School {
char name[10];
float PR;
struct Student student;
};
void show_school(struct School school) {
printf("School: %s\n", school.name);
printf("PR: %f\n", school.PR);
printf("Student: %s\n", school.student.name);
printf("Major: %s\n", school.student.major);
printf("Age: %d\n", school.student.age);
}
int main(int argc, const char * argv[]) {
struct School NCKU = {"NCKU", 91.5, {"Jimmy", "Computer Science", 22}}; // struct init
show_school(NCKU);
/*NCKU.student.name = "Jeremy";*/ // error
strcpy(NCKU.student.name, "Jeremy");
printf("-------------------------\n");
show_school(NCKU);
}
//output
School: NCKU
PR: 91.500000
Student: Jimmy
Major: Computer Science
Age: 22
-------------------------
School: NCKU
PR: 91.500000
Student: Jeremy
Major: Computer Science
Age: 22
Program ended with exit code: 0
注意:字串只能在初始化時用 assign 的方式賦值,否則皆須用 strcpy() 來更改。
#include <stdio.h>
#include <string.h>
typedef struct {
char name[50];
char major[30];
int age;
} Student;
typedef struct {
char name[10];
float PR;
Student student;
} School;
int main(int argc, const char * argv[]) {
School NCKU = {"NCKU", 91.5, {"Jimmy GAY", "Computer Science", 22}}; // struct init
}
Compiler為了效能考量,會自動做最佳化,也就是資料對齊。
嚴格遵守以下步驟:
#include <stdio.h>
typedef struct {
int a;
char b;
char c;
} Size1;
typedef struct {
char b;
int a;
char c;
} Size2;
int main(int argc, const char * argv[]) {
printf("Size1: %zu bytes\nSize2: %zu bytes\n", sizeof(Size1), sizeof(Size2));
}
//output
Size1: 8 bytes
Size2: 12 bytes
Program ended with exit code: 0
橘色方塊的部分就是 padding bytes.
#include <stdio.h>
typedef struct {
char b;
char c;
double a;
} Size3;
typedef struct {
char b;
double a;
char c;
} Size4;
int main(int argc, const char * argv[]) {
printf("Size3: %zu bytes\nSize4: %zu bytes\n", sizeof(Size3), sizeof(Size4));
}
//output
Size3: 16 bytes
Size4: 24 bytes
Program ended with exit code: 0
#include <stdio.h>
typedef struct{
unsigned char bit0: 1; // 控制 1 個 bit
unsigned char bit1: 1;
unsigned char bit2: 1;
unsigned char bit3: 1;
unsigned char bit4: 1;
unsigned char bit5: 1;
unsigned char bit6: 1;
unsigned char bit7: 1;
} BitFieldsChar;
int main(int argc, const char * argv[]) {
// 對 char_8 的每一個 bit 初始化
BitFieldsChar char_8 = {0, 0, 0, 0, 0, 0, 0, 0};
// 將第 4 個 bit 設成 1 (即 char_8 -> 00001000 = 8)
char_8.bit3 = 1;
printf("%d\n", *((unsigned char*)&char_8));
}
//output
8
Program ended with exit code: 0
語法與 struct 相同,但運作邏輯不同。union 的記憶體是共用的。如下圖所示:
因此,不論初始化 union 中的哪一個元素,都只會有一個元素被儲存,使 union 能夠支援多種不同的資料型別(多型)。
#include <stdio.h>
typedef union{
int a;
float b;
char c;
} Sample;
int main(int argc, const char * argv[]) {
Sample s = {65, 15.3, 'a'};
printf("%d %f %c\n", s.a, s.b, s.c);
}
//output
65 0.000000 A
Program ended with exit code: 0
取 union 中 size 最大的元素作為 union 的 size。
#include <stdio.h>
typedef union{
int a; // 4 bytes
float b; // 4 bytes
char c; // 1 bytes
} Size1; // -> 4 bytes
typedef union{
int a; // 4 bytes
double b; // 8 bytes
char c; // 1 bytes
} Size2; // -> 8 bytes
int main(int argc, const char * argv[]) {
printf("Size1 = %zu\nSize2 = %zu\n", sizeof(Size1), sizeof(Size2));
}
//output
Size1 = 4
Size2 = 8
Program ended with exit code: 0
#include <stdio.h>
#include <string.h>
typedef union{
int a;
float b;
char c[20];
} Polymorphism; // -> Size = 20 bytes
int main(int argc, const char * argv[]) {
Polymorphism p;
p.a = 10;
printf("%d\n", p.a);
p.b = 15.3;
printf("%f\n", p.b);
strcpy(p.c, "Hello World!");
printf("%s\n", p.c);
}
//output
10
15.300000
Hello World!
Program ended with exit code: 0
#include <stdio.h>
#include <string.h>
typedef union{
unsigned int total;
char detail[4]; // id, majorNum, score, clubNum
} Student; // Size -> 4 Bytes
int main(int argc, const char * argv[]) {
Student Jimmy;
Jimmy.detail[0] = 9;
Jimmy.detail[1] = 21;
Jimmy.detail[2] = 90;
Jimmy.detail[3] = 7;
printf("%d\n", Jimmy.total);
}
//output
123344137
Program ended with exit code: 0
#include <stdio.h>
#include <string.h>
typedef union{
unsigned int total;
struct {
char id;
char majorNum;
char score;
char clubNum;
};
} Student; // Size -> 4 Bytes
int main(int argc, const char * argv[]) {
Student Jimmy;
Jimmy.id = 9;
Jimmy.majorNum = 21;
Jimmy.score = 90;
Jimmy.clubNum = 7;
printf("%d\n", Jimmy.total);
}
//output
123344137
Program ended with exit code: 0
#include <stdio.h>
#include <string.h>
typedef union {
char header;
struct {
unsigned char bit0: 1;
unsigned char bit1: 1;
unsigned char bit2: 1;
unsigned char bit3: 1;
unsigned char bit4: 1;
unsigned char bit5: 1;
unsigned char bit6: 1;
unsigned char bit7: 1;
};
} ControlBits;
int main(int argc, const char * argv[]) {
ControlBits cb;
cb.header = 0; // init
// cb.header |= 0x01 << 3;
cb.bit3 = 1;
printf("pull high bit3 -> %d\n", *((unsigned char*)&cb.header));
// cb.header &= ~(0x01 << 3);
cb.bit3 = 0;
printf("then, pull down bit3 -> %d\n", *((unsigned char*)&cb.header));
}
//output
pull high bit3 -> 8
then, pull down bit3 -> 0
Program ended with exit code: 0
程式碼要盡量避免使用缺乏解釋或命名的數值,又稱Magic Number,而 enum 通常就是用來取代 Magic Number,目的是為了增加程式碼的可讀性。
#include <stdio.h>
typedef enum {
Monday, // 0
Tuesday, // 1
Wednesday, // 2
Thursday = 10, // 以下的枚舉會從 10 開始累加
Friday, // 11
Saturday, // 12
Sunday, // 13
} DAY;
int main(int argc, const char * argv[]) {
DAY today = Sunday;
printf("Today is Sunday: %d\n", today);
printf("%d\n", Wednesday);
printf("%d\n", Thursday);
printf("%d\n", Friday);
}
//output
Today is Sunday: 13
2
10
11
Program ended with exit code: 0
#include <stdio.h>
typedef enum {
Monday, // 0
Tuesday, // 1
Wednesday, // 2
Thursday, // 3
Friday, // 4
Saturday, // 5
Sunday, // 6
MAX, // 7 統計共有多少枚舉
} DAY;
int main(int argc, const char * argv[]) {
char TODO[][30] = {
"go swimming",
"play basketball",
"play volleyball",
"play piano",
"go hiking",
"go on a trip",
"go camping"
};
DAY today = Sunday;
printf("Today: %s\n", TODO[today]);
for (int i = 0; i < MAX; i++) {
printf("%s\n", TODO[i]);
}
}
//output
Today: go camping
go swimming
play basketball
play volleyball
play piano
go hiking
go on a trip
go camping
Program ended with exit code: 0
指標大小: 4 bytes(電腦為 32-bits) 或 8 bytes(電腦為 64-bits),不論什麼型態的指標 size 皆相同。
指標是一個變數,用來儲存某個記憶體位址,而這個位址通常是某個變數在記憶體的位置。
#include <stdio.h>
int a = 1; // global variable
void foo(void) {
static int b = 9; // static variable
int c = 21; // local variable
int* a_ptr = &a; // 指標 a_ptr 指向 a 的位址
int* b_ptr = &b;
int* c_ptr = &c;
printf("%p %p %p\n", a_ptr, b_ptr, c_ptr); // 印出指標指向的位址
printf("%p %p %p\n", &a, &b, &c); // 印出 a b c 變數對應的位址
printf("%d %d %d\n", *a_ptr, *b_ptr, *c_ptr); // 印出指標所指位址中的值
(*a_ptr) ++; // a++;
(*b_ptr) ++; // b++;
(*c_ptr) ++; // c++;
printf("%d %d %d\n", *a_ptr, *b_ptr, *c_ptr);
}
int main(int argc, const char * argv[]) {
foo();
}
// output
0x100008000 0x100008004 0x16fdff2bc
0x100008000 0x100008004 0x16fdff2bc
1 9 21
2 10 22
Program ended with exit code: 0
#include <stdio.h>
void swap(int* a, int* b) {
int tmp = *a; // 將位址 a 中的值取出存入 tmp 中
*a = *b; // 再將位址 b 中的值存入位址 a 中
*b = tmp; // 最後,將 tmp 的值存入位址 b 中
}
int main(int argc, const char * argv[]) {
int a = 9;
int b = 21;
printf("Before: a = %d, b = %d\n", a, b);
swap(&a, &b); // 傳入a, b的位址
printf("After: a = %d, b = %d\n", a, b);
}
//output
Before: a = 9, b = 21
After: a = 21, b = 9
Program ended with exit code: 0
顧名思義就是用來指著指標的指標
原本的程式碼
void remove_list_node(List *list, Node *target)
{
Node *prev = NULL;
Node *current = list->head;
// Walk the list
while (current != target) {
prev = current;
current = current->next;
}
// Remove the target by updating the head or the previous node.
if (!prev)
list->head = target->next;
else
prev->next = target->next;
}
有「品味」的版本
void remove_list_node(List *list, Node *target)
{
// The "indirect" pointer points to the *address*
// of the thing we'll update.
Node **indirect = &list->head;
// Walk the list, looking for the thing that
// points to the node we want to remove.
while (*indirect != target)
indirect = &(*indirect)->next;
*indirect = target->next;
}
目的:透過「間接指標」來避免「多」判斷 edge case。
無論指標的型別,其 size 皆為 8 bytes (64-bit OS) or 4 bytes (32-bit OS)
#include <stdio.h>
int main(int argc, const char * argv[]) {
printf("%zu %zu %zu\n", sizeof(int*), sizeof(char*), sizeof(double*));
}
//output
8 8 8
Program ended with exit code: 0
malloc() 創造出的空間會存放在 Heap,直到執行 free() 後該空間才會被釋放。另外,free() 只能對儲存在 Heap 區的資料使用。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
int* pi; // 宣告整數指標 pi
pi = (int*)malloc(sizeof(int)); // pi 指向新配置的動態記憶體位址
*pi = 5; // 於動態記憶體位址中存入5
printf("pi指標存放的記憶體位址:%p\npi動態配置的記憶體位址(即pi的內容):%p\npi指向之記憶體位址中的內容為:%d\n", &pi, pi, *pi);
}
//output
pi指標存放的位址:0x16fdff2c8
pi動態配置的位址(即pi的內容):0x6000021940e0
pi指向之記憶體位址中的內容為:5
Program ended with exit code: 0
記憶體內容如下所示:
記憶體位址 | 存放的內容 | 記憶體區塊 | 變數 |
---|---|---|---|
0x6000021940e0 | 5 | Heap | *pi |
0x16fdff2c8 | 0x6000021940e0 | Stack | pi |
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
int* pi; // 宣告整數指標 pi
pi = (int*)malloc(sizeof(int)); // pi 指向新配置的動態記憶體位址
*pi = 5; // 於動態記憶體位址中存入5
printf("pi指標存放的記憶體位址:%p\tpi動態配置的記憶體位址(即pi的內容):%p\tpi指向之記憶體位址中的內容為:%d\t", &pi, pi, *pi);
// 釋放 pi 所指向的記憶體空間
free(pi);
printf("pi指標存放的記憶體位址:%p\tpi動態配置的記憶體位址(即pi的內容):%p\tpi指向之記憶體位址中的內容為:%d\t", &pi, pi, *pi);
}
// output
pi指標存放的記憶體位址:0x16fdff2c8 pi動態配置的記憶體位址(即pi的內容):0x600000668060 pi指向之記憶體位址中的內容為:5
pi指標存放的記憶體位址:0x16fdff2c8 pi動態配置的記憶體位址(即pi的內容):0x600000668060 pi指向之記憶體位址中的內容為:710836320
Program ended with exit code: 0
可以發現,雖然 pi 仍指向原本存放 5 的記憶體位址,但其內容已經被存入其他數值了!(被作業系統視為已釋放的記憶體區塊)
記憶體位址 | 存放的內容 | 記憶體區塊 | 變數 |
---|---|---|---|
0x600000668060 | 710836320 | Heap | *pi |
0x16fdff2c8 | 0x600000668060 | Stack | pi |
發生原因:因為程式在動態分配記憶體後沒有正確地釋放它。
在使用 malloc、calloc 或 realloc 等函數分配記憶體時,會得到一個指向某記憶體區域的指標。如果這個指針在使用過程中被覆蓋掉,且原本的記憶體區域沒有被釋放,那麼這部分記憶體就會變成「失去指標的記憶體」,即稱記憶體洩漏。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
// 第一次分配
int* pi = (int*)malloc(sizeof(int));
// 第二次分配,第一次分配的記憶體現在已經沒有指標指向它了
pi = (int*)malloc(sizeof(int));
free(pi); // 只會釋放第二次分配的記憶體,第一次分配的記憶體依然還存在,這就是記憶體洩漏。
}
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
int* pi = (int*)malloc(sizeof(int));
*pi = 5;
free(pi);
*pi = 10; // pi 指向的記憶體空間已被釋放,但又在存取該記憶體空間。
}
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
int* pi = NULL;
if (pi == NULL) { // 若 pi 尚未指向任何記憶體空間
pi = (int*)malloc(sizeof(int)); // 才 malloc 記憶體空間給 pi
}
*pi = 5;
if (pi != NULL) { // 若尚未釋放 pi 所指向之記憶體空間
free(pi); // 則釋放 pi 所指向之記憶體空間
pi = NULL;
}
}
全域指標與靜態指標是無法直接初始化的,要先將指標指派為NULL,再初始化。另外,全域指標只能在函數中指派。
#include <stdio.h>
#include <stdlib.h>
int* global = NULL;
void pointer_init(int** p) {
if (*p == NULL) {
*p = (int*)malloc(sizeof(int));
}
printf("pointer_address: %p\n", *p);
}
void pointer_free(int** p) {
if (*p != NULL && p != NULL) {
free(*p);
*p = NULL;
}
printf("pointer_address: %p\n", *p);
}
int main(int argc, const char * argv[]) {
pointer_init(&global);
pointer_init(&global); // 與第一次init的位址一樣
pointer_free(&global);
static int* s_pointer = NULL;
pointer_init(&s_pointer);
pointer_init(&s_pointer); // 與第一次init的位址一樣
pointer_free(&s_pointer);
}
//output
pointer_address: 0x600000e94080
pointer_address: 0x600000e94080
pointer_address: 0x0
pointer_address: 0x600000e94080
pointer_address: 0x600000e94080
pointer_address: 0x0
Program ended with exit code: 0
陣列名稱即為指向該陣列首位元素之指標。
#include <stdio.h>
int main(int argc, const char * argv[]) {
int arr[] = {1, 2, 3, 4, 5};
// arr[1] 即 *(arr + 1)
printf("%d\n", arr[1]);
printf("%d\n", *(arr + 1));
// &arr[1] 即 arr + 1
printf("%p\n", &arr[1]);
printf("%p\n", arr + 1);
int* arr_ptr = arr;
for (int i = 0; i < 5; i++) {
printf("%d, ", *(arr_ptr + i));
}
printf("\n");
}
// output
2
2
0x16fdff274
0x16fdff274
1, 2, 3, 4, 5,
Program ended with exit code: 0
#include <stdio.h>
int main(int argc, const char * argv[]) {
int matrix[][3] = {
{1, 2, 3},
{4, 5, 6}
};
// matrix[1][1] 即 *(*(matrix + 1) + 1)
printf("%d\n", matrix[1][1]);
printf("%d\n", *(*(matrix + 1) + 1));
// &matrix[1][1] 即 *(matrix + 1) + 1 或 matrix[1] + 1
printf("%p\n", &matrix[1][1]);
printf("%p\n", *(matrix + 1) + 1);
printf("%p\n", matrix[1] + 1);
int (*matrix_ptr)[3] = matrix; // 宣告二維陣列的指標
int* ptr1D = matrix_ptr[0]; // matrix_ptr[0] 即 matrix[0]
for (int i = 0; i < 6; i++) {
printf("%d, ", *(ptr1D + i));
}
printf("\n");
}
//output
5
5
0x16fdff280
0x16fdff280
0x16fdff280
1, 2, 3, 4, 5, 6,
Program ended with exit code: 0
#include <stdio.h>
void set_1Darr_val(int* arr, int size, int val) {
for(int i = 0; i < size; i++) {
arr[i] = val;
}
}
void set_2Darr_val(int (*arr)[3], int row, int col, int val) {
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
arr[i][j] = val;
}
}
}
int main(int argc, const char * argv[]) {
int arr1D[] = {1, 2, 3, 4, 5};
printf("Brfore: %d, %d, %d, %d, %d\n", arr1D[0], arr1D[1], arr1D[2], arr1D[3], arr1D[4]);
set_1Darr_val(arr1D, 5, 21);
printf("After: %d, %d, %d, %d, %d\n", arr1D[0], arr1D[1], arr1D[2], arr1D[3], arr1D[4]);
int arr2D[][3] = {
{1, 2, 3},
{4, 5, 6}
};
printf("Brfore: %d, %d, %d, %d, %d, %d\n", arr2D[0][0], arr2D[0][1], arr2D[0][2], arr2D[1][0], arr2D[1][1], arr2D[1][2]);
set_2Darr_val(arr2D, 2, 3, 21);
printf("After: %d, %d, %d, %d, %d, %d\n", arr2D[0][0], arr2D[0][1], arr2D[0][2], arr2D[1][0], arr2D[1][1], arr2D[1][2]);
}
//output
Brfore: 1, 2, 3, 4, 5
After: 21, 21, 21, 21, 21
Brfore: 1, 2, 3, 4, 5, 6
After: 21, 21, 21, 21, 21, 21
Program ended with exit code: 0
#include <stdio.h>
#include <stdlib.h>
void set_1Darr_val(int* arr, int size, int val) {
for(int i = 0; i < size; i++) {
arr[i] = val;
}
}
int main(int argc, const char * argv[]) {
int* vector1D = (int*)malloc(sizeof(int) * 5);
set_1Darr_val(vector1D, 5, 9);
printf("%d, %d, %d, %d, %d\n", vector1D[0], vector1D[1], vector1D[2], vector1D[3], vector1D[4]);
}
//output
9, 9, 9, 9, 9
Program ended with exit code: 0
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
int row = 2;
int col = 3;
int** vector2D = (int**)malloc(sizeof(int*) * row); // vector2D[row][col]
// 配置各 col
vector2D[0] = (int*)malloc(sizeof(int) * col);
// *(vector2D + 0) = (int*)malloc(sizeof(int) * col);
vector2D[1] = (int*)malloc(sizeof(int) * col);
// *(vector2D + 1) = (int*)malloc(sizeof(int) * col);
// print
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
printf("%p, ", &vector2D[i][j]);
}
printf("\n");
}
}
//output (第一列到第二列的位址沒有連續)
0x6000034cc090, 0x6000034cc094, 0x6000034cc098,
0x6000034cc0a0, 0x6000034cc0a4, 0x6000034cc0a8,
Program ended with exit code: 0
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
int row = 3;
int col = 3;
int** vector2D = (int**)malloc(sizeof(int*) * row); // vector2D[row][col]
*(vector2D) = (int*)malloc(sizeof(int) * row * col);
for (int i = 0; i < row; i++) {
// *(vector2D + i) = *(vector2D) + col * i;
vector2D[i] = vector2D[0] + col * i;
}
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
printf("%p, ", &vector2D[i][j]);
}
printf("\n");
}
}
// output
0x600000f14450, 0x600000f14454, 0x600000f14458,
0x600000f1445c, 0x600000f14460, 0x600000f14464,
0x600000f14468, 0x600000f1446c, 0x600000f14470,
Program ended with exit code: 0
#include <stdio.h>
#include <stdlib.h>
void setArrayValue(int *arr, int size, int value) {
for (int i = 0; i < size; i++) {
arr[i] = value;
}
}
int *mallocArray(int size) {
int *arr = (int *)malloc(sizeof(int) * size);
return arr;
}
int main() {
int *arr = mallocArray(5);
setArrayValue(arr, 5, 9);
for (int i = 0; i < 5; i++) {
printf("%d\n", arr[i]);
}
}
#include <stdio.h>
#include <stdlib.h>
void setArrayValue(int *arr, int size, int value) {
for (int i = 0; i < size; i++) {
arr[i] = value;
}
}
void mallocArray(int **arr, int size) {
*arr = (int *)malloc(sizeof(int) * size);
}
int main() {
int *array1D = NULL;
mallocArray(&array1D, 5);
setArrayValue(array1D, 5, 21);
for (int i = 0; i < 5; i++) {
printf("%d\n", array1D[i]);
}
}
在上述程式碼中,arr 存的內容會是 &array1D (array1D的位址),所以 *arr 就會是 array1D,再透過 *arr 來修改 array1D 的內容。而傳入 mallocArray
的參數為一個陣列,又陣列名 array1D 同為指標,故在 mallocArray
函數中需使用 指標的指標(**) 來傳遞參數。
變數 | 記憶體位址 | 存放的內容 | 註 |
---|---|---|---|
arr(指標的指標) | 0xb0b8 | 0xb0f8 | 指向 array1D 的指標 |
*arr | 0xb0f8 | 0x0 | array1D 的替身 |
array1D | 0xb0f8 | 0x0 | array1D 本身就是整數指標 |
#include <stdio.h>
#include <stdlib.h>
void set2DarrayValue(int **arr, int row, int col, int value) {
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
arr[i][j] = value;
}
}
}
int** malloc2Darray(int row, int col) {
int** arr = (int **)malloc(sizeof(int) * row);
for (int i = 0; i < row; i++) {
arr[i] = (int *)malloc(sizeof(int) * col);
}
return arr;
}
int main() {
int row = 2;
int col = 3;
int** arr = malloc2Darray(row, col);
set2DarrayValue(arr, row, col, 21);
// print
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
printf("%d ", *(*(arr + i) + j));
}
printf("\n");
}
}
#include <stdio.h>
#include <stdlib.h>
void set2DarrayValue(int **arr, int row, int col, int value) {
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
arr[i][j] = value;
}
}
}
void malloc2Darray(int*** arr, int row, int col) {
*arr = (int **)malloc(sizeof(int) * row);
for (int i = 0; i < row; i++) {
*(*arr + i) = (int *)malloc(sizeof(int) * col);
}
}
int main() {
int row = 2;
int col = 3;
int** arr = NULL;
malloc2Darray(&arr, row, col);
set2DarrayValue(arr, row, col, 21);
// print
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
printf("%d ", *(*(arr + i) + j));
}
printf("\n");
}
}
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int id;
char name[7];
} Zoo;
int main() {
Zoo z1 = {1, "tiger"};
Zoo* zPtr = &z1;
printf("animal id: %d\nanimal name: %s\n", z1.id, z1.name);
printf("animal id: %d\nanimal name: %s\n", (*zPtr).id, (*zPtr).name);
printf("animal id: %d\nanimal name: %s\n", zPtr->id, zPtr->name);
}
// output
animal id: 1
animal name: tiger
animal id: 1
animal name: tiger
animal id: 1
animal name: tiger
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int id;
char name[7];
} Zoo;
int main() {
Zoo z[3] = {{1, "Monkey"}, {2, "Donkey"}, {3, "Horse"}};
Zoo* ptr = z;
for (int i = 0; i < sizeof(z) / sizeof(Zoo); i++) {
printf("animal_id : %d, animal_name : %s\n", (*(ptr + i)).id, (*(ptr + i)).name);
printf("animal_id : %d, animal_name : %s\n", (ptr + i)->id, (ptr + i)->name);
printf("animal_id : %d, animal_name : %s\n", ptr[i].id, ptr[i].name);
}
}
// output
animal_id : 1, animal_name : Monkey
animal_id : 1, animal_name : Monkey
animal_id : 1, animal_name : Monkey
animal_id : 2, animal_name : Donkey
animal_id : 2, animal_name : Donkey
animal_id : 2, animal_name : Donkey
animal_id : 3, animal_name : Horse
animal_id : 3, animal_name : Horse
animal_id : 3, animal_name : Horse
#include <stdio.h>
#include <stdlib.h>
#pragma pack(1)
typedef struct {
int id;
char name[7];
} Zoo;
#pragma pack()
int main() {
unsigned char data[] = {1, 0, 0, 0, 68, 111, 103, 0, 1, 2, 3, 2, 0, 0, 0, 82, 97, 98, 98, 105, 116, 0};
Zoo* ptr = data;
printf("%d, %s\n", ptr->id, ptr->name);
printf("ptr_point : %d\n", ptr);
printf("%d, %s\n", (ptr + 1)->id, (ptr + 1)->name);
printf("ptr_point : %d\n", ptr + 1);
}
// output
1, Dog
ptr_point : 1864872080
2, Rabbit
ptr_point : 1864872091
首先,到底 #pragma pack(對齊的單位)
是做什麼的?其實 #pragma pack(對齊的單位)
就是要 compiler 照我們的意思去做記憶體 aligment(對齊)的工作,在 32 位元的系統下為了提高記憶體存取效率,所以記憶體配置(對齊)的預設值是以 DWORD(4BYTES 也就是 32 bits )為單位,因此在配置 struct 的記憶體空間的時候,往往會造成 struct 內部的資料在記憶體位址上並不連續,在我們的程式之中,如果不是用指標去存取這些資料,可能還不會出錯,可是如果我們真的用指標去存取的話,由於資料排列不連續,我們可能就會讀不到我們想要的值。
#include <stdio.h>
#include <stdlib.h>
typedef struct {
unsigned int bit_1: 2; // 控制最右邊的兩個 Bit
unsigned int bit_2: 1;
unsigned int bit_3: 3;
} Bitfields;
int main() {
int test = 59; // 111011 = 59
Bitfields *bit = &test;
/**
* ---------- test ---------
* | 111 | 0 | 11 |
* ------------------------
* | bit_3 | bit_2 | bit_1 |
* -------------------------
*/
bit->bit_2 = 1; // 111 1 11 = 63
printf("%d\n", test);
bit->bit_3 = 2; // 010 1 11 = 23
printf("%d\n", test);
bit->bit_1 = 2; // 010 1 10 = 22
printf("%d\n", test);
}
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int d1;
float d2;
} Data;
int main() {
// Create an Array, which datatype is Data.
Data* dataArray = (Data *)malloc(sizeof(Data) * 3);
// Initialize Array
dataArray[0].d1 = 9;
dataArray[0].d2 = 21;
(*(dataArray + 1)).d1 = 8;
(*(dataArray + 1)).d2 = 20;
(dataArray + 2)->d1 = 7;
(dataArray + 2)->d2 = 19;
// print
for (int i = 0; i < 3; i++) {
printf("%d, %f\n", dataArray[i].d1, dataArray[i].d2);
}
}
// output
9, 21.000000
8, 20.000000
7, 19.000000
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int d1;
float d2;
} Data;
void mallocData(Data** data) {
*data = (Data*)malloc(sizeof(Data));
}
void setDataValue(Data* data, int a, float b) {
data->d1 = a;
data->d2 = b;
}
int main() {
Data* ptr = NULL;
mallocData(&ptr);
setDataValue(ptr, 9, 21);
printf("%d, %f\n", ptr->d1, ptr->d2);
}
// output
9, 21.000000
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node {
char* name;
int price;
struct Node* next;
} Node_t;
Node_t* createNode(char* name, int price) {
Node_t* i = (Node_t*)malloc(sizeof(Node_t));
i->name = name;
i->price = price;
i->next = NULL;
return i;
}
void deleteNode(Node_t** head, char* name) {
Node_t* cur = *head;
Node_t* pre = NULL;
while (cur) {
if (strcmp(cur->name, name)) { // Not equal
pre = cur;
cur = cur->next;
}
else { // Equal
if (pre) { // cur not i1
pre->next = cur->next;
}
else { // cur is i1
*head = cur->next;
}
printf("Island %s has been delete.\n", cur->name);
free(cur);
return;
}
}
printf("Island %s is not exist!\n", name);
}
void insertNodeAtTail(Node_t **head, char* name, int price) {
Node_t *newData = createNode(name, price);
Node_t *cur = *head;
if (!(*head)) {
*head = newData;
}
while(cur->next) {
cur = cur->next;
}
cur->next = newData;
}
void insertNodeAtHead(Node_t **head, char* name, int price) {
Node_t *newData = createNode(name, price);
newData->next = *head;
*head = newData;
}
void print(Node_t *head) {
Node_t *cur = head;
while (cur) {
printf("%s %d ", cur->name, cur->price);
cur = cur->next;
}
printf("\n");
}
int main() {
Node_t* head = NULL;
Node_t* head2 = NULL;
Node_t* i1 = createNode("i1", 600);
Node_t* i2 = createNode("i2", 900);
Node_t* i3 = createNode("i3", 300);
head = i1;
i1->next = i2;
i2->next = i3;
deleteNode(&head, "i1");
insertNodeAtHead(&head, "i5", 200);
insertNodeAtTail(&head, "i4", 100);
print(head);
insertNodeAtHead(&head2, "i1", 10);
insertNodeAtTail(&head2, "i2", 20);
print(head2);
}
// output
Island i1 has been delete.
i5 200 i2 900 i3 300 i4 100
i1 10 i2 20