1.1 简介
/*
**这个程序从标准输入中读取输入行并在标准输出中打印这些输入行
**输入的第一行是一串列标号,串的最后以一个负数结尾
**这些列标号成对出现,说明要打印的输入行的范围
**例如,0 3 10 12 -1表示第0列到第3列,第10列到第12列的内容将被打印
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_COLS 20
#define MAX_INPUT 100
int read_column_numbers(int columns[], int max);
void rearrange( char *output, char const *input, int n_columns, int const columns[]);
int main(void)
{
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(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;
/*
**读取列标号,如果所读取的数小于0则停止
*/
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';
}
程序输入输出:
1.1.1 空白和注释
如果我们想从逻辑上注释掉一段代码,怎么办?要用到预处理:
#if 0
statements
#endif
1.1.2 预处理指令
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_COLS 20
#define MAX_INPUT 100
这5行称为预处理指令,因为它们是由预处理器解释的。预处理器读入源代码,根据预处理指令对其进行修改,然后把修改过的源代码提交给编译器。
1.1.3 main函数
1. 每个C语言必须有一个main函数,因为它是程序执行的起点。
2. 在C语言中,数组参数是以引用形式进行传递的,也就是传址调用,而标量和常量则是按值传递的。
3. gets函数从标准输入读取一行文本并把它存储于作为参数传递给它的数组中。一行输入由一串字符组成,以一个换行符结尾。gets函数丢弃换行符,并在该行的末尾存储一个NUL字符(‘\0’)。然后,gets函数返回一个非NULL值,表示该行已被成功读取。当gets函数被调用但事实上不存在输入行时,它就返回NULL值,表示它达到了输入的末尾。
4. 在C程序中,处理字符串是常见的任务之一。一项约定是:字符串就是一串以NUL字节结尾的字符。NUL是作为字符串终止符,它本身并不被看作是字符串的一部分。字符串常量就是源程序中被双引号括起来的一串字符,比如"hello"在内存中占6个字节,最后一个字节为NUL。
但是,我这里测试时候,发现一个问题:
strlen是用来计算字符串的长度的,但是测试数组的长度怎么办,应该用sizeof来运算。但是我把以下代码放进去的时候,发现了一个问题,测试代码如下:
while (num < max && scanf("%d", &columns[num]) == 1 && columns[num] >= 0){
num += 1;
}
len = sizeof(columns) / sizeof(*columns);
printf("len:%d", len);
这是我添加的代码,但是函数输出:
为什么长度为1呢??即为什么sizeof(columns)不是20=int * 5而是4呢??
查了资料才发现,sizeof是在编译阶段就完成了。而这个函数中,数组的长度要到运行阶段才知道,所以无法正常的算出数组的长度。
5. ch = getchar()中ch之所以被声明为int是保证能与EOF进行比较,int的范围比char大了很多。
1.6 编程提示的总结
1. 使用#include指令避免重复声明
2. 使用#define指令给常量值取名
3. 在#include文件中放置函数原型
4. 在使用下标前先检查它们的值
5. 在while或if表达式中蕴含赋值操作
6. 如何编写一个空循环体
7. 始终要进行检查,确保数组不越界
习题:
1.
#include <stdio.h>
main()
{
printf("hello world\n");
}
2.
#include <stdio.h>
#include <stdlib.h>
main()
{
int c;
int nLine = 1; //行号
int isLine = 1; //判断是否显示行号
while ((c = getchar()) != EOF){
if (1 == isLine){
printf("%d:", nLine);
}
if (c == '\n')
{
isLine = 1;
nLine++;
printf("\n");
continue;
}
printf("%c", c);
isLine = 0;
}
}
程序输入输出:
3.
#include <stdio.h>
#include <stdlib.h>
main()
{
signed char checksum = -1;
int c;
while ((c = getchar()) != EOF){
checksum += c;
}
printf("%d\n", checksum);
}
程序输入输出:
4.
#include <stdio.h>
#include <stdlib.h>
#define MAX_LINE 1000
main()
{
char inputArr[MAX_LINE];
char outputArr[MAX_LINE];
int max = 0;
int len = 0;
while (gets(inputArr) != NULL){
len = strlen(inputArr);
if (len > max){
max = len;
strcpy(outputArr, inputArr);
}
}
printf("the longest line is:\n%s\nthe length is:%d\n", outputArr, max);
}
备注:outputArr声明为数组,所以outputArr就是其数据。如果声明为指针,则*outputArr为数据。
程序输入输出:
5.
/*
**这个程序从标准输入中读取输入行并在标准输出中打印这些输入行
**输入的第一行是一串列标号,串的最后以一个负数结尾
**这些列标号成对出现,说明要打印的输入行的范围
**例如,0 3 10 12 -1表示第0列到第3列,第10列到第12列的内容将被打印
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_COLS 20
#define MAX_INPUT 100
int read_column_numbers(int columns[], int max);
void rearrange( char *output, char const *input, int n_columns, int const columns[]);
int main(void)
{
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(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;
/*
**读取列标号,如果所读取的数小于0则停止
*/
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;
if ((-1 == columns[col]) || (output_col == MAX_INPUT - 1)) //用-1进行判断
break;
nchars = columns[col + 1] - columns[col] + 1;
if (columns[col] > len)
continue;
if (columns[col + 1] > len){
nchars = len - columns[col]; //这里保证复制的数据中不包含空格,以免导致'\0'使字符串结束
}
/*
**如果输出行数数据空间不够,只复制可以容纳的数据
*/
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';
}
程序输入输出:
6.
/*
**这个程序从标准输入中读取输入行并在标准输出中打印这些输入行
**输入的第一行是一串列标号,串的最后以一个负数结尾
**这些列标号成对出现,说明要打印的输入行的范围
**例如,0 3 10 12 -1表示第0列到第3列,第10列到第12列的内容将被打印
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_COLS 20
#define MAX_INPUT 100
int read_column_numbers(int columns[], int max);
void rearrange( char *output, char const *input, int n_columns, int const columns[]);
int main(void)
{
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(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;
/*
**读取列标号,如果所读取的数小于0则停止
*/
while (num < max && scanf("%d", &columns[num]) == 1 && columns[num] >= 0){
num += 1;
}
/*
**丢弃该行中包含最后一个数字的那部分内容
*/
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;
if (-1 == columns[col + 1]){
nchars = len - columns[col] + 1;
}
else{
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';
}
程序输入输出: