前記
最近找實習時候初入門了OJ,平時做題的時候是直接寫函數的,但是筆試的時候是需要自己編函數,自己寫輸入輸出的,自己寫主函數的,結果卡殼了很久,耽誤了很多時間,就來總結一下。(小白發言,若有錯誤敬請指正)
擷取資料輸入(數值)
- 在做筆試題時,常見給出多行輸入的情況,其中第一行會輸入以下幾行的行數或之類的資訊,然後将以下幾行放入一個一維或二維數組中。
例一:擷取一維數組
- 輸入: 第1行為n代表使用者的個數 第2行為n個整數,第i個代表使用者标号為i的使用者對某類文章的喜好度。第3行為一個正整數q代表查詢的組數 第4行到第(3+q)行,每行包含3個整數l,r,k代表一組查詢,即标号為l<=i<=r的使用者中對這類文章喜好值為k的使用者的個數。 資料範圍n <= 300000,q<=300000 k是整型(此處隻讀到第三行)
- 關鍵程式★★★★★:
//方法一:使用動态配置設定
int *res = (int*)malloc(numsSize * sizeof(int));
memset(res, 0, numsSize * sizeof(int));
//方法二:使用數組初始化
int nums[numsSize];
memset(nums,0,sizeof(int)*numsSize);
- 使用for循環來循環存入: scanf("%d",&like[i]);
5
1 2 3 3 5
3
//下面的未編入
1 2 1
2 4 5
3 5 3
- 對上述輸入可以先用scanf擷取行号和列号後再動态配置設定數組進行儲存。
#include<stdio.h>
#include<malloc.h>
int main(){
int num=0,gnum=0; //num代表的是n行,gnum代表的是使用者個數
scanf("%d",&num); //先讀到行數然後動态配置設定數組大小
int *like=(int*)malloc(sizeof(int*)*num);
memset(like, 0, num * sizeof(int));
//将每行資料寫入like中
for(int i=0;i<num;i++){
scanf("%d",&like[i]);
}
//printf("num=%d,like[1]=%d\n",num,like[1]);
scanf("%d",&gnum); //讀到下一次輸入的組數
//printf("%d",gnum);
}
- 運作結果為:
C語言擷取多組資料,輸入輸出問題
例二:擷取二維數組
- 将多行資料存入一個二維數組中。
3 3 //輸入第0行,表示 接下來要輸入n 行 m 列資料
1 2 3 //輸入第1行
11 12 13 //輸入第2行
21 22 23 //輸入第3行
- 對上述輸入先用scanf擷取行号和列号後再動态配置設定數組進行儲存。
- 關鍵程式★★★★★:
//動态配置設定存儲二維數組的大小,配置設定所有行的首位址
pArray = (int * * )malloc( n* sizeof(int *) );
// 按行配置設定每一列
pArray[i] = (int*)malloc( m * sizeof(int) );
scanf("%d", pArray[i] + j );
- 使用雙層循環來循環讀入:scanf("%d", pArray[i] + j );
#include<stdio.h>
#include<malloc.h>
int main(){
//初始化變量
int n = 0, m = 0;
int **pArray = NULL;
int i, j;
//擷取行列數
scanf("%d %d", &n, &m );
//動态配置設定存儲二維數組的大小
pArray = (int **)malloc( n * sizeof(int*) );
//使用雙層循環将資料讀入數組中
for( i=0; i<n; i++)
{
pArray[i] = (int*)malloc( m * sizeof(int) );
for( j=0; j<m; j++)
{
scanf("%d", pArray[i] + j );
}
}
//對讀入的資料進行測試
printf("============ 輸入資料測試 ============\n");
for( i=0; i<n; i++)
{
for( j=0; j<m; j++)
{
printf("%d ", pArray[i][j] );
}
printf("\n");
}
}
- 輸出結果測試:
C語言擷取多組資料,輸入輸出問題 C語言擷取多組資料,輸入輸出問題 - 解釋:scanf遇到空格會跳過,是以輸入不呈現3行3列時也可以正常讀取資料。
- 特别注意:此處for循環中的scanf中的%d後面千萬不用加空格,加上後無法正确讀取。
例三:多組輸入,每行都是相同讀取個數
- 輸入:第一行包括2個整數,N(1 <= N <= 1000),M(0 <= M <= N*(N-1)/2),代表現有N個人(用1~N編号)和M組關系;在接下來的M行裡,每行包括3個整數,a,b, c
- 輸入多組資料(未知幾行),且每行資料個數固定的情況:★★★★★ (以下方式等價)
- while(scanf("%d %d", &N, &M) != EOF)
- while(~scanf("%d %d", &N, &M) )
- 注釋:
-
(~為按位取反符号)
EOF->-1 int 4byte 32bit
原碼100000000000000000000000000000001
反碼111111111111111111111111111111110
補碼111111111111111111111111111111111
整形在記憶體中存儲的是補碼
~-1;
00000000000000000000000000000000即0
-
- 關鍵程式:
- while(scanf("%d %d", &N, &M) != EOF)
- scanf("%d %d %d", &a, &b, &c);
include <stdio.h>
int main()
{
int N, M;
// 每組第一行是2個整數,N和M,至于為啥用while,因為是多組。
while(scanf("%d %d", &N, &M) != EOF) {
printf("%d %d\n", N, M);
// 循環讀取“接下來的M行”
for (int i=0; i<M; i++) {
int a, b, c;
// 每行是3個整數,a,b,c。
scanf("%d %d %d", &a, &b, &c);
printf("%d %d %d\n", a, b, c);
}
// M行讀取完了,就又要開始下一組了,去while那裡。
}
}
例四:多組輸入,每行不同輸入個數
- 根據給定的個數進行循環寫入即可。
後記
結合這幾個例子,大概可以覆寫輸入的問題,儲存至一維數組、二維數組以及多組輸入(未知個數)時該如何擷取輸入的問題。
擷取字元串輸入
- 我個人感覺,scanf好用一點,因為可以直接跳過‘\n’,而用getchar的話需要再次調用取走緩沖區的‘\n’顯得有點麻煩的亞子。
- 注意點:getchar讀取字元會傳回字元的ascii碼值,是以char,int都可,但傳回值一般選取int,因異常時會傳回EOF,而EOF是-1,在char放不下。
讀取多組字元串輸入
//即End Of File 表示檔案末尾 (多組輸入)
while ((ch = getchar()) != EOF)
//清理緩沖區的\n清除緩存區的\n
getchar();
讀取字元串輸入的兩種方式
- 用getchar實作一個一個字元讀取。
- 用gets實作一行字元讀取。
- 注:如果不想用getchar來讀取\n進而消除的辦法,可以使用在%c前面加空格的方式來進行消除,此時寫作while (scanf (" %c", &ch) !=EOF)
//方法一:一個一個字元讀取
while (((ch=getchar() != '0') && ch != EOF)
//方法二:讀取一行字元
gets(str);
總結及細節注意點
1.EOF是End of File的意思,在C語言中定義的一個宏,用作檔案結束标志。該宏定義在stdio.h中,從數值角度看,就是-1。#define EOF (-1)
- 在Linux系統之中,EOF根本不是一個字元,而是當系統讀取到檔案結尾,所傳回的一個信号值(也就是-1)。
- 一般C在讀取資料時,都是按流模式進行資料讀操作,這裡的流可以是檔案,也可以是标準輸入。即:EOF可以表示檔案結尾,還可以表示标準輸入的結尾。
- 但是,标準輸入與檔案不一樣,無法事先知道輸入的長度,必須手動輸入一個字元,表示到達EOF。
- Linux中,在新的一行的開頭,按下Ctrl-D,就代表EOF
- Windows中,在新的一行的開頭,按下Ctrl-Z,就表示EOF。
2.scanf遇到空格就不讀了,getchar還會讀。在輸入緩沖區中scanf不會拿走輸入末尾的\n,是以還需要下一行輸入前,先用getchar取走留在緩沖區中的\n。如果不想用getchar來讀取\n進而消除的辦法,可以使用在%c前面加空格的方式來進行消除,此時寫作while (scanf (" %c", &ch) !=EOF))
注:scanf循環讀取時可以不考慮該問題,getchar會讀取到\n,是以在下次要用getchar前需要用getchar去掉\n才能讀取到對應字元串。
3.scanf需要加非格式字元,否則輸出不正常(非格式字元指描述語句,比如a=,b=)比如輸入:scanf(“a=%d,b=%d”,&a,&b);輸入時也需要加上a=,b=來描述對應,否則輸出不正常。
4.getchar讀取字元會傳回字元的ascii碼值,是以char,int都可,但傳回值一般選取int,因異常時會傳回EOF,而EOF是-1,在char放不下。
5.用getchar實作一個一個字元讀取,用gets實作一行字元讀取。
6.%s需要有結束标志,%c不需要。
7.printf傳回值為輸出字元的長度,是以有無\n是不同的,列印時(printf)有或沒有\n,資料長度是不一樣的。(有的話會+1)
8.判斷是不是字母可以直接用isalpha(ch)的方法,但是需要調用庫函數ctype.h
islower (ch)用來判斷是不是小寫字母。
isupper (ch)用來判斷是不是大寫字母。
toupper(ch));//小寫轉大寫
tolower(ch));//大寫轉小寫
參考文獻
OJ輸入輸出詳細講解
用scanf讀入多行資料
c中使用malloc動态申請二維數組