1 * 2 ** This program reads input lines from the standard input and prints 3 ** each input line, followed by just some portions of the lines, to 4 ** the standard output. 5 ** 6 ** The first input is a list of column numbers, which ends with a 7 ** negative number. The column numbers are paired and specify 8 ** ranges of columns from the input line that are to be printed. 9 ** For example, 0 3 10 12 -1 indicates that only columns 0 through 3 10 ** and columns 10 through 12 will be printed. 11 */ 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #define MAX_COLS 20 /* max # of columns to process */ 17 #define MAX_INPUT 1000 /* max len of input & output lines */ 18 19 int read_column_numbers( int columns[], int max ); 20 void rearrange( char *output, char const *input, 21 int n_columns, int const columns[] ); 22 23 int 24 main( void ) 25 { 26 int n_columns; /* # of columns to process */ 27 int columns[MAX_COLS]; /* the columns to process */ 28 char input[MAX_INPUT]; /* array for input line */ 29 char output[MAX_INPUT]; /* array for output line */ 30 31 /* 32 ** Read the list of column numbers 33 */ 34 n_columns = read_column_numbers( columns, MAX_COLS ); 35 36 /* 37 ** Read, process and print the remaining lines of input. 38 */ 39 while( gets( input ) != NULL ){ 40 printf( "Original input : %s\n", input ); 41 rearrange( output, input, n_columns, columns ); 42 printf( "Rearranged line: %s\n", output ); 43 } 44 45 return EXIT_SUCCESS; 46 } 47 48 * 49 ** Read the list of column numbers, ignoring any beyond the specified 50 ** maximum. 51 */ 52 int 53 read_column_numbers( int columns[], int max ) 54 { 55 int num = 0; 56 int ch; 57 58 /* 59 ** Get the numbers, stopping at eof or when a number is < 0. 60 */ 61 while( num < max && scanf( "%d", &columns[num] ) == 1 62 && columns[num] >= 0 ) 63 num += 1; 64 65 /* 66 ** Make sure we have an even number of inputs, as they are 67 ** supposed to be paired. 68 */ 69 if( num % 2 != 0 ){ 70 puts( "Last column number is not paired." ); 71 exit( EXIT_FAILURE ); 72 } 73 74 /* 75 ** Discard the rest of the line that contained the final 76 ** number. 77 */ 78 while( (ch = getchar()) != EOF && ch != ‘\n‘ ) 79 ; 80 81 return num; 82 } 83 84 * 85 ** Process a line of input by concatenating the characters from 86 ** the indicated columns. The output line is then NUL terminated. 87 */ 88 void 89 rearrange( char *output, char const *input, 90 int n_columns, int const columns[] ) 91 { 92 int col; /* subscript for columns array */ 93 int output_col; /* output column counter */ 94 int len; /* length of input line */ 95 96 len = strlen( input ); 97 output_col = 0; 98 99 /* 100 ** Process each pair of column numbers. 101 */ 102 for( col = 0; col < n_columns; col += 2 ){ 103 int nchars = columns[col + 1] - columns[col] + 1; 104 105 /* 106 ** If the input line isn‘t this long or the output 107 ** array is full, we‘re done. 108 */ 109 if( columns[col] >= len || 110 output_col == MAX_INPUT - 1 ) 111 break; 112 113 /* 114 ** If there isn‘t room in the output array, only copy 115 ** what will fit. 116 */ 117 if( output_col + nchars > MAX_INPUT - 1 ) 118 nchars = MAX_INPUT - output_col - 1; 119 120 /* 121 ** Copy the relevant data. 122 */ 123 strncpy( output + output_col, input + columns[col], 124 nchars ); 125 output_col += nchars; 126 } 127 128 output[output_col] = ‘\0‘; 129 }
1:首先关注程序的注释,我们在写程序的时候通常会加入很多注释,我们将其注释掉,并不到代表着我们将他从源代码中移除了,只不过是不起作用了而已,如果注释嵌套注释,可能还会出现问题,要从逻辑上删除一段c代码,最好使用#if
eg:
#if 0
statement
#endif这样我们的if条件表达式默认为false,之间的程序段可以有效的从程序中移除了
2:
预处理命令
我们上面代码的前5行都是预处理命令,他们都是由预处理器解释的,预处理器负责读入源代码,咱们我们将经过预处理后的代码递交给编译器,
stdio。h头文件使我们可以访问标准I/O库,
stdlib.h定义了EXIT_SUCCESS和EXIT_FAILURE
3:
gets函数负责从标准输入读取一行文本并将它传递到他的参数中,每一行字符串以一个换行符结尾,gets函数具有自动丢弃换行符,并在末尾自动加上一个NULL
的功能,当gets函数被调用但是并不存在输入行的时候,表示达到了输入的末尾,返回NULL
string 类型不存在与c语言,这一点不要同c++与java弄混
NULL是在stdio头文件中定义的
4:
在函数声明的数组传参中,我们对于数组的定义并未指定其长度,数组在接受传参的时候,无论传递给他的有多长,这个函数都照收不误,这是伟大的特性,但是我门不知道数组的长度,如果我们想知道数组的长度,我们需要额外再定义一个变量专门传递数组的长度
5:标准并未硬性规定c编译器对数组下标进行有效的检查,所以我们在程序中有的时候需要特别判断一下数组的越界与否的情况,如果在没判断的情况下超出了范围,那么多出来的数就会存放在数组紧随其后的位置,这样就占用了野地址,极有可能是其他变量的地址,
6:
scanf()函数的一些特性,我们在按照格式化读取变量的时候,如果按照%d读取的话,我们每次都是读取一个十进制的数,如果转换失败,函数都会返回0,这样return回去就会使得整个程序终止,如果可以合法的转化过去,这个数就会合理的转化为二进制存储在数组中,然后,scanf函数返回1,
7:puts()函数是gets函数的对应函数,puts具有自动加换行的功能
8:
exit_FAILURE这个值是被返回给操作系统,提示出现了错误
9:
78 while( (ch = getchar()) != EOF && ch != ‘\n‘ ) 79 ; 80
这段代码中我们申明了ch为int类型,为什么为int类型是因为EOF为-1为int类型,这事在stdio中北定义的
因为char类型其实也是就是小的整数,所以这里转化的时候不会出现错误
while后面加上一个分号称为空语句,当我们不需要循环中实现什么操作的时候,我们可以这么是实现
10:
rearrange函数
当数组名作为实参的时候,传递给函数的其实是一个只想首地址的指针,也就是数组在内存中的位置,正是因为我们传的只是一个地址而不是一份拷贝,所以我们在对形参进行操作的时候就会对主函数中的数组的变化产生影响,如果我们不希望产生这种影响,我们可以讲形参定义为const类型,
const类型有两个功能:1)声明的意图就是这个参数中的值不能改变
2)他导致编译器去验证是否违背了原则
11:
注意在void类型的函数中,我们不添加结束标志的程序return;并不表示没有,程序在执行结束之后会执行一条隐式的return;