《C和指针》第1章 快速入手

1.1.2 预处理指令

#include <stdio.h>
#define MAX_COLS 20
这2行称为预处理指令(preprocessor directives),因为它们是由预处理器(preprocessor)解释的。预处理器读入源代码,根据预处理指令对其进行修改,然后把修改过的源代码递交给编译器。

int red_colum_number(int columns[], int max);
int rearrange(char *output, char const *input,int n_columns, int const columns[]);
这些声明称为函数原型(function prototype)。它们告诉编译器这些以后将在源文件中定义的函数的特征。

1.1.3 main 函数

int main(void){
这构成了main函数定义的起始部分。每个C程序都必须有一个main函数,因为它是程序执行的起点。关键字int表示函数返回一个整型值,关键字void表示函数不接受任何参数。main函数的函数体包括左花括号和与之相匹配的右花括号之间的任何内容。

在C语言中,数据参数是以引用(reference)形式进行传递的,也就是传址调用,而标量和常数则是按值(value)传递的。在函数中对标量参数的任何修改都会在函数返回时丢失,因此,被调用函数无法修改调用函数以传至形式传递给它的参数。然而,当被调用函数修改数组参数的其中一个元素时,调用函数所传递的数组就会被实际地修改。

在C程序中,处理字符串是常见的任务之一。尽管C语言并不存在“String”数据类型,但在整个语言中,存在一项约定:字符串就是一串以NUL字节结尾的字符。NUL是作为字符串终止符,它本身并不被看做是字符串的一部分。字符串常量(string literal)就是原程序中被双引号括起来的一串字符。例如,字符串常量:
“Hello”
在内存中占据6个字节空间,按顺序分别是H、e、l、l、o和NUL。
表1.1 常用printf格式代码

格式 含义
%d 以十进制形式打印一个整型值
%o 以八进制形式打印一个整型值
%x 以十六进制形式打印一个整型值
%g 打印一个浮点值
%c 打印一个字符
%s 打印一个字符串
\n 换行

scanf函数的返回值是函数成功转换并存储与参数中的值的个数。
**警告:**对于这个函数,首先,由于scanf函数的实现原理,所有标量参数的前面必须加上一个“&”符号。数组参数前面不需要加上“&”符号(但是,即使你在它前面加上一个“&”也没有什么不对)。但是,数组参数中如果出现了下标引用,也就是说实际参数是数组的某个特定元素,那么它的前面也必须加上“&”符号。
**警告:**第二个需要注意的地方是格式代码,它与printf函数的格式代码颇为相似却又并不完全相同,所以很容易引起混淆。表1.2粗略列出了一些你可能会在scanf函数中用到的格式代码。注意,前5个格式代码用于读取标量值,所以变量参数的前面必须加上“&”符号。使用所有格式代码(除了%c之外)时,输入值之前的空白(空格、制表符、换行符号)会被跳过,值后面的空白表示该值的结束。因此,用%s格式码输入字符串时,中间不能包含空白。除了表中所列之外,还存在许多格式代码,但是这张表里面的这几个格式代码对于应付我们现在的需求已经足够了。
表1.2 常用scanf格式码

格式 含义 变量类
%d 读取一个整型值 int
%ld 读取一个长整型值 long
%f 读取一个实型值(浮点数) float
%lf 读取一个双精度实型值 double
%c 读取一个字符 char
%s 从输入中读取一个字符串 char型数组

我们现在可以解释表达式:
scanf("%d",&columns[num])
格式码%d表示需要读取一个整型值。字符是从标准输入读取,前导空白将被跳过。然后这些数字被转换为一个整数,结果存储于指定的数组元素中。我们需要在参数前面加上一个“&”符号,因为数组下标选择的是一个单一的数组元素,它是一个标量。

/*
**取得列标号,如果所读取的数小于0则停止
*/
while(num<max && scanf("%d",&columns[num])==1 && columns[num]>0)
num += 1;
提示:标准并未硬性规定C编译器对数组小标的有效性进行检查,而且绝大多数C编译器确实也部进行检查。因此,如果你需要进行数组下标的有效性检查,你必须自行编写代码。如果此处不进行num<max这个测试,而且程序所读取的文件包含超过20个列标号,那么多出来的值就会存储在紧随数组之后的内存位置,这样就会破坏原先存储在这个位置的数据,可能是其他变量,也可以是函数的返回地址,这可能会导致多种结果,程序很可能不会按照你预想的那样运行。

警告:&&与&(按位与)不同
警告:==与=。因为这两个都是合法的表达式,所以编译器无法为你找出这个错误。

/*
**确认已经读取的标号为偶数个
*/
if(num % 2 != 0){
puts(“Last column number is not paired.”);
exit( EXIT_FAILURE );
}
num是否为偶数。%操作符执行整数的除法,但它给出的结果是除法的余数而不是商。
puts函数是gets函数的输出版本,它把指定的字符串写到标准输出并在末尾添上一个换行符。程序接着调用exit函数,终止程序的运行,EXIT_FAILURE这个值被返回给操作系统,提示出现了错误。

(ch = getchar() ) != EOF
getchar函数从标准输入读取一个字符并返回它的值。如果输入中不再存在任何字符,函数就会返回常量EOF(在stdio.h中定义),用于提示文件的结尾。

1.4 总结

本章的目的是描述足够的C语言的基础知识,使你对C语言有一个整体的印象。
本章的例子程序说明了许多要点。注释以/开始,以/结束,用于在程序中添加一些描述性的说明。#include预处理指令可以使一个函数库头文件的内容由编译器进行处理,#define指令允许你给字面值常量取个符号名。
所有的C程序必须有一个main函数,它是程序执行的起点。函数的标量参数通过传值的方式进行传递,而数组名参数则具有传址调用的语义。字符串是由一串由NUL字节结尾的字符,并且有一组库函数以不同的方式专门用于操纵字符串。printf函数执行格式化输出,scanf函数用于格式化输入,getchar和putchar分别执行非格式化字符的输入和输出。if和while语句在C语言中的用途跟它们在其他语言中的用途差不太多。

1.5 警告的总结

1. 在scanf函数的标量参数前未添加&字符。
2. 机械地把printf函数的格式代码照搬于scanf函数。
3. 在应该使用&&操作符的地方误用了&操作符。
4. 误用=操作符而不是==操作符来测试相等性。

1.6 编程提示的总结

1. 使用#include指令避免重复声明。
2. 使用#define指令给常量值取名。
3. 在#include文件中放置函数原型。
4. 在使用下标前先检查它们的值。
5. 在while或if表达式中蕴含赋值操作。
6. 如何编写一个空循环体。
7. 始终要进行检查,确保数组不越界。

猜你喜欢

转载自blog.csdn.net/lanzijingshizi/article/details/83506807