2014-11-02 54 views
4

管數據到調用scanf函數(程序)和read()有一個C程序,它看起來是這樣的:如果使用像我如何在Linux

命令我管數據到這個程序

#include <stdio.h> 
#include <unistd.h> 

int main() 
{ 
    int n; 
    char str[16]; 
    scanf("%d", &n); 
    printf("n: %d\n", n); 

    int count = read(STDIN_FILENO, str, 16); 
    printf("str: %s\n", str); 
    printf("read %d bytes\n", count); 
} 

(echo -en '45\n'; echo -en 'text\n') | ./program

只有scanf()實際讀取數據。 read()只讀0個字節。

換句話說,方案產出

n: 45 
str: 
read 0 bytes

我怎麼能管到的數據都scanf()read()

編輯:對不起,我應該澄清:我正在尋找一種方法來做到這一點,而無需修改源代碼。感謝無論如何回答和評論的人。

+0

你可以先加入:#include 到你的代碼。 – user3629249 2014-11-02 09:11:53

+0

scanf()的返回代碼需要檢查以確保操作實際將值輸入到'n'中。 – user3629249 2014-11-02 09:14:40

+0

注意:read()不會在輸入末尾放置空字符。所以代碼必須這樣做,使用來自read()的調用的返回值來確定在哪裏放置空字符。否則,printf將直接讀取實際的str內容,直到它(最終)遇到空字符或導致seg錯誤 – user3629249 2014-11-02 09:20:52

回答

3

對於同一文件描述符,不推薦使用文件描述符函數(讀取)和流函數(scanf)。使用FILE *(即fread/fprintf/scanf/...)的函數正在緩衝數據,而使用文件描述符(即read/write/...)的函數不使用這些緩衝區。在你的情況下,修復程序最簡單的方法是使用fread而不是read。該程序可能看起來像:

#include <stdio.h> 
#include <unistd.h> 

int main() { 
    int n; 
    char str[16]; 
    scanf("%d", &n); 
    printf("n: %d\n", n); 

    int count = fread(str, 16, 1, stdin); 
    printf("str: %s\n", str); 
    printf("read %d bytes\n", count); 
} 

在你原來的例子,scanf已經提前讀取輸入並存儲在其緩衝區。由於輸入非常短,並且立即可用,因此完全讀取到緩衝區,並且您的調用read沒有更多可讀的內容。

當您直接從終端輸入輸入時,不會發生這種情況,因爲scanf在從終端設備讀取時不會將數據超過一行進行緩衝。

(echo -en '45\n'; sleep 1; echo -en 'text\n') | ./program 
+0

有沒有辦法在不修改源代碼的情況下做到這一點?可能有一些方法可以確保'scanf'不會緩衝所有輸入? – IGNUcius 2014-11-02 09:21:05

+0

@IGNUcius:這不是緩衝的調用,它是用於掃描/讀取的結果:'FILE'。 – alk 2014-11-02 09:28:54

+0

這可能是更值得更明確地表明,基本概念是問題:緩衝I/O與無緩衝I/O – alk 2014-11-02 09:30:08

2
#include <stdio.h> 
#include <unistd.h> 

int main() 
{ 
    int n; 
    char str[16]; 
    setbuf(stdin, NULL); // Ensure that there's no buffering for stdin 
    scanf("%d", &n); 
    printf("n: %d\n", n); 

    int count = read(STDIN_FILENO, str, 16); 
    printf("str: %s\n", str); 
    printf("read %d bytes\n", count); 
} 

正如前面說的答案,scanf函數導致您的問題,因爲它使用了一個緩衝區:這也不會,如果你通過一個命令創建一個在您例如管道輸入一次暫停發生。所以你可以確保它不通過調用setbuf(stdin,NULL)