《C和指针》学习笔记(3)
1.5
在之前的rearrange函数语句中,
if (columns[col]>=len....) break;
当字符的列范围超过输入行的末尾就停止复制,这种方式只适合列范围以递增顺序排列的时候,请修改这条语句使列范围不是按顺序读取的时候也可以完成任务。
#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) { nchars=columns[col+1]-columns[col]+1; if(columns[col]>=len) /*需要处理的行标号大于输入行长度,进行下一次循环*/ continue; if(output_col>=MAX_INPUT-1) /*当输出行已经满跳出循环*/ break; if(output_col+nchars>MAX_INPUT-1); nchars=MAX_INPUT-output_col-1; /*如果输出行数据空间不够则只处理到能容纳到的数据*/ if(columns[col]+nchars>=len+1) /*防止把一个NUL字节过早的复制入输出行*/ nchars=len-columns[col]; strncpy(output+output_col,input+columns[col],nchars); output_col+=nchars; } output[output_col]='\0'; }
这道题本来想的是在read_columns_number语句中把列范围按顺序排列就好了。但是看了答案发现他是用上面的方法,使用continue语句我没有想到。额,有一个注意的细节就是它还多加了一个语句,防止把一个NUL字节复制进入输出行。但是这一点我很不理解,感觉并不需要啊。后来想想大概是列范围不是成对,在上面的判断条件中你只可以判断columns[col]是不是超过了输入行长度,而columns[col+1]你并没有判断,所以如果columns[col+1]超过了,你就需要把nchars的值改变。不知道自己理解的对不对。。。
我的答案:
#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; int i,j,k,t; 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); } for(i=0;i<num-1;i++) { k=i; for(j=i+1;j<num;j++) { if(columns[k]>columns[j]) k=j; } if(i!=k) { t=columns[i]; columns[i]=columns[k]; columns[k]=t; } } 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'; }
在read_columns_numbers函数中选择排序而已。。。。。
1.6
修改rearrange程序,去掉输入中列标号的个数必须是偶数的限制。如果读入的列个数为奇数个,函数就会把最后一个列范围设置为最后一个列标号所指定的列到行尾之间的范围。
这道题其实很简单,只需要把在rearrange函数中对于最后一个列标号进行处理就好了,但是我把const前缀取消了,没有答案,有更好的方法吗?
#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 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) { num+=1; } while((ch=getchar())!=EOF&&ch!='\n'); /*用来处理包含最后那个负值的所有字符*/ return num; } /*处理输入行*/ void rearrange(char *output,char const*input,int n_columns,int columns[MAX_CLOS]) { int col; /*columns数组的下标*/ int output_col; /*输出行的列计数器*/ int len; /*输入行的长度*/ int nchars; /*成对处理的列之间的长度*/ len=strlen(input); output_col=0; columns[n_columns-1]=len-1; 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'; }
第一章学完了,其实很慢了,但是每天还得学一些Java的知识,额,感觉Java还是没有入门,最近在刷learncodcademy上的Java课程以及网易云课堂之类的视频,但是看到封装之类的有些看不下去了,还是把《核心技术》好好再看看吧。以后也在这里写一写Java的心得体会吧。推荐一个网站,codehunt可以学Java和C#,微软培训Java的学姐推荐的,类似于闯关游戏,不过我好久也不写了,一会上完C实验课,回来写一下过关题解吧。