2016-02-01 34 views
2

我正在爲Holberton學校進行一項練習。這是我3 hello_write代碼:爲什麼我的寫函數打印一個字符串(到stdout)會附加隨機字符輸出?

#include <unistd.h> 

int main(void) 
{ 
    write(1, "Hello, C\n", 1000); 
    return (0); 
} 

這是輸出的gcc -Wall 3 hello_write.c & & ./a.out:

$ gcc -Wall 3-hello_write.c && ./a.out 
Hello, C 
@44v4 
    zRx 
     ?HQc??h?i??i?? $ 

當我想輸出只是:

$ gcc -Wall 3-hello_write.c && ./a.out 
Hello, C 
$ 

我是一個初學者到C,所以我引用此文件的語法寫入功能。 http://codewiki.wikidot.com/c:system-calls:write

是否有一些上下文我可以給出爲什麼它可能會打印我的字符串後的額外字符?

+3

我的期望是,因爲你告訴它來寫1000個字節。 – drescherjm

+0

我認爲這可能是相關的,謝謝。我會查看如何計算我的字符串有多少個字節。 :) –

+0

寫入函數的最後一個參數是要寫入的字符數您試圖寫入1000個字符,而只提供幾個字符。寫入嘗試寫入更多並在內存中前進。它打印任何它發現那裏 – loginn

回答

3

最好的方式來弄清楚什麼是錯的是看在write函數的documentation處,並檢查每個單獨參數控制的內容:

ssize_t write(int fd, const void *buf, size_t count); 

你傳入1的文件描述符(精),字符串文字,它是一個指向C字符串爲buf(也精細),以及要寫入的字符數。

注意write在到達串標記的結束(即'\0'在字符串的末尾)確實不停止。這就是爲什麼打印出額外的字符會導致未定義的行爲。

傳遞正確的長度將解決這個問題:

write(1, "Hello, C\n", 9); 

不幸的是,這段代碼是脆弱的,因爲改變字符串字面需要更新它的長度。更好的辦法是讓"Hello, C\n"恆定,並使用strlen

const char *str = "Hello, C\n"; 
write(1, str, strlen(str)); 
1

你應該告訴* nix write函數有多少字符(字節)來自你想要寫入的緩衝區(最後一個參數)。您提供了一個大小爲10的緩衝區(您的"Hello, C\n"字符串),但後來要求write寫入1000個字節。這只是沒有意義。

write complintly寫你的緩衝區的內容(10個字符),然後繼續寫你的"Hello, C\n"字符串之後的任何垃圾駐留在內存中的990多字節。垃圾就是你在輸出中看到的。或者,也許這並不是真正的「垃圾」,而是一些其他非常有意義的數據,儘管如此,您仍然無法以這種方式訪問​​業務(即通過溢出緩衝區的邊界)。

您提供的字符數作爲write的最後一個參數應爲小於或等於與緩衝區的大小。通過指定更大的值,你基本上可以說是write。你看到的輸出是這個謊言的結果。

2

正如已經指出的那樣,這是因爲你寫函數的第三個參數:要寫的字節數。爲了避免這種錯誤的未來的情況下,我會建議使用的strlen來計算的字節數發送,例如:

#include <unistd.h> 
#include <string.h> 

int main(void) 
{ 
    char buf[] = "Hello, C\n"; 
    write(1, buf, strlen(buf)); 
    return (0); 
} 
1

函數調用:

write(1, "Hello, C\n", 1000); 

使系統寫1000從C字符串開始的字節從"Hello, C\n" ...您正在讀取超出C字符串末尾的字節,並將它們寫入終端,一直到第1000個字節。未定義的行爲,但明顯沒有崩潰,只是C字符串,它的終止符以及C字符串之後的內存恰好在內存中。

的應指定字符串的長度:

write(1, "Hello, C\n", strlen("Hello, C\n")); 

或使用該常數小規模最終'\0'

write(1, "Hello, C\n", sizeof("Hello, C\n") - 1); 
+0

我沒有找到「優雅」(因爲「不要重複自己」的原因)需要複製粘貼字符串一次。雖然我在回答中提出了與strlen相同的用法。 –

+0

@VicenteCunha:我同意,但字符串常量是最有可能共享和'strlen'將在編譯時計算(至少與gcc + glibc),所以它並不重要。你的版本甚至可能生成更多的代碼。 – chqrlie

1

爲@anT說,write似乎試圖寫一個完整的1000個字符到屏幕上。爲了解決這個問題,你有幾個選擇,其中一個就是簡單地計算你想要打印的字符串的總長度,並用它代替1000

#include <unistd.h> 
#include <string.h> 
int main(void) 
{ 
    char *test1 = "test test test"; 
    char *test2 = "test test test"; 
    write(1, test1, strlen(test1)); 
    write(1, test2, strlen(test2)); 
    return (0); 
} 

這麼說,我真誠地相信,你的老師會詢問你使用write。我建議你看看puts

int puts(const char *str); 

或古老printf

int printf(const char *restrict format, ...);​ 

這些更常用的,尤其是在入門課程。此外,使用這些可以顯着簡化流程。

例子:

#include <stdio.h> //both puts and printf functions are defined in this library 
int main(void) 
{ 
    char *test1 = "test test test"; 
    char *test2 = "test test test"; 
    printf(test1); 
    puts(test2); 
    return (0); 
} 
+0

好的建議,但我猜測練習的目標確實是使用寫作,因爲練習題(3-hello_write)。 –

+0

哈哈!謝謝。霍爾伯頓的課程是獨一無二的。我們被要求查看信息來完成自己的練習。前兩個練習要求我們使用puts和printf。我假定這一點的重點是向我們介紹內核函數及其語法。 –

相關問題