第一章通过一个简单的例子,向读者说明了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