2017-09-14 132 views
0

我有以下代碼:在Collat​​z和打印與空間

#include <stdlib.h> 
#include <stdio.h> 
#include <sys/mman.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/wait.h> 

int main(int argc, char** argv) 
{ 
    const char* name = "COLLATZ"; 
    const int SIZE = 4096; 
    int num = atoi(argv[1]); 
    int shm_fd; 
    void *ptr; 
    shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666); 
    ftruncate(shm_fd, SIZE); 
    ptr = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0); 
    pid_t id = fork(); 
if (id == 0) { 
    shm_fd = shm_open(name, O_RDWR, 0666); 
    ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0); 
    while (num != 1) { 
     sprintf(ptr, "%d", num); 
     ptr++; 
     if (num % 2 == 0) num /= 2; 
     else num = 3 * num + 1; 
    } 
    sprintf(ptr, "%d", num); 
    ptr++; 
} else { 
    wait(NULL); 
    printf("PARENT: %s\n", (char*) ptr); 
    shm_unlink(name); 
} 

return 0; 
} 

我想它與正確的數字之間的間隔打印,但增加"%d "" %d"時一直沒能明白這一點像和其他一些格式化「東西」。如果您輸入8,則運行該程序時,我會預期輸出爲:8 4 2 1,而代之以8421。這就是說,當我們輸入一個像19這樣的數字時,我們得到一個非常長的數字,它是「正確的」,但沒有正確格式化。我希望有一些格式化幫助!

而且似乎我的算法可能不正確 - 如果你使用3,你應該期望的結果:3, 10, 5, 16, 8, 4, 2, 1和我31518421

+0

歡迎來到Stack Overflow。 請注意,在這裏說'謝謝'的首選方式是通過 提高投票的好問題和有用的答案(一旦你有足夠的聲譽這樣做),並接受任何 問題最有用的答案,你問(這也給你一個小小的提升,以你的聲望 )。 請參閱[關於]頁面,以及[如何在此處提問 ?]和 [當有人回答我的 問題時,我該怎麼辦? ?](http://stackoverflow.com/help/someone-answers) –

+0

請注意,如果您搜索到1126015,您將得到緩衝區溢出(並可能是崩潰);這需要超過4個KiB(4477個字節加上空或換行)來記錄Collat​​z序列中的整個528個數字列表。在此之前你也會遇到溢出。序列中最大數爲1,126,015的是90,239,155,648(這對於32位無符號整數來說太大了)。序號爲77,671的最大值爲1,570,824,736; 113,383的最大值是2,482,111,348,它溢出了帶符號的32位'int'; 159,487的最大值是17,202,377,752,它溢出了無符號的32位'int'。 –

回答

3

您可以簡單地使用:

sprintf(ptr, "%d ", num); 

後,這將添加一個空格您正在打印的號碼。你可以閱讀更多關於printfprintf doc

格式化根據您的不正確的結果,你可以看到,如果你把每個數字的第一個字符:3, 10, 5, 16, 8, 4, 2, 1,你31518421。這是因爲在ptr++;中打印後,您只能將ptr轉爲1。因此,如果您打印了兩個字符,則第二個字符將在下一步中被覆蓋。你需要做的是:

int shift = sprintf(ptr, "%d ", num); 
ptr = ptr + shift; 

或者,更簡潔的形式:

ptr += sprintf(ptr, "%d ", num); 

在這裏,你將被實際寫入的字符數,這將防止接下來是轉移作家被下一次調用sprintf覆蓋。