顯示具有 C 標籤的文章。 顯示所有文章
顯示具有 C 標籤的文章。 顯示所有文章

2009-10-28

【C語言】秀出數值的二進位表示

#include <stdio.h>

void showBinary(int value, int size) {
int i ;

for(i=(size<<3)-1 ; i>=0 ; i--)
(value & (1<<i) ) ? putchar('1') : putchar('0') ;
}

int main() {
int i=5 ;
char j = 15 ;

//example1: show int type, value is 5
showBinary(i, sizeof(i)) ;
putchar('\n') ;
//example2: show char type, value is 15
showBinary(j, sizeof(j)) ;

getchar() ;
return 0 ;
}

2009-10-04

【C語言】左移&右移巨集

恩...就左移與右移巨集函數

#include <stdio.h>

#define ROTATE_LEFT(NUM,BIT) ( \
(NUM<<BIT) | (NUM>>( (sizeof(unsigned)<<3)-BIT) ) \
)

#define ROTATE_RIGHT(NUM,BIT) ( \
(NUM>>BIT) | (NUM<<( (sizeof(unsigned)<<3)-BIT) ) \
)

int main() {
unsigned int x = 0xff000000 ;
printf("0x%8X\t0x%08X\n", x, ROTATE_RIGHT(x,4)) ;
printf("0x%8X\t0x%08X\n", x, ROTATE_LEFT(x,4)) ;
system("pause") ;
return 0 ;
}

2008-09-03

【LP】程式讀取參數列

  在Linux下寫程式要讀取參數列的參數(值),最直覺的作法莫過於直接使用main()中的argc與argv變數,不過要自己在程式中處理參數列並且想要提供使用者靈活的參數組合,恐怕會是一個叫人頭痛的"超級任務"。
  以ls程式為例,其參數項目就已經玲瑯滿目(如:-l、-a...等),參數項豐富頂多就是在程式中的switch...case敘述多寫一點,但是再加上沒有參數值的參數項可以合併在一個破折號後面(如:-la),這就很麻煩了。
  在Linux下可使用getopt()函數來幫我們處理參數列的問題,其prototype如下:

int getopt(int argc, char *argv[], const char * optstring) ;
extern char *optarg ;
extern int optind, opterr, optopt ;
  使用上很簡單,getopt函數前兩個參數就將main函數宣告的參數項(argc與argv)填入就是了,重點在於optstring,直接用例子來說明:
#include <stdio.h>
#include
<unistd.h>

int main(int argc, char *argv[]) {
int opt ;


while( (opt=getopt(argc, argv, "x:yz")) != -1 ) {
switch(opt) {
case 'x':
printf("option: %c argument: %s\n", opt, optarg) ;
break ;
case 'y':
case 'z':
printf("option: %c\n", opt) ;
break ;
case '?':
printf("unknow option\n") ;
}
}


return 0 ;
}
  將此範例存檔為lab_arg.c並編譯成lab_arg:gcc -o lab_arg lab_arg.c
  此程式可接受參數x、y、z,並且參數x其後會接著一個參數值,可以先執行看看其效果。在optstring部分範例中用了"x:yz",其表示此程式接受參數有x、y、z,而在x後面加一個冒號(:)說明x參數將會帶一個參數值。
  getopt會依序解析使用者傳入的參數項,若符合optstring規則的參數會回傳對應的參數字元,當getopt函數解析完餐數個數後,會傳回-1表示結束,因此使用一個while迴圈將之包附並檢查傳回值是否為-1。
  使用getopt()我們僅需關注程式中對於各個參數項的對應行為即可,而不需費盡心思自己在程式中解析複雜的參數組合可能。
  更詳細的getopt()函數說明請參閱:http://fair.athost.net/main/linux_c/function/16.html#linuxc293

2008-06-04

用XOR交換兩個變數的資料

  『用XOR交換變數內容可以不用第三個變數唷!』這句話相信已經是老梗話題了,既然老梗那還寫這篇搞笑...這篇只是用數學來證明為何運用連續的互斥或運算就可以達成兩個變數的交換而且不必用到其他暫存變數。
  在遊戲開始之前先作此假設:運算式的敘述是從右到左。那麼遊戲就開始了,請直接參考下面這張用Tabel PC手寫的證明圖片吧!

<==============全文結束==============>
  好啦~我承認寫這篇其實是炫耀而已,我買了台Table PC耶!手寫功能真方便,ㄎㄎㄎ(喔不~宅男毛病又犯了...向殭屍會磨牙一樣~克制不了XD)

2008-01-01

模數運算子:%

  模數運算子(modulus operator)主要用於整數的計算,「a%b」:a除以b後得到的餘數即是該運子求得的答案。有看過我之前寫的「整數型態的除法」的人可能就會問「用於浮點數計算的話會得到什麼?」這點可以不用擔心,因為模數運算子不提供浮點數運算,compiler會跳出來阻止你的!

  模數運算子看起來似乎只是很普通的數學運算子,實際上他的用處可不少呢!參考以下程式碼:

#include <stdio.h>

int main() {
int i = 0 ;
while(i++ < 5) {
if(i%2)
printf("%d => 奇數\n", i) ;
else

printf("%d => 偶數\n", i) ;
}
system("pause") ;
return 0 ;
}
印出結果不意外的是
1 => 奇數
2 => 偶數
3 => 奇數
4 => 偶數
5 => 奇數
  透過模數運算子很簡單的就能判斷奇偶數,當然這只是很簡單的應用範例,在思考下面的程式範例:
#include <stdio.h>

int main() {
int i = 0 ;
while(i++ < 12) {
printf("%2d ", i) ;
if(i%4==0)
printf("\n 印了四次!!\n") ;
}
system("pause") ;
return 0 ;
}
得到結果如下:
1 2 3 4
印了四次!!
5 6 7 8
印了四次!!
9 10 11 12
印了四次!!
  此範例示範了模數運算子在週期性上的應用,常見應用如印月曆。除了上面兩個簡單的應用範例外,當然還有數不盡的範例可以說,若只是講解應用範例的話那就太沒意思了!真正的重點在下面這段程式碼:
#include <stdio.h>

int main() {
printf("%d\n", 5%2) ;
printf("%d\n", -5%2) ;
printf("%d\n", 5%-2) ;
printf("%d\n", -5%-2) ;
system("pause") ;
return 0 ;
}
  思考一下究竟會得到什麼結果?!

  這在C99標準制定之前可是沒有標準答案,但既然現在C99已是公認的標準,因此就遵循C99的規則來思考吧:前面的運算元如果是負的,得到的結果就是負的;如果前面的運算元是正數,則結果就是正數,簡單來說就是看左邊的運算子正負號即可。因此結果如下:
1
-1
1
-1

2007-12-23

關於C語言中的volatile修識字

詳細說明請參考網址→http://www.programmersheaven.com/articles/pathak/article1.htm

之前暑假在樓下學SoC程式設計時就遇過volatile這關鍵字,當時授課的助教只說他也不清楚這意思,要大家照抄就是了。現在實驗室也開始玩SoC發展平台,自然的有一部分就是要寫一些程式控制周邊硬體,以上都是廢話XD

由於ARM都是採用memory-map方式存取周邊裝置,因此要對周邊裝置溝通只要把資料丟進記憶體或從記憶體讀取資料就可以了,但這時聰明的編譯器反而可能變成壞了大了事的老鼠屎,原來是幫程式碼最佳化的功能反而成了困擾,請參考底下程式碼:

*ptr = 0;
while(*ptr){
*ptr = 4 ;
*ptr = 0 ;
}

這段內容很可能會被聰明的編譯器給最佳化成了下面的樣子:
*ptr = 0
while(0) {
}

從軟體角度來說,這是編譯器幫不聰明的Programmer化簡了多餘的冗碼;在硬體角度來看,可能就不見得是好事了,如果Programmer原本就是希望*ptr指到的位址訊號一直由0與4交互替換,那這時編譯器就幫倒忙了!
若要避免這窘境發生,可以在宣告*ptr變數時,加上volatile修識字讓每次的存取都乖乖的照作,並且是到記憶體進行讀取,而不使用暫存器。

2007-12-21

Dev-C++在Vista環境下無法編譯的問題

  Dev-C++在Vista系統下似乎都會遇到無法編譯的問題。詳細解法請參考網頁→http://msml92.net/blog/LD/archives/229

  感謝金剛學弟熱情提供資訊!

2007-12-16

整數型態的除法

對新手來說很重要的觀念!
請思考的程式碼印出結果,究竟會印出0.5或是0?

#include <stdio.h>
int main() {
  int a = 10 ;
  int b = 20 ;
  printf("%f\n", a/b) ;
  system("pause") ;
  return 0 ;
}
很多新手應該會選擇0.5吧!確實~以人類思考角度來看0.5應該是正確的,可是在C語言看來0才是正確解答。
在C語言中,除法分為整數除法浮點數除法
  • 整數除法
    電腦僅會算到整數值,至於小數(分數)部分直接省去,並且是無條件捨位。
  • 浮點數除法
    電腦會一路除下去,直到表示位數的最小位數,採用四捨五入。

那究竟什麼時候採用整數除法又什麼時候採用浮點數除法呢?當然不是看電腦心情隨機決定XD
端看除法兩邊的運算元來決定,如果除法的兩個運算子其中一個為浮點數型態(float或double)則電腦就會採用浮點數除法,否則就採用整數除法。上面的例子會採用整數除法,原因是變數a與b都是整數型態,因此採用整數除法。
接著再看以下範例,答案將會是0.666667
#include <stdio.h>
int main() {
  float a = 2 ;
  float b = 3 ;
  printf("%f\n", a/b) ;
  system("pause") ;
  return 0 ;
}

2007-07-04

【遞迴】字串的排列組合

問題:
假若給一字串abc , 寫一程式能夠印出其所有的排列組合
abc acb bac bca cba cab

想法:
n為字串長度
讓所有字元皆出現在第n位置一次
abc
acb
cba
接著分n組個別探討,此時第n位置已固定
m為剩下字元,讓剩下所有字元皆出現在第m位置一次

依此類推,當n為1時直接印出字串,即完成。

用C語言實作:

#include <stdio.h>

void p(char *str, int n) {
char ch ;
int i ;
if(n==1) {
printf("%s\n", str) ;
}
else {
for(i=n-1 ; i>=0 ; i--) {
ch = *(str+i) ;
*(str+i) = *(str+n-1) ;
*(str+n-1) = ch ;
p(str, n-1) ;
ch = *(str+i) ;
*(str+i) = *(str+n-1) ;
*(str+n-1) = ch ;
}
}
}

int main() {
char ch[] = "abcd" ;
p(ch, 4) ;
system("pause") ;
return 0 ;
}

【關鍵字:字串排列組合、Permutation、遞迴】

2007-06-04

Advanced Linux Programming

  上Unix時劉老介紹的網站,正確說法是強迫接受...很讚的東西。「Advanced Linux Programming」是一本書名,其內容名符其實就是介紹Linux上的程式(C/C++)寫作,這本書是一群作者合力完成的,這些作者也很讚...把這本書的所有內容都放上網路了,網頁上註明書本版權Open Publication License,也就是可以隨意拿去書局「拷貝」!

  Link:http://www.advancedlinuxprogramming.com/

2007-05-26

用C實做二元搜尋數

二元搜尋(Binary Search)
  從一個排序過的序列中找尋數值所在的位置(index)。  假設一個陣列大小為10,存放已排序好的數列如圖所示,搜尋數值16所在位址。

  1. 初始min為柱標0
  2. 初始max為柱標n-1
  3. 以min到max為搜尋範圍,每次都比較中間數值是否為搜尋之key,如果是就回傳其所在位址
  4. 如果中間值(mid)小於key,表示key存在於範圍mid+1到max之間,因此修改min為mid,並繼續下一次比較
  5. 如過中間值(mid)大於key,表示key存在於範圍min到mid-1之間,因此修改max為mid,並繼續下一次比較
  6. 重複3, 4, 5 步驟直到min大於max為止,此時還未找到key所在位址,表示key不存在于數列之中,因此回傳-1表示搜尋失敗
參考程式如下:
#include <stdio.h>

int binary_search(int arr[], int n, int key) {
int min = 0 ;
int max = n-1 ;
int mid ;
while(max >= min) {
mid=(min+max)/2 ;
if(arr[mid] == key)
return mid ;
else if(key < arr[mid])
max = mid-1 ;
else

min = mid+1 ;
}
return -1 ;
}

int main() {
int arr[10] = {1, 5, 7, 10, 12, 13, 16, 19, 20, 30} ;
printf("%d\n", binary_search(arr, 10, 13)) ;
system("pause") ;
return 0 ;
}

2007-05-25

【5/24】計概實習參考解答

題目:運用遞迴觀念設計一函數,該函數接受兩個參數:一個整數型態陣列、一個整數(表示陣列大小),並回傳總和

#include <stdio.h>

int sum(int a[], int x) {
if(x<=1) {
return a[x-1] ;
}
else

return a[x-1] + sum(a, x-1) ;
}
int main() {
int test1[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} ;
printf("%d\n", sum(test1, 10)) ;
system("pause") ;
return 0 ;
}

2007-05-16

簡單猜數字遊戲

猜數字遊戲之【終極密碼】

遊戲中用到亂數,相關學習可以到美麗C世界參考

#include <stdio.h>

int main() {
int input ;
int ans ;
int min=0, max=1000 ;
srand(time(NULL));
ans = rand()%1000 ;


while(1) {
printf("%d 到 %d, 猜一數字", min, max) ;
scanf("%d", &input) ;
if(input < min input > max) {
printf("賣來亂...\n");
continue ;
}
if(ans == input)
break ;
else if(input < ans)
min = input ;
else

max = input ;
}
printf("恭喜猜對了!! ans: %d\n", ans) ;
system("pause") ;
return 0 ;
}