最近C語言已經學完,布置的大作業:學生管理系統5個版本也完成了。但是又買了一本《C和指針》,主要是感覺自己的指針還是沒有完全熟悉。所以還是要好好研究一下。閑話不多說,直接第一章。一看是快速入門,以為很簡單,但那個程序就把我卡了半天才看懂,按照作者說的的確運用了C語言中的大部分技巧。
程序1.1:首先讀取一串列標號,這些列標號成對出現,便是輸入行的列范圍。這串列標號以一個負值結尾,作為結束標志。剩余的輸入行被程序讀入並打印,然后輸入行中被選中范圍的字符串被提取出來打印。
書中代碼如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_CLOS 20 /*所能處理的最大列號*/ #define MAX_INPUT 1000 /*每個數入行的最大長度*/ int read_column_numbers(int columns[],int max); void rearrange(char *output,char const*input,int n_columns,int const columns[MAX_CLOS]); int main(void) { int n_columns; /*進行處理的列標號*/ int columns[MAX_CLOS]; /*需要處理的列數*/ char input[MAX_INPUT]; /*需要容納的輸入的數組*/ char output[MAX_INPUT]; /*容納輸出行的數組*/ n_columns=read_column_numbers(columns,MAX_CLOS); while(gets(input)!=NULL) /*如果讀入不存在輸入行則程序結束*/ { printf("Original input :%s\n",input); rearrange(output,input,n_columns,columns); printf("Rearranged line :%s\n",output); } return EXIT_SUCCESS; } /*讀取需要處理的列標號,如果超出規定范圍不予理會*/ int read_column_numbers(int columns[],int max) { int num=0; int ch; while(num<max&&scanf("%d",&columns[num])==1&&columns[num]>0) { /*這個循環條件保證了讀取的行號不會超過最大值,而且利用&&的短路特性, 也不會即使超過最大行號也不會被scanf讀入,同時scanf保證了讀入整型數據, 同時后面的條件輸入的為正數*/ num+=1; } /*判斷是否讀入的數據是成對的*/ if(num%2) { puts("Last column number is not paired."); exit(EXIT_FAILURE); } while((ch=getchar())!=EOF&&ch!='\n'); /*用來處理包含最后那個負值的所有字符*/ return num; } /*處理輸入行*/ void rearrange(char *output,char const*input,int n_columns,int const columns[MAX_CLOS]) { int col; /*columns數組的下標*/ int output_col; /*輸出行的列計數器*/ int len; /*輸入行的長度*/ int nchars; /*成對處理的列之間的長度*/ len=strlen(input); output_col=0; for(col=0;col<n_columns;col+=2) { if(columns[col]>=len||output_col==MAX_INPUT-1) /*如果輸入行的標號小於需要處理的列標號或者 輸出數組已滿結束任務*/ break; nchars=columns[col+1]-columns[col]+1; if(output_col+nchars>MAX_INPUT-1); nchars=MAX_INPUT-output_col-1; /*如果輸出行數據空間不夠則只處理到能容納到的數據*/ strncpy(output+output_col,input+columns[col],nchars); output_col+=nchars; } output[output_col]='\0'; }
一點點思考:不得不說,Kenneth這種大師思維的確很完善,要是我寫的確很多地方都想不到(我怎么敢和大師比2333!),比如while(ch=getchar())那個語句,一開始我百思不得其解,后來才明白為的是清除負值之后的字符(包括負值本身)因為這些字符雖然沒有被讀走,同時也仍然在stdin中存在。所以在主函數調用gets這個函數進行讀取的時候這些未被讀走的字符就會被解釋為第一行數據進而使我們得不到自己想要的結果。 而他對於可能造成數組越界訪問的情況也進行了處理。想想自己在寫的時候從來沒有在乎過這些,都是越界了才會debug找出來。另外一個細節就是他傳入rearrange這個函數的input數組,加了前綴const,防止函數內可能造成的改動。這點也是我需要學習的。
不過我也對於他的主函數設置的while條件有一些異議,gets函數在讀到文件尾(EOF)才會得到NULL,這種的確適合我們打開一個文件進行讀取的操作,因為這個文件的末尾一定會有EOF。但是如果我們在鍵盤輸入的時候,我們只有CtrlZ才可以得到EOF,這點總讓我感覺很不爽,其實主要是我懶不想摁CtrlZ,另外是我在書上並不是很理解它的輸入樣例(大家可以去看一下),里面沒有CtrlZ,所以,我並不是很懂作者的意思。但貌似沒有其他更好的方法了。就暫且認為是需要輸入CtrlZ。在這個問題上糾結這么久,我也是醉了。
這個程序的確很經典,包含的東西多但不難,其實大家可以按照示例試一下輸出,然后就會得到很好玩的結果了。感覺自己學了一學期C,還是什么都不會,自己打的時候打不下去,然后看了書的程序也是看了半天。。。可能是因為最近在看Java導致的吧。不能一天放松啊。。。