C99 [6.3.2.1] An lvalue is an expression with an object type or an incomplete type other than void;
C99 [3.14]:region of data storage in the execution environment, the contents of which can represent values
struct example *ptr;
、int a[]
C99[6.2.5] Types are partitioned into object types (types that fully describe objects), function types (types that describe functions), and incomplete types (types that describe objects but lack information needed to determine their sizes).
練習:
int a = 10;
int *E = &a;
++(*E); // a = a + 1
++(a++); // error
ref: [Note] 你所不知道的 C 語言:開發工具和規格標準篇
ref: 參考來源
struct 稱為結構體,可以包含數個不同資料型態的變數,所有變數佔用不同的內存。
union 稱為聯合體,也可以包涵不同資料型態的變數,但是所有變數佔用相同內存。
C11 [6.7] Declarations
Declaration
A declaration specifies the interpretation and attributes of a set of identifiers.
Definition
A definition of an identifier is a declaration for that identifier that:
for an object, causes storage to be reserved for that object;
for a function, includes the function body;
for an enumeration constant or typedef name, is the (only) declaration of the identifier.
對 variable 來說,declaration 僅是標示了 variable 的名稱和特性,definition 才會真正分配對應的儲存空間。
對 function 來說,definition 會包含 body { },而 declaration 不會。
此外,相同 variable 可以多次 declaration,但是 definition 只能有一次。
ref: C extern keyword
// Macro是在預處理時直接單純的文字替換,inline function是在compile階段時,直接取代function。
// 比較下面兩個例子:
// inline寫法:
inline int square(int x) {
return x * x;
}
output: SQUARE(3 + 2) → (3 + 2) * (3 + 2) = 25
// Macro寫法:
#define SQUARE(x) (x * x)
output: SQUARE(3 + 2) → 3 + 2 * 3 + 2 = 11
const 代表只可讀不可改。
1. 一個常數型整數
2. 同 1,一個常數型整數
3. 一個指向常數型整數的指標 (整型數不可修改,但指標可以)
4. 一個指向整數的常數型指標 (指標指向的整數可以修改,但指標不可修改)
5. 一個指向常數型整數的常數型指標 (指標指向的整數不可修改,同時指標也不可修改)
int square(volatile int *ptr)
{
return *ptr * *ptr;
}
volatile 用於提示編譯器某個變數會被意想不到的改變,如外部硬體或是其他的實行緒,因此不可對該變數進行優化,需要重新自記憶體存取該變數的值。
ref: Why is volatile needed in C?
ref: Why is a point-to-volatile pointer, like "volatile int * p", useful?
1. static 出現在變數前,且該變數宣告於函式中 (C/C++):
局部變數加上 static 修飾後便不會因為離開可視範圍而消失。
2. static 出現在變數前,且該變數不是宣告於函式中(C/C++):
讓變數只限定在該檔案內,而不是整個程式中(解決編譯時連結多個檔案造成相同變數名衝突)。
3. static 出現在類別的成員變數前 (C++ only):
表示該變數不屬於某個類別實例,他屬於這個類別,所有以此類別生成出來的實例都共用這個變數。
4. static 出現在類別的成員函式之前 (C++ only):
表示該函式不屬於某個類別實例,他屬於這個類別,所有以此類別生成出來的實例都共用這個函式(即便我們沒有產生實例出來,我們也隨時可以取用這個函式)(同 python 的 @static method)。
extern 可放在變數或是函數前,提示編譯器該變數或是參數的定義在其他檔案。
ref: C extern keyword
ref: 面试挖坑题(6)之c语言extern
char a[6];
extern char *a;
不正確,因為 B.c 中 extern char *a;
宣告的是一個 pointer to char,與 A.c 中實際定義的 char array 型態不同。
void(*(*papf)[3])(char *);
typedef_______;
pf (*papf)[3];
papf is a pointer to array of "pointer to function return void"
papf is a pointer to array of "pf"
pf is a pointer to function return void
--> typedef void(*pf)(char *);
int a[5]={1,2,3,4,5};
int *p=a;
*(p++)+=123;
*(++p)+=123;
int a[5]={1,2,3,4,5};
int *p=a; // p is the pointer to the a[5]
*(p++)+=123; // -> *p += 123; p+=1;-> a[0] = 124; p = a + 1;
*(++p)+=123; // -> p+=1; !p+=123;-> a[2] = 126; p = a + 2;
int a;//1
int *a;//2
int **a;//3
int a[10];//4
int* a[10];//5
int a[10];//
int *b = a;//6
int (*func)(int);//7
int (*func[10])(int);//8
int a[10]; int *b[10]; int (*c)[10];
分別代表什麼意思?
int a[10]; // an array of 10 integers
int *b[10]; // an array of 10 pointers to integer
int (*c)[10]; // a pointer to an array of 10 integers
a++, b++ 會發生錯誤,因為 a 與 b 為陣列的開頭位置,不可被更改。
#define SET(num, i) num |= 1<<i
#define CLEAR(num, i) num &= ~(1<<i)
#define INVERSE(num, i) num ^= 1<<i
int check(int n) {
while(n > 0) {
n -= 3;
}
if (n == 0) return 1;
else return 0;
}
void swap(int *a, int *b) {
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
void swap(char *a, char *b) {
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
void reverse(char s[]) {
int n = strlen(s);
for (int i = 0; i < n/2; i++) {
swap(&s[i], &s[n-i-1]);
}
}
int define2N(int n){
return (!(n&n-1) && n!=0)
}
// Ex. n = 11000 n-1 = 10111 n&n-1 > 0
int gcd(int x, int y) {
int max, min, mod;
max = x > y ? x : y;
min = x < y ? x : y;
do {
mod = max%min;
max = min;
min = mod;
}while (mod);
return max;
}
w/o mod()
#include <stdint.h>
uint64_t gcd64(uint64_t u, uint64_t v)
{
if (!u || !v) return u | v;
// 若 u 跟 v 都是偶數,則:gcd(u,v)=2×gcd(u/2,v/2)
int shift;
for (shift = 0; !((u | v) & 1); shift++) {
u /= 2, v /= 2;
}
// 若 u 為偶數,v 為奇數,則:gcd(u, v) = gcd(u/2, v)
while (!(u & 1))
u /= 2;
do {
while (!(v & 1))
v /= 2;
// gcd(u, v) = gcd(u-v, v)
if (u < v) {
v -= u;
} else {
uint64_t t = u - v;
u = v;
v = t;
}
} while (v);
return u << shift;
}
unsigned long v1 = 0x 00001111;
unsigned long v2 = 0x 00001202;
unsigned long v;
v = v1&(~v2);
v = v | v2;
void adder(int a, int b, int c) {
int sum = a ^ b ^ c;
int carry =
}
#define SEC_IN_A_YEAR (1 * 365 * 24 * 60 * 60UL)
Note:
#define SEC_IN_A_YEAR (1 * 365 * 24 * 60 * 60)UL
編譯器會報錯,因為根據 C99[6.4.4] 十進位的 integer constant 是由 decimal-constant integer-suffix 所組成的。 也就是說,UL 前面需要加上 decimal- conatant。#define SEC_IN_A_YEAR (1 * 365 * 24 * 60 * 60UL)
中, UL 會先跟 60 結合,並根據 C 語言的算術提升規則,算術後的結果也會是 unsigned long。SEC_IN_A_YEAR
會導致 overflow,因此需要加上 UL。void helper(List *head, List **tmp) {
if (!head) return;
helper(head->next, tmp);
(*tmp)->next = head;
*tmp = (*tmp)->next;
}
List *reverse(List *head) {
List* dummy = (List *)malloc(sizeof(List));
List *tmp = dummy;
helper(head, &tmp);
List *rets = dummy->next;
free(dummy);
return rets;
}
struct ListNode* reverseList(struct ListNode* head){
struct ListNode *cur = head, *pre = NULL, *next = NULL;
while(cur){
next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
#include <stdio.h>
int c;
int func(int m, int* n){
c += 1;
m += c;
*n += m;
return m;
}
int main(void) {
c = 0;
int x = 5;
int y = 7;
int z;
x = func(x, &y);
z = func(x, &y);
printf("sum of x, y, z, and c = %d", x + y + z + c); // 37
return 0;
}
extern void func1(void);
extern void func2(void);
extern void func3(void);
extern void func4(void);
extern void func5(void);
void main(int n)
{
if n==1 execute func1;
if n==2 execute func2;
if n==3 execute func3;
if n==4 execute func4;
if n==5 execute func5;
}
Int ival;
Int **p;
Ival = *p;
#include <stdio.h>
int main(void) {
char *str[] = {
{"MediaTekOnlineTesting"},
{"WelcomeToHere"},
{"Hello"},
{"EverydayGenius"},
{"HopeEverythingGood"}
};
char* m = str[4] + 4;
char* n = str[1];
char* p = *(str+2) + 4;
printf("1. %s\n", *(str+1));
printf("2. %s\n", (str[3]+8));
printf("3. %c\n", *m);
printf("4. %c\n", *(n+3));
printf("5. %c\n", *p + 1);
// 1. WelcomeToHere
// 2. Genius
// 3. E
// 4. c
// 5. p
return 0;
}
#include <stdio.h>
#define VAR 6
int func(int a){
int m = 3;
#undefined VAR
#define VAR 10
m = 4;
#endif
return m + VAR;
}
int main(void) {
int i=5;
printf("%d\n", func(i));
return 0;
}
T t1[2];
T *p1 = &t1[0];
T *p2 = &t1[1];
printf("size of T: %d byte", (int)p2 - (int)p1);
#include <stdbool.h>
#include <stdio.h>
bool is_one(int i) { return i == 1; }
int main() {
struct { signed int a : 1; } obj = { .a = 1 };
puts(is_one(obj.a) ? "one" : "not one");
return 0;
}
struct {int a : 1; } obj = {.a = 1 };
的地方,原本 int 這個資料型態需要 4 bytes 的空間,即 32 個位元,我們透過 bit field 指定只用其中一個 bit 來存放數值。Explain “thread” and “process”, and what is the difference ?
What is stack and heap when talking about memory ?
little-endian and big-endian 判斷
typedef union {
unsigned long l;
unsigned char c[4];
} EndianTest;
int main() {
EndianTest et;
et.l = 0x12345678;
printf("本系統位元組順序為:");
if (et.c[0] == 0x78 && et.c[1] == 0x56 && et.c[2] == 0x34 && et.c[3] == 0x12) {
printf("Little Endiann\n");
} else if (et.c[0] == 0x12 && et.c[1] == 0x34 && et.c[2] == 0x56 && et.c[3] == 0x78) {
printf("Big Endiann\n");
} else {
printf("Unknown Endiann\n");
}
printf("0x%lX 在記憶體中的儲存順序:\n", et.l);
for (int i = 0; i < 4; i++) {
printf("%p : 0x%02X\n", &et.c[i], et.c[i]);
}
return 0;
}
ref: 發哥(聯發科)上機考題目整理
ref: 聯發科 C語言測試題目
ref: 面試 C/C++ 觀念整理