2015年6月29日 星期一

[C筆記]struct union enum 實作

介紹

struct : 使用者變數不會只是簡單的 int or char 所以用結構來定義使用者所               需要的變數


enum:列舉 讓使用者只能輸入固定值(例如星期幾)(使用實不必加""字串符號)

union: 當使用者需要一個不是特定的單位時候就必須使用union
             範例中

               typedef union{
                          short count;
                          float weight;
                          float volume;
                           }quantity;

             使用者用到"量單位的變數" 可能是整數或者浮點數,就需要使用union ,原因是如果用 struct來做就會造成空間的浪費,必須浪費一個short (2byte)和2個  float (4byte)的記憶體空間來存一個值 ,union 則是以最大空間來變通  float (4byte) 可以省下許多記憶體空間。







sample code
#include <stdio.h>
#include <stdlib.h>
typedef enum{count,pounds,pints}unit; // 與struct不同  用,隔開
 typedef union{ // quantity x ={5};會被設定第一個欄位  //指定設定 quantity x ={.volume=1.5};                      short count;
        float weight;
        float volume;
        }quantity;
typedef struct {
        const char *name;
        const char *color;
        quantity amount;
        unit units;  
        }fruit;
   
void display(fruit x); //因為有fruit 所以必須放在 typedef struct fruit 下面   
int main(int argc, char *argv[])
{
  fruit apple = {"apples","red",.amount.count=150,count}; //不允許先宣告 下一行才設定值 !! apple ={}會被編譯器誤以為陣列 
  fruit strawberries = {"strawberries","pink",.amount.weight =1.5,pounds};
  fruit noisy ={"noisy","nocolor",.amount.volume =1.3,pints};
  display(apple);
  display(strawberries);
  display(noisy);
  return 0;
}
void display(fruit x)//如果是改值請用指標改記憶體內的值(這方法純輸出來看所以不帶入指標) 
{
     if(x.units == count)
        printf("%s is %s and %i\n",x.name,x.color,x.amount.count);
     else if(x.units == pounds )
         printf("%s is %s and %1.1f\n",x.name,x.color,x.amount.weight);
     else
         printf("%s is %s and %1.1f\n",x.name,x.color,x.amount.volume);
}

輸出結果


2015年6月24日 星期三

[C筆記] typedef struct 觀念 用法

前言:變數不會只侷限在簡單的整數或者字串,撰寫時可以用struct 來做出你想要的類別,C中的類別與其他語言有些不同,struct中不能寫方法只能宣告物件內容。


code: sample


#include <stdio.h>
#include <stdlib.h>
typedef struct
{
        const char *descrption;
        float value;
        } swag;
typedef struct
{
        swag *swag ;
        const char *sequence;
        }combin;
typedef struct
{
        combin numbers;
        const char *make;
        }safe;
void method (safe *safe_pointer)
{
   
      printf("%0.2f\n",safe_pointer->numbers.swag->value);
     }
   
void method2 (safe safe_pointer)
{    
      safe_pointer.numbers.swag->value =safe_pointer.numbers.swag->value +1;
      printf("%0.2f\n",safe_pointer.numbers.swag->value);
     }

int main(int argc, char *argv[])
{
  swag gold ={"gold",10.0};
  combin numbers ={&gold,"1234"};
  safe s ={numbers,"5678"};
  method2(s);
  method(&s);
  return 0;
}

輸出結果:
11.00
11.00
補充說明

 method2(s);

編譯器複製了一份一樣架構的資料丟進這個方法裡做一個safe_pointer.numbers.swag->value=safe_pointer.numbers.swag->value+1的運算,在這個方法裡struct做任何的修改都只式改複製版本的值,但是為什麼最後結果會讓 method(&s);輸出也變11呢??

原因是因為雖然是複製版本,但是複製版本的swag欄位為一個指標,他與非複製版本同時指向參數真正儲存記憶體的位置。

 method(&s);

編譯器將s在記憶體中的位置資料丟進這個方法裡,在這個方法裡改任何struct中的變數,就是真實在改main中s的資料,

2015年6月23日 星期二

[C筆記]Makefile介紹與實際操作

前言:當我們有一個由多個程式組合而成的一之程式,正常情況下我們修改某個子程式,編譯器執行前必須將每個子程式都在重編譯一次,這非常浪費時間,Makefile可以去幫我們檢查相依關係,並且去檢查修改時間加以判斷哪些子程式需要重編譯,不必花費多餘時間在編譯沒有改動過的子程式上。


實作:

main.c


encrypt.c


encrypt.h 內容

void encrypt(char* msg);


關係圖:

補充:利用.c檔 的開頭擋來排出關係圖 ,.c檔經過-c(compile)生出目地擋.o

Makefile檔


encrypt.o: encrypt.h encrypt.c   //encrypt.o與  encrypt.h encrypt.c相依
gcc -c encrypt.c                
main.o: main.c encrypt.h   //main.o 與main.c encrypt.h相依
gcc -c main.c
try: main.o encrypt.o //try.exe 與 main.o encrypt.o相依
gcc main.o encrypt.o -o try


實際操作:假設我修改了encrypt.c 的情況下執行(window指令為mingw32-make)mingw32-make try (linux 下指令為make)



因為我只修改了encrypt.c 所以make只幫我重新編譯encrypt.c (不去編譯main.c !!)
然後再重新Link main.o encrypt.o 來輸出一份try.exe



ref:深入淺出C

2015年6月22日 星期一

[C筆記]利用標頭檔共享程式碼

前言:當有兩個以上的程式檔需要用到某個方法,直觀作法是在兩支程式內都寫下此方法的程式碼,但如果這個共同的方法需要改良,那不就代表我們必須去每支擁有這程式碼的程式都改一遍,這是一件麻煩的事情,這裡利用標頭擋來讓N個程式檔都可以共享一個方法的檔案,只要修改此檔案就可以讓所以引用此方法的程式碼都跟著改變。


範例:









解說:

encrypt.h :用來連結的標頭擋


code:
void encrypt(char *message);//類似宣告方法的回傳值

encrypt.c :想共用方法


code:
#include "encrypt.h" //這邊要將連結用的標頭擋包含進來
void encrypt(char *message)
{
while(*message)
{
               
 *message = *message^31;

  message++;
}
}

main.c :主程式


code:
#include <stdio.h>
#include <stdlib.h>
#include "encrypt.h"//這邊就是共享 encrypt.c 裡面方法的關鍵int main(int argc, char *argv[])
{
  char msg[80];
  while(fgets(msg,80,stdin))
  {
    encrypt(msg);
    printf("%s",msg);
                            }
  system("PAUSE");   return 0;
}


最後執行要記的兩個檔一起編譯進去 gcc main.c encrypt.c -o try

補充:當encrypt方法需要修改就直接去改encrypt.c裡面就ok了




ref:深入淺出C

2015年6月21日 星期日

[C筆記]命令列選項與命令列引數


practice

sample code:

#include <stdio.h>

#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    char *delivery ="";
    int thick =0;
    int count =0;
    char ch;
  while( (ch =getopt(argc,argv,"d:g:t"))!=EOF)
  switch (ch){
         case 'd':
                  delivery = optarg;
                  break;
         case 'g':
                  printf("%s\n",optarg);
         case 't':
                   thick = 1;
                  break;
                 
         default:
                 fprintf(stderr,"Unknow option: '%s'\n",optarg) ;
                 return 1;    
         }  
         argc-=optind;
         argv+=optind;
       
         if(thick)
         puts("thick crust");  
         if(delivery[0])
         printf("to be delivery %s .\n",delivery);
         for(count = 0;count<argc;count++)
         puts(argv[count]);
    return 0;
}


執行結果:


要點補充說明:

getopt 使用前必須先#include<unistd.h>

利用getopt 來設置選項 d  : 代表此選項後面必須帶參數(-d now)

命令(try.exe -d now -g go -t output1 output2)

*argc為8
*argv為8 (argv[0]~argv[7])
*變數 optind為6  (output1,output2為參數所以不算命令數)
*變數 optarg 內容利用case '指令' 來區分輸入的參數( case 'd': optarg 為 -d  後面帶入的值)
*arg+=optind (將 arg[0]變成output1 arg[2]變成 output2)

2015年6月20日 星期六

[C筆記]自定資料串流(將輸出到多個檔案)

前言: 作業系統只提供3種資料串流 stdin 、stdout、stderr(標準輸入 標準輸出 標準錯誤),當我們需要更多的輸出、輸入時,可以透過fopen 來定義自己要的資料串流。


重點整理

* fopen 回傳是檔案的指標

     FILE * in_file = fopen("input.txt","r"); //r唯讀
     FILE *out_file = fopen("output.txt","w"); //w//唯寫
    

* FILE這個類別一定要大寫(早期巨集定義)

   

 *一個程式最多256個資料串流(視作業系統而定)使用玩季的關閉fclose();


sample code:


輸入


輸出1

輸出2

輸出3








[C筆記] 不去更改已寫好的project 利用管線來解決

前言:  第一之程式工具可以將輸入的資料(經度,緯度)轉換成json格式,此範例如果想要加條件來過濾出我們所要的坐標,最直觀的方法就是在程式碼中加if 條件來過濾,但是這個方法並不是一個好方法(因為必須去動到別人已寫好的工具),長期這樣改下來這隻程式反而會有太多多餘不必要的code出現,因此用管線的方式來取代上數的過濾條件。


C code 1: 將輸入的資料轉換成Json格式



Code 1編譯出 Map.exe 檔






C code 2: 過濾出我們要的位置



Code 2 編譯出 Range.exe 檔


(注: | 為管線 aa.txt檔案餵給Range.exe 過濾出我們要的坐標後再透過管線直接餵給map.exe最後將結果存到bb.json


結果:


aa.txt 

bb.json

注過濾出來的結果





[C筆記] 將資料透過小工具轉換格式輸出

前言: C語言程式在比較實用的情況下往往需要將資料以檔案的形式輸出,並將此檔案餵給其他小工具,此範例將我們所需要的資料內容轉換成JSON格式輸出。


C :code

Input : aa.txt



輸入不再是手動輸入,而是透過指令將檔案直接餵給程式

gcc main.c -o trycode
在windows底下 trycode必須加.exe
trycode.exe < aa.txt  > bb.txt ( <輸入  >輸出)

output : bb.txt