簡體   English   中英

如何在c中掃描一行的其余部分

[英]How to scan the rest of a line in c

我在文件Eg中有幾行整數

100 20 300 20 9 45 -1
101 80 80 2 80 2 50 3 70 -1

我想讀取前2個字符並將它們存儲在整數變量中,然后將其余字符存儲在一個字符串中,我可以稍后迭代。

do {
    fscanf(file, "%d %d", &var1,&var2);
    }while(!feof(file));

現在我想掃描剩余的線,移動到下一行並重復。 但我不知道如何將其余部分掃描成var3字符串

..有任何想法嗎?

這是你做的第一件事。 拋棄任何使用scanf("%s")想法,除非您完全控制輸入​​數據。 否則你會打開緩沖區溢出。

這個答案顯示了一種安全的方法,可以將fgets用於用戶輸入,提供緩沖區溢出檢測/避免和行清除,可以輕松地適應任何輸入流。

一旦你將行(和行)作為一個字符串,並因此知道它的最大大小,你可以簡單地使用:

char strBuff[1000]. str1[1000]; // Ensure both big enough.
:
// Use /getLine/fgets to get the line into strBuff.
:
int numScanned = sscanf (strBuff, "%d %d %[^\n]", &int1, &int2, str1);

什么%[^\\n]格式說明的作用是掃描任何數目的非新行字符到的字符串: []表示一個字符類中, ^表示“相匹配的一切,但以下的字符,並用於(非字符- )匹配是換行符\\n

標准引用在本答案(a)的底部。


例如,使用該功能:

#include <stdio.h>
#include <string.h>

#define OK       0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
    int ch, extra;

    // Get line with buffer overrun protection.
    if (prmpt != NULL) {
        printf ("%s", prmpt);
        fflush (stdout);
    }
    if (fgets (buff, sz, stdin) == NULL)
        return NO_INPUT;

    // If it was too long, there'll be no newline. In that case, we flush
    // to end of line so that excess doesn't affect the next call.
    if (buff[strlen(buff)-1] != '\n') {
        extra = 0;
        while (((ch = getchar()) != '\n') && (ch != EOF))
            extra = 1;
        return (extra == 1) ? TOO_LONG : OK;
    }

    // Otherwise remove newline and give string back to caller.
    buff[strlen(buff)-1] = '\0';
    return OK;
}

使用以下程序:

int main (void) {
    int rc, numScanned, int1, int2;;
    char strBuff[100], str1[100];

    rc = getLine ("Yes> ", strBuff, sizeof(strBuff));
    if (rc == NO_INPUT) {
        // Extra NL since my system doesn't output that on EOF.
        printf ("\nNo input\n");
        return 1;
    }

    if (rc == TOO_LONG) {
        printf ("Input too long [%s]\n", strBuff);
        return 1;
    }

    printf ("OK [%s]\n", strBuff);

    numScanned = sscanf (strBuff, "%d %d %[^\n]", &int1, &int2, str1);
    printf ("numScanned = %d\n", numScanned);
    printf ("int1       = %d\n", int1);
    printf ("int2       = %d\n", int2);
    printf ("str1       = [%s]\n", str1);

    return 0;
}

給出以下輸出:

Yes> 100 20 300 20 9 45 -1 blah blah blah
OK [100 20 300 20 9 45 -1 blah blah blah]
numScanned = 3
int1       = 100
int2       = 20
str1       = [300 20 9 45 -1 blah blah blah]

(a)7.20.6.2 The fscanf functionC11 (雖然這是從不變C99 )指出此有關[格式說明,稍稍轉述以除去無關的多字節的東西:

[ format specifier]匹配一組預期字符(scanset)中的非空字符序列。

相應的參數應該是指向大小足以接受序列的字符數組的初始元素的指針,以及將自動添加的終止空字符。

轉換說明符包括格式字符串中的所有后續字符,包括匹配的右括號( ] )。

括號(掃描列表)之間的字符組成掃描集,除非左括號后面的字符是抑揚符(^),在這種情況下,掃描集包含在旋轉和右括號之間的掃描列表中不出現的所有字符。 如果轉換說明符以[][^]開頭,則右括號字符位於掃描列表中,下一個右括號字符是結束規范的匹配右括號; 否則第一個右括號字符是結束規范的字符。

不,你可以使用scanf前提是你知道緩沖區的大小。 您可以避免緩沖區溢出測試它何時發生。 恢復邏輯搞砸了事情,但仍有可能。 我建議讓緩沖區足夠大,溢出真的是一種放棄和死亡的錯誤。

首先假設一個256-bye緩沖區,以及你需要聲明的其他一些變量。 您可以存儲的最長字符串是255個字節。 您可能希望掃描內部空白,但不希望最后的\\n換行符成為字符串的一部分。 (在這種情況下,這是fgets的主要問題。)神奇的序列是:

char var[256], endchar = '\n';
int n;

n = scanf("%255[^\n]%c", var, &endchar);
if ((n < 1) || (endchar!='\n') || ferror(stdin))
{
    if (n==2) { /*it's a buffer overflow*/ }
    else if (n==0 && !ferror(stdin)) { /*must be EOF on 1st byte*/ }
    else { /*an I/O error occurred*/ }
} else { /* OK */ }

這幾乎是防彈的,並且所有循環都發生在庫中。 scanf格式分解為:

  1. %255[^\\n] :除換行符外最多255個字符串。
  2. %c :存儲下一個內容的單個字符,如果有的話。

返回值是成功存儲的字段數。 那個, endchar的結束值和ferror()結果告訴你在一些if語句中你需要知道的一切。 單個if檢測到正常情況。

這允許EOF在最后一行沒有換行符。 在這種情況下, feof(stdin)將成為外循環檢測的真實。

PS:反對scanf %s (以及相關的%[] )的參數是有根據的,但是如果你能確保"nnn"值與緩沖區大小一致,則%nnns%nnn[]是完全安全的。 遺憾的是,沒有辦法為格式提供計算緩沖區大小。 我所知道的最佳選擇是使用sprintf()動態生成scanf()格式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM