2008年1月13日 星期日

C - fgets & strncmp & strrchr

今天練習寫 C 時,使用了在 stdio.h 中所提供的 char *gets(char *str) function,但是在 compile 的時候卻出現了以下警告訊息:
warning: the `gets' function is dangerous and should not be used.
喔? 這個 function 竟然被 compiler 說是危險不應該使用的.....原因是為何呢?

看到了以下兩篇文章,終於知道了答案:

原來當輸入的值超過接收這個值的變數範圍時,就會有 overflow 的情況發生。

overflow 又會怎樣呢? 這讓我想起了之前參加 OpenSource 研討會時,有一個講 Embedded System Security 的主講人有提到這個,overflow 的確會造成資訊安全上的漏洞,因此這個情形要盡量應該避免。

那要用什麼才會比較安全呢? 答案是 char *fgets(char *str, int num, FILE *stream) function,透過第二個參數可以指定最多可以取得多長的字串,如此一來,就不怕因為使用者亂輸入而造成 overflow 的情況發生了!

但是需要注意的是,函式所取得的長度是 (num - 1) 並非 num 喔! 這是需要注意一下的地方。


另外,取得值之後,若要跟另外的字串做比較,一般來說是用 int strcmp(const char *s1, const char *s2) function,若兩個字串相同,則回傳 0。

但是我怎麼試都不是 0,明明輸入的字串跟原本的字串都相同阿?

後來才發現,我用 fgets 取得輸入值,在 BufferSize 的地方設定為 10(也就是說最多取到長度為 9),而輸入值的長度只有 5,於是 fgets 很好心的幫我在字串後面加上 New Line(\n) 的標記..........就是因為這樣比對出來才不會是 0!!!

用 strcmp 看來是不行了,於是找了一下,發現有 int strncmp(const char *s1, const char *s2, size_t n) function 可以用,透過此 function 就可以指定比對的字串以及所要比對的長度囉!!

因此,我只要在第三個參數的部分設定為 5 即可!


還有另外一個 solution,即是透過 fgets 取得輸入後,將最後的「\n」給去除,只要用以下的程式碼即可:
#include <string.h>
char *usrInput;
*strrchr(usrInput, '\n') = '\0';

1 則留言:

  1. fgets 不是好心的加入 '\n'
    而是對 fgets 來說 '\n' 是它結束的條件
    故也是輸入的一部份

    char * fgets ( char * str, int num, FILE * stream );
    Get string from stream
    Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.

    A newline character makes fgets stop reading, but it is considered a valid character by the function and included in the string copied to str.

    回覆刪除