簡體   English   中英

C - 忽略 scanf() 中的空格

[英]C - Ignore spaces in scanf()

我正在嘗試進行簡單的字符串獲取。 我需要的是從輸入(stdin)中寫入一個字符串,它可以包含空格,並在單詞之間沒有空格的情況下保存它。

到目前為止,我已經編寫了這個簡單的代碼,它保存了所有內容(還有空格),但我不知道如何讓scanf()忽略空格。

int main(){
    char str[10];
    scanf("%[^\n]s, str);
    printf("%s", str;
}

例如

如果我的輸入是: I love C programming! 我的輸出應該是: IloveCprogramming!

我嘗試使用%* ,用於忽​​略字符,但沒有任何成功。

我也知道我可以“重新掃描”一次保存並刪除所有空格的字符串,但是我需要盡可能高效地進行此獲取,並且重新掃描每個字符串以刪除空格將大大增加計算時間(而不是只是掃描和忽略,其復雜度為 O(n))

您正在使用錯誤的工具來完成工作。 你需要使用getc

並執行以下操作

int ch;
char str[10];

// Loop until either loop reaches 9 (need one for null character) or EOF is reached
for (int loop = 0; loop < 9 && (ch = getc(stdin)) != EOF; ) {
   if (ch != ' ' ) {
     str[loop] = ch;
     ++loop;
   }
}
str[loop] = 0;

printf("%s", str);

無需重新掃描

如果有興趣從輸入中刪除其他空格(除了' ')您還可以合並C庫函數isspace(。) ,它測試以下標准空格字符:

''(0x20)空格(SPC)
'\\ t'(0x09)水平標簽(TAB)
'\\ n'(0x0a)換行符(LF)
'\\ v'(0x0b)垂直制表符(VT)
'\\ f'(0x0c)feed(FF)
'\\ r'(0x0d)回車(CR)

此示例使用isspace(.);合並函數isspace(.); 庫函數,並提供一種從C字符串中清除所有標准空格的方法。

int main(void)
{
    char string[] = {"this contain's \n whitespace\t"};
    int len = strlen(string);
    char out[len+1];// +1 for null terminator 
                    //(accommodates when input contains no whitespace)
    int count = clean_whitespace(string, out);

    return 0;
}

int clean_whitespace(const char *in, char *out)
{
    int len, count=0, i;
    if((in) && (out))
    {
        len = strlen(in);
        for(i=0;i<len;i++)
        {
            if(!isspace(in[i]))
            {
                out[count++] = in[i];
            }
        }
        out[count]=0;//add null terminator.
    }
    return count;
}

scanf()對你的目的沒有用,實際上你甚至不需要一個緩沖區來從輸入行中去除空格:只需要一次讀取一個字節,忽略空格,輸出其他空格並停止在換行符或EOF:

#include <stdio.h>

int main(void) {
    int c;
    while ((c = getchar()) != EOF) {
        if (c != ' ') {
            putchar(c);
        }
        if (c == '\n') {
            break;
        }
    }
    return 0;
}

另請注意您的代碼有問題:

  • scanf()格式字符串未終止
  • 尾隨s不正確,格式只是%[^\\n]
  • 在null終止符之前指定要存儲到數組中的最大字節數是更安全的: scanf("%9[^\\n]", str);
  • 你應該測試scanf()的返回值,以避免在轉換失敗時將uninitialize數組傳遞給printf ,例如在空行或空文件上。

您可以使用scanf()作為一種低效的方式來讀取字符而忽略空格,使用char c; while (scanf(" %c", &c) == 1) { putchar(c); } char c; while (scanf(" %c", &c) == 1) { putchar(c); } char c; while (scanf(" %c", &c) == 1) { putchar(c); }但是你會無法檢測到行的末尾。

到目前為止,我已經編寫了這個簡單的代碼,它保存了所有內容(也是空格),但我不知道如何使scanf()忽略空格。

你從與大多數新C程序員相反的方向來實現這一目標。 問題通常不是使scanf跳過空格,因為它默認為大多數類型的字段,特別是%s字段。 空格通常被識別為字段分隔符,因此不僅跳過前導空格,而且還不在字段內讀取空格。 我認為這是因為你知道你正在使用%[字段。

但你不能吃蛋糕也不能吃。 字段指令%[^\\n]表示要讀取的數據由一系列非換行符組成。 scanf將忠實地讀取所有這些字符並將它們傳輸到您指定的數組 您沒有選項來指示scanf避免傳輸您告訴它屬於該字段的一些字符。

如果您想繼續使用scanf那么您有兩個選擇:

  • 讀取數據后刪除空格,或
  • 讀取並將空格分隔的片段作為單獨的字段傳輸。

另一個答案已經描述了如何做前者。 以下是你如何做后者:

int main(void) {
    int field_count;

    do {
        char str[80];
        char tail;

        field_count = scanf("%79[^ \n]%c", str, &tail));
        if (field_count == 0) {
            // No string was scanned this iteration: the first available char
            // was a space or newline.  Consume it, then proceed appropriately.
            field_count = scanf("%c", &tail);
            if (field_count != 1 || tail == '\n') {
                // newline, end-of-file, or error: break out of the loop
                break;
            } // else it's a space -- ignore it
        } else if (field_count > 0) {
            // A string was scanned; print it:
            printf("%s", str);

            if (field_count == 2) {
                // A trailing character was scanned, too; take appropriate action:
                if (tail == '\n') {
                    break;
                } else if (tail != ' ') {
                    putchar(tail);
                } // else it is a space; ignore it
            }
        } // else field_count == EOF
    } while (field_count != EOF);
}

注意事項

  • scanf %79[^ \\n]指令中的79個字符(最大)字段寬度。 如果沒有字段寬度,則存在超出陣列邊界的嚴重風險(必須至少比字段長一個字符以允許字符串終止符)。
  • [是字段類型,而不是限定符。 s是一個單獨的字段類型,它也處理字符串,但具有不同的行為; 這里沒有使用s字段。
  • scanf的返回值告訴您成功掃描了多少個字段,如果在輸入和格式之間發生不匹配,或者到達輸入的結尾,或者I /,則可以少於格式字符串中描述的字段數。發生O錯誤。 需要考慮這些可能性。
  • 如果第二個字段%c實際上是掃描的,它允許您確定前面的字符串字段是否結束,因為字段寬度已經耗盡而沒有到達空格或換行符,因為觀察到空格,或者因為換行符被觀測到。 每種情況都需要不同的處理。
  • 雖然scanf跳過大多數字段類型的前導空格,但%[%c字段是三個例外中的兩個。
  • 這種方法專門跳過空格字符( ' ' ); 它不會跳過其他空格字符,例如水平和垂直制表符,回車符,換頁符等。這種方法也可以適用於處理這些字符,但所提供的內容足以證明。

我發布這個來證明也可以用scanf來解決這個問題。

 int main() {
   char a[10];
    for(int i = 0; i < 10 ; i++){
        scanf("%c", &a[i]);
        if( a[i] == ' ')
        i--;
    }
}

上面的一個只掃描10個字符,中間沒有空格。

    for(int i = 0; i < 9; i++){
       printf("%c,", a[i]);
     }

    printf("%c", a[9]);

如果你想用其他東西替換空格,這是使用的方式,例如:','

如果您希望輸入包含更多字符,只需定義一個新變量x並將10更改為x,將9更改為x-1

為了完整起見,這里有一個使用 scanf() 的簡單版本:

#include <stdio.h>

int main(void)
{
    char buff[10];
    int r;

    r = 1;

    while (r == 1) {
        scanf("%*[ ]");
        r = scanf("%9[^ \n]%*[ ]", buff);
        if (r == 1) fputs(buff, stdout);
    }

    putchar('\n');

    return 0;
}

這是做什么的:

  • scanf("%*[ ]") :跳過初始空格,如果有的話(請求格式:非空的空格序列,不將其存儲在變量中),忽略結果。
  • r = scanf("%9[^ \\n]%*[ ]", buff) :讀取兩種請求的格式(解釋如下)並返回成功轉換的次數。
    • %9[^ \\n] : 要求的格式:最多 9 個字符的連續文本(讀到換行符)。
    • %*[ ] : 請求格式:非空的空格序列,不將其存儲在變量中。
  • if (r == 1) fputs(buff, stdout) :檢查是否讀取了某些文本(從scanf()成功轉換 1 次)。 如果是,輸出它。

這在循環中執行,直到無法再讀取文本切片。 或者,可以使用getchar()讀取最終的\\n

示例執行:

$ ./scanstring 
             abcd          xyz        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa    wwwwwwwwwwwwwwwwwwwwwwwwwwww      zzzzz 1234567891011121314             !!!
abcdxyzaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaawwwwwwwwwwwwwwwwwwwwwwwwwwwwzzzzz1234567891011121314!!!

scanf()手冊: https : //man7.org/linux/man-pages/man3/scanf.3.html

暫無
暫無

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

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