第一章通过一个简单的例子,向读者说明了C语言的头文件、宏定义和输入输出语句等基础知识。
原文例子如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_COLS 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[]); int main() { int n_columns; int columns[MAX_COLS]; char input[MAX_INPUT]; char output[MAX_INPUT]; n_columns = read_column_numbers(columns,MAX_COLS); while (gets_s(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) { num += 1; } if (num % 2 != 0) { puts("last column number is not paired."); exit(EXIT_FAILURE); } while ((ch = getchar()) != EOF && ch != '\n') { ; } return num; } //处理输入行,将指定的字符连接在一起,输出行以NUL结尾。 void rearrange(char *output, char const *input, int n_columns, int const columns[]) { int col; //columns数组的下标 int output_col; //输出列计数器 int len; len = strlen(input); output_col = 0; //处理每对列标号 for (col = 0; col < n_columns; col += 2) { int nchars = columns[col + 1] - columns[col] + 1; //如果输入行结束或者输出行数组已满,就结束任务 if (columns[col] >= len || output_col == MAX_INPUT - 1) break; //如果输入行数据空间不够,只复制可以容纳的数据 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_column_numbers
和rearrange
两个函数,输入列标号的取值范围(成对),则会对后续输入的字符串进行提取,然后再打印输出,举例如下:
2 3 5 10 -10 hellow world! Original input : hellow world! Rearranged line: llw worl Let life be beautiful like summer flowers and death like autumn leaves. Original input : Let life be beautiful like summer flowers and death like autumn leaves. Rearranged line: t ife be
这样就提取了编号在2-3和5-10这两个范围内的内容。(众所周知,C语言的输入是从0开始计数的)下面我们来详细看看这三个函数的具体内容。
1.1 read_column_numbers函数
int read_column_numbers(int columns[], int max) { int num = 0; int ch; while (num < max && scanf("%d",&columns[num]) == 1 && columns[num] >= 0) { num += 1; } if (num % 2 != 0) { puts("last column number is not paired."); exit(EXIT_FAILURE); } while ((ch = getchar()) != EOF && ch != '\n') { ; } return num; }
先定义了相关变量。
然后读取输入的数值保存到数组columns
中,将输入的个数用变量num
保存,当数值小于0时候结束输入。
然后就是这部分代码:
if (num % 2 != 0) { puts("last column number is not paired."); exit(EXIT_FAILURE); }
很好理解,范围肯定是成对出现的,如果不是长队出现的,则会打印输出提示信息并退出当前窗口,这里有个小问题,就是没有添加窗口暂停,即使出现了提示信息,我们也是看不见的,只能看见窗口闪退,要解决这个问题,只需添加一条语句即可,添加后变成了这样:
if (num % 2 != 0) { puts("last column number is not paired."); system("pause"); exit(EXIT_FAILURE); }
剩下这部分也不难
while ((ch = getchar()) != EOF && ch != '\n') { ; }
如果没有停止(比方说windows下输入Ctrl+Z),并且没有换行,则停留在当前状态,否则结束当前循环。
1.2 rearrange函数
从函数的命名就可以看出来,这是重新安排的意思,也就是要对输入的内容进行二次处理。
void rearrange(char *output, char const *input, int n_columns, int const columns[]) { int col; //columns数组的下标 int output_col; //输出列计数器 int len; len = strlen(input); output_col = 0; //处理每对列标号 for (col = 0; col < n_columns; col += 2) { int nchars = columns[col + 1] - columns[col] + 1; //如果输入行结束或者输出行数组已满,就结束任务 if (columns[col] >= len || output_col == MAX_INPUT - 1) break; //如果输入行数据空间不够,只复制可以容纳的数据 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'; }
这个函数内容也比较容易理解,函数中最核心的就是for
循环中的内容,先读取每次需要读取的范围大小nchars
,比方说在上述的输出示例中, nchars = columns[1] - columns[0] + 1
也就是3 - 2 + 1 = 2。
接下来是两个条件判断,比较容易理解,略。
后来是一个复制语句,很重要,也就是将需要的部分复制给新的数组,以供输出。
strncpy(output + output_col, input + columns[col], nchars);
strncpy
的底层是这样实现的
char *strncpy(char *dst, const char *src, size_t len) { assert(dst != NULL && src != NULL); char *res = dst; while (len--) { *dst++ = *src++; } return res; }
也就是说,会将后面字符串的内容复制到前一个字符串,复制长度为len。但是需要注意的是,复制后,新的字符串并没有自动添加终止符。所以需要在结尾手动添加即可。
1.3 main函数
int main() { int n_columns; int columns[MAX_COLS]; char input[MAX_INPUT]; char output[MAX_INPUT]; n_columns = read_column_numbers(columns,MAX_COLS); while (gets_s(input) != NULL) { printf("Original input : %s\n",input); rearrange(output,input,n_columns,columns); printf("Rearranged line: %s\n",output); } return EXIT_SUCCESS; }
两个调用的函数分析完了,主函数也就不难了。
首先定义了四个变量,然后是
n_columns = read_column_numbers(columns,MAX_COLS);
其中n_columns
统计了区间数,也就是有多少个区间的字符需要复制,columns
保存了第一行的输入内容(最后的负数除外)。然后就进入了while的循环体,保证了连续的输入。
更新于2022.4.17