C语言程序设计基础(二)
高效性
C是一种高效的语言。在设计上它充分利用了当前计算机在能力上的优点。C程序往往很紧凑且运行速度快。事实上,C可以表现出通常只有汇编语言才具有的精细控制能力(汇编语言是特定的CPU设计所采用的一组内部指令的助记符。不同的CPU类型使用不同的汇编语言)。如果愿意,你可以细调程序以获得最大速度或最大内存使用率。
C是一种可移植语言。这意味着,在一个系统上编写的C程序经过很少改动或不经修改就可以其他系统上运行。如果修改是必要的,则通常只须改变伴随主程序的一个头文件中的几项内容即可。多数语言原本都想具有可移植性,但任何曾将IBM PC BASIC 程序转换为 Apple BASIC 程序(它们还是近亲)的人,或者试图在 UNIX 系统上运行一个 IBM 大型机 FORTRAN 程序的人都知道,移植至少是在制造麻烦。C 在可移植性方面处于领先地位。C 编译器(将C代码转换为计算机内部使用的指令的程序)在大约40多种系统上可用,包括从使用8位微处理器的计算机到Cray超级计算机。不过要知道,程序中为访问特定硬件设备(例如显示器)或操作系统(如Windows XP或OS X)的特殊功能而专门编写的部分,通常是不能移植的。
由于C与UNIX的紧密联系,UNIX系统通常都带有一个C编译器作为程序包的一部分。Linux中同样也包括一个C编译器。个人计算机,包括运行不同版本的 Windows 和 Macintosh 的PC,可使用若干种C编译器。所以不论你使用的是家用计算机,专业工作站还是大型机,都很容易得到针对你特定系统的C编译器。
C强大而又灵活(计算机世界中经常使用的两个词)。例如,强大而灵活的 UNIX操作系统的大部分便是用C编写的。其他语言(如 FORTRAN,Perl,Python,Pascal,LISP,Logo和BASIC)的许多编译器和解释器也都用C编写的。结果是,当你在一台UNIX机器上使用FORTRAN时,最终是由一个C程序负责生成最后的可执行程序的。C程序已经用于解决物理学和工程学问题,甚至用来为《角斗士》这样的电影制造特殊效果
C面向编程人员的需要。它允许你访问硬件,并可以操纵内存中的特定位。它具有丰富的运算符供选择,让你能够简洁地表达自己的意图。在限制你所能做的事情方面,C 不如Pascal这样的语言严格。这种灵活性是优点,同时也是一种危险。优点在于:许多任务(如转换数据形式)在C中都简单得多。危险在于:使用C时,你可能会犯在使用其他一些语言时不可能犯的错误。C给予你更多的自由,但同时也让你承担更大的风险。
一维数组
我们知道,要想把数据放入内存,必须先要分配内存空间。放入4个整数,就得分配4个int类型的内存空间:
int a[4];这样,就在内存中分配了4个 int 类型的内存空间,共 4×4=16 个字节,并为它们起了一个名字,叫 a 。
我们把这样的一组数据的集合称为 数组(Array) ,它所包含的每一个数据叫做数组 元素 ,所包含的数据的个数称为数组 长度 ,例如
int a[4];
就定义了一个长度为4的整型数组,名字是
a
。数组中的每个元素都有一个序号,这个序号从0开始,而不是从我们熟悉的1开始,称为下标。使用数组元素时,指明下标即可。
注意:数组中每个元素的数据类型必须相同,访问数组元素时,下标的取值范围为 0 ≤ index < 长度。
数组是一个整体,它的内存是连续的;也就是说,数组元素之间是相互挨着的,这为指针访问数组提供了便利。
当在函数中只定义数组时,数组里的值和函数里定义一个变量的值一样,都是未初始化过的,我们也可以定义的时候并初始化赋值,并且,当给部分元素赋初值的时候,未被赋值的元素将自动赋值为0,更细一些,int类型未被赋值的元素为0,浮点型为小数类型,而字符类型则为'\0'。如下:
int
a[5]={1,2};
//定义一个整型数组a,前2个元素即赋值为1,2,后3个元素值值全部为0
float
b[5]={1.1,2.2,3.3,4.4,5.5};
//定义float数组b并对全部float类型的元素都分别赋值
char
c[5]={
'a'
,
'b'
};
//定义一个数组名为c的字符型数组 并对前2个元素进行赋值,其余元素全部为'\0'
二维数组
二维数组的定义:
类型说明符 数组名[行数][列数]; 如:
int
a[3][4];
/*定义一个整形二维数组a,有3行4列共12个元素分别为:
a[0][0] a[0][1] a[0][2] a[0][3]
a[1][0] a[1][1] a[1][2] a[1][3]
a[2][0] a[2][1] a[2][2] a[2][3]
*/
char
arry[10][10];
//定义一个字符型二维数组arry,有10行10列,依次为arry[0][0]~arry[9][9]供100个元素
注意:二维数组与一维数组一样在内存中的存储也是按照线性排布的。
程序运行虽然只执行主函数main内的语句,但是在主函数中可以调用其他函数从而执行其他函数实现不同的功能。函数定义基本格式如下:
dataType functionName( dataType1 param1, dataType2 param2 ... ){
//body}
dataType 是返回值类型,它可以是C语言中的任意数据类型,例如 int、float、char 等。
functionName 是函数名,它是标识符的一种,命名规则和标识符相同。函数名后面的括号()不能少。
body 是函数体,它是函数需要执行的代码,是函数的主体部分。即使只有一个语句,函数体也要由{}包围。
如果有返回值,在函数体中使用 return 语句返回。return 出来的数据的类型要和 dataType 一样。
dataType1 param1, dataType2 param2 ...是参数列表,可有可无,也可以是一个或多个。
注意:主函数或其他函数内只能调用函数,不能定义函数;且调用的函数必须在此之前已经声明或定义。
没学指针就是没学C语言!指针是C语言的精华,也是C语言的难点,破解C语言指针,会让你的C语言水平突飞猛进。
datatype *name ;
datatype表示该指针变量所指向的数据的类型
*表示这是一个指针变量
name表示指针变量名
指针简单使用:
#include <stdio.h>
int main(){
int a = 15;
int *p;
p = &a;
printf("%d, %d\n", a, *p); //两种方式都是输出a的值
return 0;
}
注意:
定义指针变量时必须带*,给指针变量赋值时不能带*。
要想更加了解指针,还需要清楚以下重要概念:
概念 | 描述 |
---|---|
指针的算术运算 | 可以对指针进行四种算术运算:++、--、+、- |
指针数组 | 可以定义用来存储指针的数组。 |
指向指针的指针 | C 允许指向指针的指针。 |
传递指针给函数 | 通过引用或地址传递参数,使传递的参数在调用函数中被改变。 |
从函数返回指针 | C 允许函数返回指针到局部变量、静态变量和动态内存分配。 |
结构体(Struct)从本质上讲是一种自定义的数据类型,只不过这种数据类型比较复杂,可以包含多个其他类型的数据。常用来存放一组不同类型的数据。结构体的定义的一般形式如下:
struct 结构体名{
结构体所包含的变量或数组
};
结构体是一种集合,它里面包含了多个变量或数组,它们的类型可以相同,也可以不同,每个这样的变量或数组都称为结构体的成员(Member)。
结构体变量定义一般格式如下:
struct 结构类型名 结构变量名;
访问结构体成员的一般格式如下:
结构体变量名.成员名;
结构体指针的定义形式一般为:
预处理命令可以改变程序设计环境,提高编程效率,它们并不是 C 语言本身的组成部分,不能直接对 它们进行编译,必须在对程序进行编译之前,先对程序中这些特殊的命令进行“预处理” 。经过预处理后,程序就不再包括预处理命令了,最后再由编译程序对预处理之后的源程序进行编译处理,得到可供执行的 目标代码。C 语言提供的预处理功能有三种,分别为宏定义、文件包含和条件编译。
宏定义
宏定义的一般格式如下:
#define 标识符 内容;
“#”表示这是一条预处理命令(凡是以“#”开头的均为预处理命令)
“define”为宏定义命令
“标识符”为所定义的宏名,
“内容”可以是常数、表达式、符号等
编译时,将先由预处理程序进行宏替换,即用宏定义内容去置换所有对应的宏定义标识符,然后 再进行编译。
文件包含
文件包含的一般形式如下:
#include "头文件名"
或者
#include <头文件名>
#include <头文件名> 这种形式用于引用系统头文件
#include "头文件名" 这种形式用于引用用户头文件。
条件编译
预处理程序提供了条件编译的功能,可以按不同的条件去编译不同的程序部分,因而产生不同 的目标代码文件,这对于程序的移植和调试是很有用的。
部分预处理器指令如下:
指令 | 描述 |
---|---|
#define | 定义宏 |
#include | 包含一个源代码文件 |
#undef | 取消已定义的宏 |
#ifdef | 如果宏已经定义,则返回真 |
#ifndef | 如果宏没有定义,则返回真 |
#if | 如果给定条件为真,则编译下面代码 |
#else | #ifdef,#ifndef,#if 的替代方案 |
#endif | 结束一个 #ifdef(#ifdef,#if)……#else 条件编译块 |
条件编译可分为三种形式。
第一种形式如下:
#ifdef 标识符
程序段 1
#else
程序段 2
#endif
它的功能是如果标识符已被 #define 命令定义过则对程序段 1 进行编译;否则对程序段 2 进行编译。常用于头文件内。
第二种形式如下:
#ifndef 标识符
程序段 1
#else
程序段 2
#endif
它的功能是如果标识符未被#define 命令定义过则对程 序段 1 进行编译,否则对程序段 2 进行编译。
第三种形式如下:
#if 表达式
程序段 1
#else
程序段 2
#endif
它的功能是如果常量表达式的值为真(非 0),则对程序段 1 进行编译,否则对程序段 2 进行编译。