2010-02-03 60 views
2

我試圖計算從終端輸入的一行命令參數的總和。到目前爲止,我已經到了將打印出所有東西的位置,直到最後幾位。我必須利用fork()來完成伴隨程序的所有計算。主程序無法對最終總和進行任何計算。我試圖通過創建一個新的動態數組來提取最後的幾位數字,但是如果碰巧有100個或更多的單個數字,這是沒用的。叉()不能計算命令行參數的最後幾位數

它將做./coordinator 3 4 3 2 1 4 5 4 3 2 4 3 2

之後從終端打印出****開始運營****

進程ID: 5642 計算:3和4總和爲7個

進程ID:5643 計算:3薩姆和2是5個

進程ID:5644 計算:1薩姆和4是5

進程ID:5645 計算:5薩姆和4是9個

進程ID:5646 計算:3薩姆和2是5個

進程ID:5647 計算:4薩姆和圖3是7個

進程ID:5648 計算:2薩姆和0 2

**** MIDDLE OPERATIONS ****

的ProcessID 5649: 計算:7和5總和爲12

的ProcessID 5650: 計算:5薩姆和9爲14

的ProcessID 5651: 計算:5薩姆和圖7是12

的ProcessID 5652: 計算:2和0總和爲2個

**** ENDING OPERATIONS ****

的ProcessID 5654: 計算:12和14的總和爲26

的ProcessID 5656: 計算:12的薩姆和2是14

return_array [0]:12
return_array [1]:14
return_array [2]:12
return_array [3]:2
return_array [4]:26
return_array [5]:14

事情變得COM在存在一行奇數的地方進行拼接,因此您必須在計算中的任意點添加一個零。所以你可以再次設置這個設置,這樣就可以繼續計算了。

如這一行:的ProcessID 5652:計算:2總和,0是2

如果我讓數字更加複雜,部分(在開始的時候更多的數字)後,「結束操作」變得更大從而使得把最後幾筆款項拉到最後總計一筆就更難了。我無法拉出這些數字。

+0

你應該考慮發佈你的代碼。 – 2010-02-03 08:56:06

+0

我發佈了迄今爲止我所擁有的內容。 – foobiefoob 2010-02-03 09:01:49

+1

什麼能阻止你迭代argv數組?家庭作業標籤也許? – 2010-02-03 13:06:19

回答

3

看起來你正在構建一個遞歸程序。我不確定你爲什麼將邏輯分爲開始,中間和結束操作?

我建議你要麼實現此作爲頭::尾遞歸,其中每個調用添加的第一個參數上,其餘的正在運行的結果,或返回零,如果它沒有參數:

Program -> 0 
Program head,... -> head + program ... 

或分而治之,其中每個調用或者返回它的一個參數,因爲沒有零,或叉兩個子調用,每次半的其餘參數:

Program -> 0 
Program x -> x 
Program (N args) -> Program (N+1/2 args) + Program (remaining args) 

,不需要複雜的內部數據結構,只是一些光陣列處理:

我應該指出,通過退出代碼傳遞值是一個壞主意,因爲退出代碼有一個非常有限的值(256)可用於此用途,並且如果您的程序由於某種原因失敗,它可能會返回一個令人驚訝的價值。

下面是不使用退出代碼的perl版本:

#!/usr/bin/perl 
[email protected]&&(shift(@ARGV)+‘$0 @ARGV‘)||0 

雖然這是perl,它不是每個人都可以閱讀,和Perl是做了很多幕後工作,對於我們來說,演示瞭如何使用fork和exec實現遞歸head :: tail sum函數的方式。

下面是一個使用退出代碼C版本:

int forkexec(char**oldargv,char**newargv,char**endargv) 
{ 
    if(!fork()) 
    execve(newargv[0]=oldargv[0],newargv,endargv[0]=0); 
    int b; 
    wait(&b); 
    return b>>8; 
} 

main(int c, char** a) 
{ 
    int b;for(b=0;b<c;b++)printf("%s ",a[b]);printf("\n"); 
    exit(!(c-1)?0 // empty head returns 0 
      :atoi(a[1])+ // convert the head into a number 
       forkexec(a,a+1,a+c)); // re-invoke on the remaining arguments 
} 

請注意,此代碼是不是安全,它使用無證的功能,如main參數數組argva)被NULL終止。然而,它的工作原理,並演示遞歸使用fork,exec和退出代碼在c中。與調試的printf註釋掉運行:

$ gcc sum.c 
$ ./a.out 1 2 3 4 5; echo RESULT $? 
./a.out 1 2 3 4 5 
./a.out 2 3 4 5 
./a.out 3 4 5 
./a.out 4 5 
./a.out 5 
./a.out 
RESULT 15 

正如你所看到的,我沒有使用任何樹木或名單 - 我只是每次都重新調用程序,沿着一個運動參數列表指針。

這裏的分而治之的版本:

int forkexec(char**oldargv,char**newargv,char**endargv) 
{ 
    if(!fork()) 
    execve(newargv[0]=oldargv[0],newargv,endargv[0]=0); 
    int b; 
    wait(&b); 
    return b>>8; 
} 

main(int c, char** a) 
{ 
    //int b;for(b=0;b<c;b++)printf("%s ",a[b]);printf("\n"); 
    exit(!(c-1)?0: // empty leaf is 0 
     !(c-2)?atoi(a[1]): // leaf returns value 
       forkexec(a,a,a+1+c/2)+ // Sum left half of children 
       forkexec(a,a+c/2,a+c)); // Sum right half of children 
} 

我想推薦你使用我的代碼;這是醜陋,不安全,故意壓縮形成一個小例子在這裏張貼。您應該使用功能分解,錯誤檢查和註釋來重新編寫代碼,以及將argv的內容克隆到新的,足夠大和空終止的數組中。另外execve的第三個參數在我的例子中是誤導性的。

取消對調試的printf:

int b;for(b=0;b<c;b++)printf("%s ",a[b]);printf("\n"); 

我們得到:

$ ./a.out 1 2 3 4 5 6 7 8; echo RESULT $? 
./a.out 1 2 3 4 5 6 7 8 
./a.out 1 2 3 4 
./a.out 1 2 
./a.out 1 
./a.out 2 
./a.out 3 4 
./a.out 3 
./a.out 4 
./a.out 5 6 7 8 
./a.out 5 6 
./a.out 5 
./a.out 6 
./a.out 7 8 
./a.out 7 
./a.out 8 
RESULT 36 

,清楚地顯示問題被分裂成越來越小的一半。

+0

作爲鏈接列表實現? – foobiefoob 2010-02-03 09:14:23

+0

謝謝,現在我對如何去做這件事有了一個想法。 – foobiefoob 2010-02-03 14:37:46