2017-05-31 51 views
0

我對C編程非常陌生。我的先生給了這個代碼找到最多n個數字。當我像Sir先生說的那樣,事情是完美的時候,例如在行中寫一個數字 - 輸入數字並在7,8 9 10行中輸入數字時,輸入數字彈出。瞭解scanf行爲

#include <stdio.h> 
main() 
{ 
    int n, max, number, i; 
    printf("Type the number of numbers"); 
    scanf("%d", &n); 
    if(n>0) 
    { 
     printf("Type the numbers"); 
     scanf("%d",&number); 
     max=number; 
     for(i=1; i<n; i++) 
     { 
      scanf("%d", &number); 
      if(number>max) 
       max=number; 
     } 
     printf("MAX=%d \n", max); 
    } 
} 

但是如果我寫假設 - 5 8 9 10 7 6 - 然後程序理解它喜歡 - 它把N = 5,然後把數= 8然後循環執行號變爲9然後數字變成10日至6日,然後gves最大。

那麼如何scanf在這裏工作?儘管它們被連續寫入空格,它會單獨佔用數字嗎?

+0

您可能還會閱讀'scanf'的一般頁面 - Google它編輯這裏是https://linux.die.net/man/3/scanf –

+0

空格和換行符是相同的:它分隔數字。你也可以試試TAB。他們被稱爲「白色空間」。 – ZDF

+1

'scanf'的'%d'按預期工作,因爲它跳過了以前的空白字符。 – BLUEPIXY

回答

1

From the horse's mouth

7.21.6.2 fscanf函數
...      這是一個轉換規格甲指令定義一個一套匹配輸入序列,如下面針對每個說明符所述的 。 A轉換規範在 以下步驟執行:

     輸入的空白​​字符(如由 isspace爲功能指定)被跳過,除非 說明書包括 [Ç ,或 n說明符。 284)

     的輸入項目是從該流讀取,除非本說明書中包括 Ñ說明符。輸入項目被定義爲輸入字符的最長序列,其不超過任何指定的字段寬度,並且是或匹配匹配輸入序列的前綴。 285) 輸入項目保持未讀狀態後的第一個字符(如果有的話)。如果輸入 項目的長度爲零,則指令的執行失敗;除非 文件結尾,編碼錯誤或讀取錯誤阻止來自流的輸入,否則此條件是匹配失敗,其中 是輸入失敗。

     除了在一個 說明符,輸入項目的情況下(或者,在一個 %N指令的情況下,輸入字符的 計數)被轉換成適當的類型轉換說明符。如果 輸入項目不是匹配序列,則指令的執行將失敗:此 條件是匹配失敗。除非分配抑制被 *指示,否則 轉換結果將放置在 之後的第一個參數指向的對象中,該參數尚未收到轉換結果。如果此對象 沒有適當的類型,或者對象中的轉換結果不能表示爲 ,則行爲未定義。
...
     轉換標識符和它們的含義如下:

                d        匹配任選符號十進制整數,其格式是相同的as
                           預期爲 strtol將功能的具有值10 主題序列爲
                           基座參數。相應的參數應該是一個指向 的有符號整數。
...
284)這些空白字符不會計入指定的字段寬度。

285)fscanf將最多一個輸入字符推回到輸入流上。因此,strtod,strtol等可接受的一些序列fscanf是不可接受的。

scanf的處理過程完全一樣;唯一的區別是scanf總是從標準輸入讀取。

實例:

假設你鍵入空間空間空間 響應於第一提示輸入;輸入流然後包含序列{' ', ' ', ' ', '1', '2', '3', '\n'}。當您致電scanf("%d", &n);時,scanf會讀取並丟棄前導空格,然後讀取並匹配序列{'1', '2', '3'},將其轉換爲整數值123,並將結果指定給n。由於成功轉換和分配,scanf返回1。

如果輸入流中包含的序列{' ', ' ', ' ', '1', '2', '.', '3', '\n'}scanf讀取並丟棄該前導空白,然後讀取並且序列{'1', '2'}匹配,將其轉換爲整數值12,並將結果n分配。輸入流仍將包含{'.', '3', '\n'}。因爲有一個成功的轉化率和分配,scanf將返回1

如果輸入流中包含的序列{'.', '3', '\n'},則存在的字符沒有匹配的序列('.'不在十進制整數的有效字符)。 scanf將使.未讀,並保留n的值不變。由於沒有成功轉換和分配,因此scanf返回0表示匹配失敗

如果最終的文件是在輸入流信號任何匹配的字符被讀取之前,或是否有其他一些輸入錯誤,scanf沒有任何新的值賦給n並返回EOF以指示輸入失敗

0

當您按下鍵盤時,您正在填充計算機上的緩衝區。 scanf會讀取連續數據量直到它碰到一個空格,所以在代碼scanf(「%d」)上的「1234 43」,你說的是「讀取一個數字」,而1234是一個數字,這就是它會讀取的內容。

但是,如果您有一個將再次執行scanf的循環,數字「43」當前在讀取緩衝區中,並且scanf將在不停止的情況下讀取它。

scanf手冊沒有說明這一點,對於新手來說,理解爲什麼應用程序不會在那裏停下來閱讀新號碼有點困惑。

+1

%d不讀取_number_ - 它讀取帶符號的十進制整數。即不是一個浮動,不是十六進制.... –

+0

而且,對於在計算機和編程上開始的任何人都是一個數字。讓我們不要太過於技術性並且混淆新手。 「 –

0

讓我儘可能簡單地解釋一下......

scanf讀取從標準輸入流stdin字節。

假設您給出的輸入是"23 67 21 99\n"(當您按Enter鍵時,\ n來自)。

然後scanf每下一個電話將開始從該輸入緩衝區中讀取,它會解釋,你告訴不管它是什麼見("%d",等等),而分離輸入一個空字符。這可能是一個新行,空格,製表等

雖然仍然字節被讀,scanf等待你輸入。這就是發生在這裏的事情。

+1

」,同時用空字符分隔輸入「 - >不完全。考慮''4 23 + 67-21 + 99 \ n「' – chux

+0

@chux也許這有點含糊,但我解釋了OP的具體問題,而不是scanf的一般工作原理。否則你是正確的。 – DeiDei

1

"%d"scanf("%d",&number);原因有3個階段掃描用戶文本輸入到int

  1. 0以上的領先白色空間,像' ''\n''\t'和其他一些人被讀取並丟棄。

  2. 數字文本如"123","-123","+123"被讀取,直到讀取一個非數字字符。 (或文件結束或罕見的輸入錯誤)。

  3. 對於隨後的輸入呼叫,該數字字符被放回stdin

如果步驟2成功地讀出至少1位,則該函數返回1.良好代碼檢查返回的值。

if (scanf("%d",&number) != 1) Handle_UnexpectedInput(); 

重要的是,'\n'不與scanf("%d",&number);特別之處。它像另一個空格或非數字文本一樣起到分隔符的作用。

'\n'不引起緩衝stdin由各個scanf()呼叫接受處理用戶輸入的

0

讓我們保持簡單。我假設你對緩衝區或標準輸入不瞭解。 scanf用於從用戶接收輸入。無論您何時鍵入一個號碼並在鍵盤上按'空格'或'輸入',該號碼都將被輸入到程序中以用於其他目的。當您鍵入scanf(「%d」,& n);這意味着取整數輸入從用戶和存儲它的地址變量n

+0

這很有幫助。但隨着程序進一步執行,程序如何返回整行(包含空格)的方式令人困惑。就像第2行3 4 5 6 7 8行一樣,它將首先採用數字2,然後運行一條語句,然後爲下一條語句執行一條語句,它將從用戶執行它之後執行3條語句,然後對於下一條語句,它將執行4條並執行它等等。 ..我的問題是爲什麼不是一個錯誤。我聽起來很可笑。你能否推薦我一本關於C的基礎知識的書來澄清這樣的疑惑。 scanf的行爲。 –

+0

** for(i = 1; i max)** //如果這個數字大於最大值, ** max = number; **/*那麼,max現在與該數字相同......但是如果數字小於max,如果不會執行並且max仍然是先前存儲的號碼。 * /因爲這是在循環中,在此之後scanf將被調用,並且這個{...}中的所有代碼都會重複。 Scanf不會從頭開始讀取數字,魔法是在'如果'情況下。 } – 2017-05-31 17:15:22

1

這是簡化的解釋(不是過於簡單,我希望)上從用戶的角度來看如何scanf作品:

的參數被分爲兩個部分:

  1. 第一部分是一個「格式字符串」。該字符串至少由 一個格式說明符組成。在其最簡單的形式中,一個說明符以 %開頭,後面跟着一個字母,它指定了您期望的 變量的類型(「%d」 - 我期待的是一個整數)。 指定者的數量必須匹配第二部分中的參數數量和類型 。

  2. 第二部分是由一個或多個地址組成的地址內存 您輸入的數據將被存儲。指定類型必須與指定符匹配

當被調用時,該函數將重複以下步驟,從第一個開始說明符和所述第一指針,直到檢測到格式字符串的末尾:

  1. 讀取和丟棄任何空白直到找到一個非空白字符(空格:空格,標籤,NL,至少);
  2. 讀取第一個空白字符或與當前說明符的期望輸入不匹配的字符;
  3. 將它們轉換爲當前指定符的類型並
  4. 將結果存儲在當前指針指向的位置。

有三種典型的初學者的錯誤這將導致不確定的行爲(崩潰,最有可能的):

  1. 您忘記了地址的運營商&
  2. 說明符和類型不匹配。
  3. 說明符的數量與指針的數量不匹配。

int d; 
    scanf("%d", d); // no & 
    scanf_s("%s", &d); // s do not match int 
    scanf_s("%d%d", &d); // too many specifiers 
+1

冒着複雜化的風險,'%c','%n'或'%[]'說明符不會跳過初始空白字符;這有時會導致初學者在輸入流中留下換行符時出現問題。此外,第一個不匹配的字符留在輸入流中,通常會導致稍後調用I/O函數時出現問題。 –

+0

@DavidBowling你是對的,但我擔心我已經使事情變得複雜。 – ZDF