6

私は持っている:

#define MAX_STR_LEN 100

scanfそして、文字列の長さを制御できるようにパターンに入れたい:

scanf("%100[^\n]s",sometext)

私は試した:

scanf("%MAX_STR_LEN[^\n]s",sometext)
scanf("%"MAX_STR_LEN"[^\n]s",sometext)
scanf("%",MAX_STR_LEN,"[^\n]s",sometext)

そして、それはうまくいきませんでした。「sometext」が割り当てられているため、バッファオーバーフローを回避したいだけですmalloc(MAX_STR_LEN)...

何か案は?

4

5 に答える 5

10

私はこれらの解決策のどれにも満足できなかったので、さらに調査し、GNU GCC マクロ文字列化を発見しまし

次のように使用できます。

#define XSTR(A) STR(A)
#define STR(A) #A
#define MAX_STR_LEN 100
scanf("%"XSTR(MAX_STR_LEN)"[^\n]s", sometext)

多分VS2010は似たようなものを提供していますか?

于 2013-10-16T23:49:55.883 に答える
7

バッファオーバーフローを回避したいだけです

その後、使用しないでくださいscanf()。まったく。

テキストの行をスキャンしている場合も、そうしないでください#define MAX_STR。ハズインできます(POSIX互換システムをターゲットにLINE_MAX<limits.h>ている場合):

char buf[LINE_MAX];
fgets(buf, sizeof(buf), stdin);

トリックを行う必要があります。

于 2013-06-26T08:11:42.257 に答える
4

ほとんどの人が言うように、fgets(..., stdin)この問題を処理するには を使用することをお勧めします。

次のリンクでは、確実なマクロscanf()を使用して、より安全な方法に置き換えることができる安全で正しい手法を提案しました。

scanf()を安全に置き換えるマクロ

私が提案した (互換性のあるC99コンパイラで動作する) マクロはsafe_scanf()、次のプログラムに示すとおりです。

#include <stdio.h>
#define safe_scanf(fmt, maxb, ...) { \
    char buffer[maxb+1] = { [maxb - 1] = '\0' }; \
    fgets(buffer, maxb+1, stdin); \
    if ((buffer[maxb - 1] != '\0') && (buffer[maxb - 1] != '\n')) \
        while(getchar() != '\n') \
           ; \
    sscanf(buffer, fmt, __VA_ARGS__); \
  }

#define MAXBUFF 20     

int main(void) {
   int x; float f;      
   safe_scanf("%d %g", MAXBUFF+1, &x, &f);
   printf("Your input was: x == %d\t\t f == %g",  x, f);
   return 0;
}  

必要に応じて の値を調整MAXBUFFする必要があります...
マクロsafe_scanf()はかなりしっかりしています
が、マクロ アプローチの使用にはいくつかの弱点があります:
パラメータの型チェックの欠落、「戻り値」の欠落 (これは、intscanf()を返す「true」関数と、エラー チェックのための貴重な情報) など。 すべての問題には解決策がありますが、それは別のトピックの一部です...

おそらく、最も正確な解決策は、との組み合わせに結合しmy_scanf()てライブラリを呼び出すことにより、可変数のパラメーターを持つ関数を定義することです。ここにコードがあります: stdarg.hfgets()vsscanf()

#include <stdio.h>
#include <stdarg.h>

int my_scanf(const char* fmt, const unsigned int maxbuff, ...) {
    va_list ptr;
    int ret;

    if (maxbuff <= 0)
       return EOF; /* Bad size for buffer[] */

    char buffer[maxbuff+1];
    buffer[maxbuff-1] = '\0';  /* Quick buffer cleaning... */

    if (fgets(buffer, maxbuff+1, stdin) == NULL)
       return EOF; /* Error detected */
    else {
        if ((buffer[maxbuff-1] != '\n') && (buffer[maxbuff-1] != '\0'))
            /* Condition logically equivalent to:
                   fgets() has not reached an '\n'
            */
            while (getchar() != '\n')
               ; /* "Flushing" stdin... */

        va_start(ptr, maxbuff);
        ret = vsscanf(buffer, fmt, ptr);
        va_end(ptr);
        return ret;
    }    
}

#define MAXBUFF 20
int main(void) {
   int x; 
   float z;
   int scanf_ret = my_scanf("%d %g", MAXBUFF, &x, &z);
   printf("\nTest:\n x == %d\n z == %g\n scanfret == %d", x, z, scanf_ret);
   getchar();   
   return 0;   
}

関数 my_scanf() にはプロトタイプがあります

int my_scanf(const char* fmt, const int maxbuff, ...);

他の-likefmtと同じように動作するフォーマット文字列を受け入れます。2 番目のパラメーターは、標準入力 (キーボード) から有効に受け入れられる文字 の最大数です。 戻り値はintです。意味がないか、何らかの入力エラーが発生した場合です。負でない値が返された場合、標準関数またはによって返される値と同じです。 scanf()

EOFmaxbuffsscanf()vsscanf()

関数内では、'\0' 文字を追加するための余地ができるmaxbuffため、1 ずつインクリメントされます。 の正でない値はすぐに破棄されます。(キーボード)から読み取られる文字列を読み取り、'\n' を含む最大文字数の余地があります。ユーザーが非常に長い文字列を入力した場合、文字列は切り捨てられます。次の '\n' ( ENTER ) までのすべての文字を破棄するには、ある種の「フラッシュ」メカニズムが必要です。そうでない場合、次のキーボード読み取りで古い文字が使用される可能性があり、まったく望ましくありません。 「フラッシュ」の条件は、読み取り後に '\n' に達していないことです。 これは、次の場合にのみ当てはまります。fgets()
maxbuff
fgets()stdinmaxbuff

fgets()stdin
buffer[maxbuff - 1]'\0' にも '\n' にも等しくありません。
(確認してください! )最後に、マクロと関数
の適切な組み合わせを使用して、パラメーターの可変リストを処理します。 stdarg.h vsscanf()

于 2013-08-22T18:32:30.363 に答える
0

アプローチをお勧めしfgets(buffer, sizeof(buffer), stdin)ます。

それでもscanf() を使用したい場合は、実行時にそのフォーマットを作成できます。

#define MAX_STR_LEN 100
char format[2 + sizeof(size_t)*3 + 4 + 1];  // Ugly magic #
sprintf(format, " %%%zu[^\n]", (size_t) MAX_STR_LEN);
scanf(format, sometext);

または MAX_STR_LEN を文字列に再定義します

#define MAX_STR_LEN "100"
scanf(" %" MAX_STR_LEN "[^\n]", sometext);

それでもお勧めしfgets()ます。
Notefgets()は先頭のスペースと末尾\nをバッファーに入れますが、入れ" %[^\n]"ません。
ところで:sフォーマットの末尾は、あなたが考えていることをしていない可能性があります。

于 2013-06-30T06:58:27.443 に答える
-3

どうですか

scanf("%.*[^\n]s", MAX_STR_LEN, sometext)
于 2013-06-26T08:12:07.270 に答える