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

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

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

相关文章
|
存储 搜索推荐 算法
《C和指针》读书笔记(第十一章 动态内存分配)
《C和指针》读书笔记(第十一章 动态内存分配)
|
存储 C语言
《C和指针》读书笔记(第十章 结构和联合)(下)
《C和指针》读书笔记(第十章 结构和联合)(下)
|
存储 C语言 C++
《C和指针》读书笔记(第十章 结构和联合)(上)
《C和指针》读书笔记(第十章 结构和联合)(上)
《C和指针》读书笔记(第九章 字符串、字符和字节)(下)
《C和指针》读书笔记(第九章 字符串、字符和字节)(下)
|
程序员 C语言
《C和指针》读书笔记(第九章 字符串、字符和字节)(中)
《C和指针》读书笔记(第九章 字符串、字符和字节)(中)
|
存储 C语言
《C和指针》读书笔记(第九章 字符串、字符和字节)(上)
《C和指针》读书笔记(第九章 字符串、字符和字节)(上)
|
存储 编译器 C语言
《C和指针》读书笔记(第八章 数组)(下)
《C和指针》读书笔记(第八章 数组)
|
存储 安全 编译器
[笔记]读书笔记 C++设计新思维《一》基于策略的类设计(下)
[笔记]读书笔记 C++设计新思维《一》基于策略的类设计(下)
|
存储 算法 编译器
C++ Primer Plus 第6版 读书笔记(8)第 8章 函数探幽(二)
C++ Primer Plus 第6版 读书笔记(8)第 8章 函数探幽(二)
70 1
|
存储 算法 Java
[笔记]读书笔记 C++设计新思维《二》技术(Techniques)(二)
[笔记]读书笔记 C++设计新思维《二》技术(Techniques)(二)