《C和指针》读书笔记(第一章 快速上手)

本文通过一个实例详细解析了C语言中的头文件、宏定义以及输入输出语句的基础知识。讲解了`read_column_numbers`和`rearrange`两个函数,前者用于读取列号并检查是否成对,后者根据列号重新排列字符串。在`main`函数中,这两个函数被用来处理用户输入,提取指定列号范围的内容并输出。文章还分析了每个函数的内部逻辑,帮助初学者理解C语言的基本操作。
摘要由CSDN通过智能技术生成

第一章通过一个简单的例子,向读者说明了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_numbersrearrange两个函数,输入列标号的取值范围(成对),则会对后续输入的字符串进行提取,然后再打印输出,举例如下:

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-35-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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值