2018.1.9 AndyLee
void (*fptr)(type_a, type_b) = &func;
#include <stdio.h>
int add(int a, int b) {
return a+b;
}
int mult(int a, int b) {
return a*b;
}
int main() {
int (*op)(int a, int b);
op = add;
printf("op(3,5)=%d\n", op(3,5));
op = mult;
printf("op(3,5)=%d\n", op(3,5));
}
typedef void(F1)(void);
#include <stdio.h>
typedef int(*OP)(int,int);
int add(int a, int b) {
return a+b;
}
int mult(int a, int b) {
return a*b;
}
int main() {
OP op = add;
printf("op(3,5)=%d\n", op(3,5));
op = mult;
printf("op(3,5)=%d\n", op(3,5));
}
int a; // 一個整型數
int *a; // 一個指向整數的指標
int **a; // 一個指向指標的指標,它指向的指標是指向一個整型數
int a[10]; // 一個有10個整數型的陣列
int *a[10]; // 一個有10個指標的陣列,該指標是指向一個整數型的
int (*a)[10]; // 一個指向有10個整數型陣列的指標
int (*a)(int); // 一個指向函數的指標,該函數有一個整數型參數並返回一個整數
int (*a[10])(int); // 一個有10個指標的陣列,該指標指向一個函數,該函數有一個整數型參數並返回一個整數
const int *foo; // 一個 pointer,指向 const int 變數。
int const *foo; // 一個 pointer,指向 const int 變數。
int* const foo; // 一個 const pointer,指向 int 變數。
int const *const foo; // 一個 const pointer,指向 const int 變數。
註:C 語言之父明確表示 C 語言只有 call by value。
void swap (int c , int d){
int temp=c;
c=d;
d=temp;
}
int main(){
int a=5,b=10;
swap(a,b);
printf(" %d %d ", a,b);
}
Ans:5,10
註:傳參考是C++才有的東西,C語言是沒有的唷!
void swap (int &c , int &d){
int temp=c;
c=d;
d=temp;
}
int main(){
int a=5,b=10;
swap(a,b);
printf(" %d %d ", a,b);
return 0;
}
Ans:10,5
註:注意的是,一變數已經是別的變數的參考,就不可以再參考別的變數
int a=5,b=10;
int &c=a;
printf("c=%d \\n",c);
&c=b; //錯誤,因為他已經參考了a
int a=5;
int &c; //錯誤,傳參考必須在宣告的時候就一起給參考的對象,沒辦法之後再給。
坊間有 call by address 的說法其實是方便教學,指的是對指標變數進行操作的 call by value或是call by value of pointer,具體的執行效果和 call by reference 一樣。
void swap (int *c , int *d){
int temp=*c;
*c=*d;
*d=temp;
}
int main(){
int a=5,b=10;
swap(&a,&b); //意思就是要把a跟b的位址給swap副程式c跟d使用
printf(" %d %d ", a,b);
}
Ans:10,5
local 變數 : local 變數僅活在該函式內,存放位置在 stack 記憶體中。
static 變數 : static 變數生命周期(life time)跟程式一樣長,而範圍(scope)則維持不變,即在宣告的函式之外仍無法存取 static 變數。
global 變數 : 所有區段皆可使用此變數
註:除了範圍不同,static 變數只有宣告的檔案可以使用;而 global 變數可加上 extern 關鍵字修飾,即可在其他檔案以 .h 標頭檔方式使用該變數 (也就是 internal linkage 和 external linkage 的不同)。
const 通常表示只可讀取不可寫入的變數,常用來宣告常數。使用const有以下好處:
編譯器處理方式 : define 在預處理階段展開;const 在編譯階段使用。
類型和安全檢查 : const 會在編譯階段會執行類型檢查,define 則不會。
存儲方式 : define 直接展開不會分配記憶體,const 則會在記憶體中分配。
由於嵌入式系統常處理I/O、中斷、即時操作系統(RTOS)相關的問題,因此在嵌入式系統開發中 volatile 尤為重要。
被 volatile 修飾的變數代表它可能會被不預期的更新,因此告知編譯器不對它涉及的地方做最佳化,並在每次操作它的時候都讀取該變數實體位址上最新的值,而不是讀取暫存器的值。
extern const volatile unsigned int rt_clock;
這是在 RTOS kernel 常見的一種宣告:rt_clock通常是指系統時鐘,它經常被時鐘中斷進行更新。所以它是volatile。
因此在用的時候,要讓編譯器每次從記憶體裡面取值。而rt_clock通常只有一個寫者(時鐘中斷),其他地方對其的使用通常都是唯讀的。所以將其聲明為 const,表示這裏不應該修改這個變數。
所以volatile和const是兩個不矛盾的東西,並且一個物件同時具備這兩種屬性也是有實際意義的。
inline 可以將修飾的函式設為行內函式,即像巨集(#define)一樣將該函式展開編譯,用來加速執行速度。
#define 是巨集,在前置處理器(preprocessor)執行時處理,將要替換的程式碼展開做文字替換。define 語法範例如下:``
#define PI 3.1415926 //常數巨集
#define A(x) x //函數巨集
#define MIN(A,B) ( (A) <= (B) ? (A) : (B))
注意把參數用括號括起來,不然容易發生以下錯誤:
#define SUM(a,b) a+b
當 SUM(2,5)*10 時,因為沒有括弧先乘除後加減,得輸出為 52,錯誤
正確寫法:
#define SUM(a,b) (a+b)
常見的語法 i++ 和 ++i 具有以下性質:
因此會出現這種問題:
int i = 10
i = i++ + ++i;
這個問題的標準答案是
i = i++ + ++i;
i = 10 + ++i;
i = 10 + 12;
i = 22
語言規格在定義時為了編譯器實做上的彈性和效率考量,會刻意不去規定某些規格,因此如果寫出來的程式依賴或著錯用某些沒有在規格內所規定的特性時,我們就稱之為Undefined behavior,
reference: 萬惡的未定義行為
簡單的說,如果你使用了某個function,那麼你就是『call』了一個function。
如果系統或是函式是要求你給一個function pointer,這個function pointer指到一個實際的函式。然後它會在適當的時間呼叫此function,則此function就是所謂的 callback function。
#define Max(x, y) ((x)>=(y)? (x): (y))
就記憶體方向來看,指標所用的記憶體位置不為連續,而"矩陣"所配置的空間為連續。
int Max = a[0], Min = a[0], Avg = 0;
for(int i = 0 ; i < 10 ; i++)
{
if(Min > a[i])
Min = a[i];
if(Max < a[i])
Max = a[i];
Avg += a[i];
}
cout << Min << Max << static_cast<float>(Avg)/10 << endl;
Compiler展開後變成 2 + 5 * 10 = 52
Ans:52
// array version
void strcpy(char *dst, char *src){
int i = 0;
while((dst[i] = src[i]) != '\0')
i++;
}
// pointer version
void strcpy(char *s, char *t)
while((*s = *t) != '\0') {
s++;
t++;
}
}
int strlen( const char *str ){
int len;
while( (*str++) != '\0' ){
len++;
}
return len;
}
Ref :
http://www.voidcn.com/article/p-hfobsfai-bnz.html
http://www.cppblog.com/mydriverc/articles/35389.html
__interrupt double isr(double r) //不能有參數
{
double area = PI*r*r ;
printf("%f\n",area) ; //改成printk
return area ; // 不能有return
}
int *ptr;
ptr = (int *)0x67a9; // 設定指標變數的值
*ptr = 0xaa55; //設定指標變數指向的值
boolean isPowerof2(int n) {
return n > 0 && (n & (n - 1)) == 0;
}
二進位中,只要是 2 的次方,都剛好會是像 100 (4)或者 1000 (8)這種 1 開頭,尾巴都是 0 的狀況
8 的二進位 1000
7 的二進位 0111
1000
&
0111
-----
0000 = 0 (return true)
Reference: http://davidhsu666.com/410/ispowerby2
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int *p = &(a + 1)[3];
printf("%d\n", *p);
void func(void){
static int i = 0 ;
i++ ;
printf("%d" , i ) ;
}
ANS: 12345678910
void GetMemory(char *p) {
p=(char *)malloc(100);
}
void test() {
char *str=NULL;
GetMemory(str);
strcpy(str,"hello world");
printf(str);
}
传入GetMemory(char *p)函数的形参为字符串指针,在函数内部修改形参并不能真正的改变传入形参的值去执行完。
void GetMemory(void) {
char p[]="hello world";
return p;
}
void test() {
char *str=NULL;
str=GetMemory();
printf(str);
}
这段代码的p[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。
void GetMemory(char **p,int num) {
*p=(char *)malloc(num);//这段代码后面未进行内存申明成功的判断
}
void test() {
char *str=NULL;
GetMemory(&str,100);
strcpy(str,"hello");
printf(str);
}
传入GetMemory的参数为字符串指针的指针,但是在GetMemory中执行申请内存及赋值语句。
*p=(char *)malloc(num);
后未判断内存是否申请成功,应加上:
if(*p == NULL) {
…//进行申请内存失败处理
}
swap(int *p1,int *p2) {
int *p;
*p=*p1;
*p1=*p2;
*p2=*p;
}
在swap函数中,p是一个“野”指针,有可能指向系统区,导致程序运行的崩溃。
在VC++中DEBUG运行时提示错误“ACCESS Violation”。程序应该改写为:
swap(int * p1,int *p2) {
int p=*p1;
*p1=*p2;
*p2=p;
}
http://dummyh.pixnet.net/blog/post/9902458-【c語言】面試考古題-經驗分享–-%E4%B8%AD%E7%B4%9A
A:
第一行字串為 : 0113234
第二行字串為 : 0123456
首先,*p = s 所代表的含意為 pointer p 指向字串s的第一個位址 0,而接下來一連串的運算可分成四類:
Operations | Meaning |
---|---|
*p++ = *(p++) | 先取值,後指標下移 |
*++p = *(++p) | 指標下移,後取值 |
++*p = ++(*p) | 先把該值+1,後取值 |
(*p)++ | 先取值,後該值+1 |