文档章节

C和指针---第一章:快速上手

fzyz_sb
 fzyz_sb
发布于 2013/09/11 23:26
字数 2494
阅读 165
收藏 1
点赞 0
评论 0

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';
}

程序输入输出:


© 著作权归作者所有

共有 人打赏支持
fzyz_sb
粉丝 404
博文 209
码字总数 447144
作品 0
武汉
程序员
手册中快速上手的例子,为什么访问应用不需要上下文?

@JFinal 你好,想跟你请教个问题: jfinal2.0手册第一章快速上手有个例子,启动jetty后访问http://localhost/hello即可请求到action,为什么这里url不需要应用上下文?...

Mr_Sky ⋅ 2015/11/24 ⋅ 1

快速上手Gobject

What is G-object? —很多人被灌输了这样一种概念:要写面向对象程序,那么就需要学习一种面向对象编程语言,例如C++、Java、C#等等,而C语言是用来编写结构化程序的。 —事实上,面向对象只...

shezjl ⋅ 2016/01/17 ⋅ 0

第一章 数组与指针概念剖析

数组与指针生来就是双胞胎,多数人就是从数组的学习开始指针的旅程的。在学习的过程中,很自然就会经常听到或见到关于数组与指针的各种各样的看法,下面我节选一些在各种论坛和文章里经常见到...

北极心 ⋅ 2016/08/11 ⋅ 0

使用Go语言一段时间的感受

最近在忙一个Server+Client的项目,Client是Android手机,大概也就是几十的规模。Server是纯Go语言实现,没有apache或者ngix这种web server,也没有数据库,自己写了个文件管理module,处理这...

acmfly ⋅ 2012/12/02 ⋅ 13

C语言和C++太难?没前途?谬论!

因为有些对C++并不了解,所以就简要介绍一下。很多人对C++语言都存在误解,以为C++就是C语言的扩展,包括我自己,最开始学习C++时也是这么认为的,一是因为名字太像了,然后C++面向过程部分,...

小辰GG ⋅ 2017/11/27 ⋅ 0

一、C语言概述

说明:这个C语言专题,是学习iOS开发的前奏。也为了让有面向对象语言开发经验的程序员,能够快速上手C语言。如果你还没有编程经验,或者对C语言、iOS开发不感兴趣,请忽略 为什么iOS开发要先...

长平狐 ⋅ 2013/03/28 ⋅ 1

F#系列随笔索引

循着我的Google笔记本,我看到第一条与F#相关的笔记发生在4月7日,到今天刚好6个月整。 为何要学习F#?这是个首当其冲的问题,跟当初“Java还是C#”这样的问题不同,现在是在学习一门新语言。...

长征3号 ⋅ 2017/12/21 ⋅ 0

《Python3.6官方文档》– 第一章

1. 开胃小菜 如果你有许多在电脑上的工作要做,并发现其中的任务一些是可以自动化的。 例如,你可能希望执行一个能够搜索并替换大量的文本文件程序,或者是有需要以一种复杂的方式去重命名和...

jowu ⋅ 01/24 ⋅ 0

即时 Linux 内核开发环境 - Linux Lab

Linux Lab 是一套基于 Docker 和 Qemu 的即时 Linux 内核开发环境,它也可以用于嵌入式 Linux 系统开发。 一、基本功能 基于 Docker,支持 Windows、Linux 和 Mac OSX,可一键安装,节约生命...

tinylab ⋅ 2017/12/06 ⋅ 4

转:再再再论指针

  一直以来想把2005年写的《再再论指针》修改一下,因为经过了这么多年,对C/C++的理解与05年相比又有了一些进展。但公司的工作一直很忙,没有时间进行修改工作。直到10月初的长假...

IMGTN ⋅ 2012/06/20 ⋅ 1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

个人博客的运营模式能否学习TMALL天猫质量为上?

心情随笔|个人博客的运营模式能否学习TMALL天猫质量为上? 中国的互联网已经发展了很多年了,记得在十年前,个人博客十分流行,大量的人都在写博客,而且质量还不错,很多高质量的文章都是在...

原创小博客 ⋅ 今天 ⋅ 0

JavaScript零基础入门——(十一)JavaScript的DOM操作

JavaScript零基础入门——(十一)JavaScript的DOM操作 大家好,欢迎回到我们的JavaScript零基础入门。最近有些同学问我说,我讲的的比书上的精简不少。其实呢,我主要讲的是我在开发中经常会...

JandenMa ⋅ 今天 ⋅ 0

volatile和synchronized的区别

volatile和synchronized的区别 在讲这个之前需要先了解下JMM(Java memory Model :java内存模型):并发过程中如何处理可见性、原子性、有序性的问题--建立JMM模型 详情请看:https://baike.b...

MarinJ_Shao ⋅ 今天 ⋅ 0

深入分析Kubernetes Critical Pod(一)

Author: xidianwangtao@gmail.com 摘要:大家在部署Kubernetes集群AddOn组件的时候,经常会看到Annotation scheduler.alpha.kubernetes.io/critical-pod"="",以表示这是一个关键服务,那你知...

WaltonWang ⋅ 今天 ⋅ 0

原子性 - synchronized关键词

原子性概念 原子性提供了程序的互斥操作,同一时刻只能有一个线程能对某块代码进行操作。 原子性的实现方式 在jdk中,原子性的实现方式主要分为: synchronized:关键词,它依赖于JVM,保证了同...

dotleo ⋅ 今天 ⋅ 0

【2018.06.22学习笔记】【linux高级知识 14.4-15.3】

14.4 exportfs命令 14.5 NFS客户端问题 15.1 FTP介绍 15.2/15.3 使用vsftpd搭建ftp

lgsxp ⋅ 今天 ⋅ 0

JeeSite 4.0 功能权限管理基础(Shiro)

Shiro是Apache的一个开源框架,是一个权限管理的框架,实现用户认证、用户授权等。 只要有用户参与一般都要有权限管理,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户...

ThinkGem ⋅ 昨天 ⋅ 0

python f-string 字符串格式化

主要内容 从Python 3.6开始,f-string是格式化字符串的一种很好的新方法。与其他格式化方式相比,它们不仅更易读,更简洁,不易出错,而且速度更快! 在本文的最后,您将了解如何以及为什么今...

阿豪boy ⋅ 昨天 ⋅ 0

Python实现自动登录站点

如果我们想要实现自动登录,那么我们就需要能够驱动浏览器(比如谷歌浏览器)来实现操作,ChromeDriver 刚好能够帮助我们这一点(非谷歌浏览器的驱动有所不同)。 一、确认软件版本 首先我们...

blackfoxya ⋅ 昨天 ⋅ 0

线性回归原理和实现基本认识

一:介绍 定义:线性回归在假设特证满足线性关系,根据给定的训练数据训练一个模型,并用此模型进行预测。为了了解这个定义,我们先举个简单的例子;我们假设一个线性方程 Y=2x+1, x变量为商...

wangxuwei ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部