程序示例
/*
** 這個(gè)程序從標(biāo)準(zhǔn)輸入中讀取輸入行并在標(biāo)準(zhǔn)輸出中打印這些輸入行
** 每個(gè)輸入行的后面一行是該行內(nèi)容的一部分
**
** 輸入的第一行是一串列表號(hào),串的是最后以一個(gè)負(fù)數(shù)結(jié)尾
** 這些列標(biāo)號(hào)成對(duì)出現(xiàn),說明需要打印的輸入行的列的范圍
** 例如,0 3 10 12 -1 表示第0列到第3列,第10列到第12列的內(nèi)容將被打印
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_COLS 20 /* 所能處理的最大列號(hào) */
#define MAX_INPUT 1000 /* 每個(gè)輸入行的最大長度 */
int read_column_numbers(int columns[], int max);
void rearrange(char *output, char const *input,
int n_columns, int const columns[]);
int main(void){
int n_columns; /* 進(jìn)行處理的列標(biāo)號(hào) */
int columns[MAX_COLS]; /* 需要處理的列數(shù) */
char input[MAX_INPUT]; /* 容納輸入行的數(shù)組 */
char output[MAX_INPUT]; /* 容納輸出行的數(shù)組 */
/*
** 讀取該串列標(biāo)號(hào)
*/
n_columns = read_column_numbers(columns, MAX_COLS);
/*
** 讀取 處理 和 打印剩余的輸入行
*/
while(gets(input) != NULL){
printf("Original input: %s\n",input);
rearrange(output, input, n_columns, columns);
printf("Rearranged line: %s\n", output);
}
}
//讀取序列號(hào),如果超出范圍則不給予理會(huì)
int read_column_numbers(int columns[],int max){
int num = 0;
int ch;
//取得序列號(hào),如果讀取的序列號(hào)小于0則停止讀取
while (num < max && scanf("%d",&columns[num]) == 1 && columns[num] >= 0)
num ++;
//確認(rèn)已經(jīng)讀取的序列號(hào)為偶數(shù)個(gè),因?yàn)樗鼈兪浅蓪?duì)出現(xiàn)的
if (num%2 != 0){
puts("Last column number is not paired.");
exit(EXIT_FAILURE);
}
//丟棄該行中包含最后一個(gè)數(shù)字的那部分內(nèi)容
//比如當(dāng)出現(xiàn)-1后,如果后面還有內(nèi)容的話,后面的內(nèi)容應(yīng)該處理,否則會(huì)變?yōu)檩斎胱址畠?nèi)容
while ((ch = getchar())!= EOF && ch != '\n' );
return num;
}
//處理輸入行,將指定列的字符連在一起,輸出行以NUL結(jié)尾
void rearrange(char *output, char const *input, int n_columns, int const columns[]){
int col; /* columns數(shù)組的下標(biāo) */
int output_col; /* 輸出列計(jì)數(shù)器 */
int len; /* 輸入行的長度 */
len = strlen(input);
output_col = 0;
//處理每對(duì)列標(biāo)號(hào)
for (col = 0; col < n_columns; col += 2){
int nchars = columns[col+1] - columns[col] + 1;
//如果輸入行結(jié)束或輸出行數(shù)組已滿,就結(jié)束任務(wù)
if (columns[col] >= len || output_col == MAX_INPUT-1)
break;
//如果輸出行數(shù)據(jù)空間不夠,只復(fù)制可以容納的數(shù)據(jù)
if (output_col + nchars > MAX_INPUT-1)
nchars = MAX_INPUT - output_col -1;
//復(fù)制相關(guān)數(shù)據(jù)
strncpy(output+output_col,input+columns[col],nchars);
output_col += nchars;
}
output[output_col] = '\0';
}
預(yù)處理指令
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_COLS 20 /* 所能處理的最大列號(hào) */
#define MAX_INPUT 1000 /* 每個(gè)輸入行的最大長度 */
以上5行都為預(yù)處理指令。因?yàn)樗鼈兪怯?strong>預(yù)處理器解釋的。預(yù)處理器讀入源代碼,根據(jù)預(yù)處理指令對(duì)其進(jìn)行修改,然后將把修改后的源代碼遞交給編譯器。
函數(shù)原型
int read_column_numbers(int columns[], int max);
void rearrange(char *output, char const *input,
int n_columns, int const columns[]);
這些聲明被稱為函數(shù)原型。它們告訴編譯器這些以后將在源文件中定義的函數(shù)的特征。這樣,當(dāng)這些函數(shù)被調(diào)用時(shí),編譯器就能對(duì)它們進(jìn)行準(zhǔn)確性檢查。
參數(shù)傳遞
在C語言中,數(shù)組參數(shù)是以引用形式進(jìn)行傳遞的,也就是傳遞調(diào)用,而標(biāo)量和常量則是按值傳遞的。
- 注意
在函數(shù)中對(duì)標(biāo)量參數(shù)的任何修改都會(huì)在函數(shù)返回時(shí)丟失,因此,被調(diào)用函數(shù)無法修改調(diào)用函數(shù)以傳值形式傳遞給它的參數(shù)。然而,當(dāng)被調(diào)用函數(shù)修改數(shù)組參數(shù)的其中一個(gè)參數(shù)時(shí),調(diào)用函數(shù)所傳遞的數(shù)組會(huì)被實(shí)際地修改。
get函數(shù)
while(gets(input) != NULL){
printf("Original input: %s\n",input);
rearrange(output, input, n_columns, columns);
printf("Rearranged line: %s\n", output);
}
get函數(shù)從標(biāo)準(zhǔn)輸入讀取一行文本并把它存儲(chǔ)于作為參數(shù)傳遞給它的數(shù)組中。一行輸入由一串字符組成,以一個(gè)換行符結(jié)尾。gets函數(shù)丟棄換行符,并在該行的末尾存儲(chǔ)一個(gè)NUL字節(jié)。
字符串常量
字符串常量就是源程序中被雙引號(hào)括起來的一串字符。例如,“Hello”,在內(nèi)存中占據(jù)6個(gè)字節(jié)的空間,按順序分別是H、e、l、l、o和NUL。
printf函數(shù)
printf("Original input: %s\n",input);
scanf函數(shù)
while (num < max && scanf("%d",&columns[num]) == 1 && columns[num] >= 0)
scanf函數(shù)從標(biāo)準(zhǔn)輸入讀取字符并根據(jù)格式字符串對(duì)它們進(jìn)行轉(zhuǎn)換。scanf函數(shù)的返回值是函數(shù)轉(zhuǎn)換成功并存儲(chǔ)于參數(shù)中的值的個(gè)數(shù)。
- 注意
所有的標(biāo)量參數(shù)的前面必須加上一個(gè)“&”符號(hào),而對(duì)于數(shù)組參數(shù),可加可不加。但如果是數(shù)組中的一個(gè)參數(shù),則必須加。
puts("Last column number is not paired.");
put函數(shù)是gets函數(shù)的輸出版本,它把指定的字符串寫到標(biāo)準(zhǔn)輸出并在末尾添上一個(gè)換行符。
int ch;
while ((ch = getchar())!= EOF && ch != '\n' );
getchar函數(shù)從標(biāo)準(zhǔn)輸入流讀取一個(gè)字符并返回它的值。如果輸入中不再存在任何字符,函數(shù)就會(huì)返回常量EOF(在stdio.h中定義),用于提示文件的結(jié)尾。
- 為什么這里ch被聲明為整型?
EOF是一個(gè)整型值,它的位數(shù)比字符類型要多,把ch聲明為整型可以防止從輸入讀取的字符意外被解釋為EOF。但同時(shí),這也意味著接收字符的ch必須足夠大,足以容納EOF,這就是ch使用整型值的原因。實(shí)際上,字符只是小整型數(shù),所以用一個(gè)整型變量容納字符值不會(huì)引起任何變化。
const類型
void rearrange(char *output, char const *input, int n_columns, int const columns[]){
int col; /* columns數(shù)組的下標(biāo) */
int output_col; /* 輸出列計(jì)數(shù)器 */
int len; /* 輸入行的長度 */
當(dāng)數(shù)組名作為實(shí)參時(shí),傳給函數(shù)的實(shí)際上是一個(gè)指向數(shù)組起始位置的指針,也就是數(shù)組在內(nèi)存中的地址。將columns聲明為const有兩方面的作用:首先,它聲明該函數(shù)的作者的意圖是這個(gè)參數(shù)不能被修改。其次,它導(dǎo)致編譯器去驗(yàn)證是否違背該意圖。
strncpy函數(shù)
strncpy(output+output_col,input+columns[col],nchars);
strncpy函數(shù)的前兩個(gè)參數(shù)分別是目標(biāo)字符串和源字符串的地址,最后一個(gè)參數(shù)指定需要復(fù)制的字符數(shù)。