【C语言】C语言中的函数及参数传递,变量的作用域和生存期、多文件程序、宏定义

目录

1、函数的定义、调用、声明

1.1函数的定义

1.2 函数的调用

1.3函数调用的形式

1.3.1代码演示

 1.4函数的声明

1.4.1函数声明的格式

 2、函数参数的传值

2.1 单向传递

2.2双向地址传递

 3、嵌套调用和递归调用

3.1嵌套调用

3.2递归调用

 4、变量的使用范围和存储类别

4.1 局部变量与全局变量

4.2变量的存储类别

4.2.1auto类型的局部变量

4.2.2static类型的局部变量、全局变量

4.2.3全局变量

4.2.4 extern类型的全局变量

4.2.5register类型的全局变量

5、多文件程序

5.1C源文件的划分

5.2C源文件的格式

6、用带参数的宏代替公式型函数


1、函数的定义、调用、声明

1.1函数的定义

当 C编译系统提供的标准数据库不满足用户需要时,用户可以自己定义函数

C语言中函数的基本格式为:

函数类型 函数名 (类型1  形式参数1,类型2  形式参数2,……类型n 形式参数n)

{

说明部分

语句部分

}

说明:

(1)一般将函数类型 函数名 (类型1  形式参数1,类型2  形式参数2,……类型n 形式参数n)称为函数的首部,或函数头;大括号内称为函数体。

(2)函数类型,即:函数值的类型

(3)函数名用合法标识符命名,最好能够有见名知意的效果,函数名后紧跟一对小括号,中间不要加空格

(4)形式参数简称形参,指函数中的自变量,它们是从函数外部向函数内部运送值的数据通道。形式参数根据需要可以有1个、多个或没有。定义时每个形参(自变量)都应指出各自的类型

(5)函数体主要包括变量说明和可执行语句,两者可以根据情况缺省。若都为空,也合法,称为空函数

(6)变量说明部分主要是定义运算所需要的变量。因为这些变量在函数的内部定义,又称为局部变量。只在函数内部有效,不能在函数外使用

(7)语句部分主要是利用已定义的变量进行运算,得到结果

(8)有些函数末尾会写return语句,相当于是从函数内部向函数外部运送值的数据通道。返回值类型需要跟函数类型匹配,即:赋值兼容。若程序不需要计算结果,那就将此函数类型写为void。

注意:

一个函数中可以有多个return语句

return语句后面可以是变量、常量、表达式,也可以用小括号将它括起来

若无return语句,遇到函数结尾的“}”时,程序自动返回调用函数

函数类型最好与return语句返回的值类型保持一致,若不一致,函数结果以函数类型为准,由C编译系统自动完成类型转换。

例如

int f(int a,int b)

{

int s;

s=a+b;

return s;

}

1.2 函数的调用

函数定义完毕后,需要使用一下,验证函数定义是否正确。

使用C程序的函数,称为函数调用,函数调用的格式:

        函数名(实际参数1,实际参数2,……,实际参数n);

实际参数简称实参,可以是常量、变量、表达式。实参的个数、类型应该跟形参一一对应匹配。实参主要是用于给形参一一对应传送数据。

1.3函数调用的形式

使用函数调用的形式有:

(1)函数调用作为一条语句;

(2)函数有明确的返回值时,函数调用可以当作普通变量使用,作为表达式的一部分。

(3)函数有明确的返回值时,函数调用可以作为其他函数的实参。

1.3.1代码演示

题目1:编写函数是吸纳打印输出以下图形的功能

/*
   *
  ***
 *****
******* 
*/
#include <stdio.h>
void printStar(){
	int i,j,k;
	for(i=0;i<=3;i++){//行数 
		for(j=0;j<=2-i;j++)//空格 
		{
			printf(" "); 
		}
		for(k=0;k<=2*i;k++){
			printf("*");
		}
		printf("\n");
	}
}
int main(){
	printStar();
	return 0;
}

题目2:定义pow函数,实现求x^{y}的功能。只考虑x和y均为正整数的情况

#include<stdio.h>
int pow(int x,int y){
	int i,p=1;
	for(i=1;i<=y;i++){
		p*=x;
	}
	return p;
}
int main(){
	printf("%d的%d次方是%d\n",5,3,pow(5,3));
	return 0;
}

 题目3:定义bigger函数,实现求2个整数中较大值的功能。利用此函数求3个整数中的最大值

//定义bigger函数,实现求2个整数中较大值的功能。利用此函数求3个整数中的最大值
#include<stdio.h>
int bigger(int a,int b){
	return a>b?a:b;//求a,b中较大值作为结果返回 
}
int main(){
	int x,y,z,max;
	printf("请输入三个需要比较的数:");
	scanf("%d%d%d",&x,&y,&z);
	max=(bigger(bigger(x,y),z));//三个数需要调用两次 
	printf("最大值为:%d\n",max);
	return 0;
	
}

 1.4函数的声明

为了防止C编译系统会提示找不到函数,可以在函数调用前面加上函数声明。

1.4.1函数声明的格式

函数声明由函数首部加上分号组成。例如:函数f的函数声明为:int f(int a,int b);也可以将参数名省略,例如:int f(int,int);。

函数声明使用

#include<stdio.h>
int f(int a,int b);//函数声明 
int main(){
	int c;
	c=f(3,5);
	printf("c=%d\n",c);
	return 0;
}
int f(int a,int b){
	int s;
	s=a+b;
	return s;
} 

 2、函数参数的传值

2.1 单向传递

当基本类型的常量或变量作函数的实参时,形参与实参可以同名,它们占用不同的内存空间。从实参到形参的数据传递是单向的,数据只是从实参传给形参,而不能由形参传递给实参。即:形参值的改变不会影响到实参,因此这种传递称为:“单向值传递”

 代码演示:

2.2双向地址传递

当地址常量或地址变量(例如数组名)作为函数的实参时,从实参到形参传递的是地址,形参与实参使用相同的内存空间。形参值的改变会影响到实参,这种传递也称为“双向地址传递”

代码演示:有一个已按从小到大的顺序排列的整型数组,从键盘输入一个整数,按照数组原来的排列规律将此数插入到数组中。写一个函数insertNumber实现此功能,并测试。

#include<stdio.h>
#define N 10
void insertNumber(int a[N],int num); 
void insertNumber(int a[N],int num){
	int i,j;
	if(num>a[N-2]){
		a[N-1]=num;
	}
	else{
		for(i=0;i<=N-2;i++){
			if(num<a[i]){
				for(j=N-2;j>=i;j--){
					a[j+1]=a[j];
				}
				a[i]=num;
				break;
			}
		}
	}
}
int main(){
	int a[N]={-9,5,12,33,45,47,66,76,89};
	int i,num;
	printf("插入num前的数组\n:");
	for(i=0;i<=N-2;i++){
		printf("%2d\n",a[i]);
	} 
	printf("请输入要插入的数字:");
	scanf("%d",&num);
	insertNumber(a,num);
	printf("插入num后的数组:\n");
	for(i=0;i<=N-1;i++){
		printf("%d\n",a[i]);
	} 
	return 0;
}

 3、嵌套调用和递归调用

3.1嵌套调用

一个函数调用另一个函数,另一个函数又调用其他函数,称为函数的嵌套调用。C规定函数定义不可嵌套,但可以嵌套调用函数。

编写程序计算s=\sum_{k=1}^{n}k!

#include<stdio.h>
int fac(int k){
	int i,mul=1;
	for(i=1;i<=k;i++){
		mul*=i;
	}
	return mul;
}
int sum(int n){
	int i,total=0;
	for(i=1;i<=n;i++){
		total+=fac(i);
	}
	return total;
}
int main(){
	int n;
	printf("请输入正整数n:");
	scanf("%d",&n);
	printf("s=%d\n",sum(n));
	return 0;
}

3.2递归调用

 一个函数直接调用自己本身或者通过调用其他函数来间接调用自己,也称递归函数

递归问题:

有5个人坐在一起,问第5个人多少岁?他说比第4个人大5岁。问第4个人岁数,他说比第3个人大5岁。问第3个人,又说比第2个人大5岁。问第2个人,说比第1个人大5岁。最后问第1个人,他说他10岁。问第5个人多大?

#include<stdio.h>
int age(int n){
	if(n==1){
		return 10;
	}
	else{
		return age(n-1)+5;
	}
}
int main(){
	printf("第5个人的年龄是%d岁。\n",age(5));
	return 0;
}

用递归调用求n的阶乘

求阶乘的数学公式:

n!=\left\{\begin{matrix} 1&n=0,1 \\ n\cdot \left ( n-1 \right )!& n>1 \end{matrix}\right.

#include<stdio.h>
int fac(int n){
	int f;
	if(n<0){
		printf("n<0,数据出错!");
	}
	else if(n==0||n==1){
		f=1;
	}
	else{
		f=fac(n-1)*n;
		return f;
	}
}
int main(){
	int n,y;
	printf("请输入一个正整数:");
	scanf("%d",&n);
	y=fac(n);
	printf("%d的阶乘等于%d\n",n,y);
	return 0;
}

 4、变量的使用范围和存储类别

编译连接程序时,有可能会遇到这样的问题,明明需要的变量、函数都已经定义了,可编译器还是会跳出一些诸如某变量未定义、某函数找不到的错误信息。这不是因为编译器有问题,而是可能会涉及到变量、函数的作用域、生命期等要素。

4.1 局部变量与全局变量

根据其使用范围不同,可以划分为局部变量和全局变量。

局部变量(也称为内部变量):在函数内部定义,有效范围是从定义处开始,到本函数结束为止。

全局变量(也称为外部变量):在函数外部定义,不作特殊声明的情况下,有效使用范围是从定义处开始,到所在源文件末尾为止。当局部变量缺少的时候才使用全局变量

说明:

(1)不同函数中的同名变量,是两个不同的变量,占用不同内存单元。

(2)函数的形式参数属于局部变量

(3)若全局变量与局部变量同名,则在局部变量的有效范围内,全局变量被屏蔽

(4)若未给局部变量赋值,其值为随机值;若未给全局变量赋值,其值为0。

局部变量的有效区域:

 因为a和b定义在main函数中,只在main函数中生效,如果超过此范围程序就会认为其没有定义。

全局变量的有效范围:

a和b定义在外部,所以是全局变量,又因为main函数和fun函数内部没有定义a和b,所以就会使用全局变量。

不同函数中的同名局部变量:

 不同函数中断的局部变量同名,它们互不相关。

局部变量和全局变量同名:

 fun函数没有局部变量,所以使用全局变量,而main函数有局部变量,所以优先选择局部变量。

4.2变量的存储类别

                                                                 用户内存区

静态数据存储区
动态数据存储区

            程序存储区

 一个变量完整的定义除了变量的数据类型之外,还应加上存储类型的限制,格式如下:

[存储类型] 数据类型 变量名;

C语言中,变量的存储类型可以分为四类:auto(自动型)、static(静态型)、register(寄存器型)、extern(外部型)。

变量有效范围生命周期默认值
局部变量(auto)变量定义开始到函数结束函数调用开始到调用结束随机值
static局部变量变量定义开始到函数结束整个程序执行开始到整个程序结束该数据类型里面表示假的值
static全局变量

变量定义开始到

定义所在文件结束

整个程序执行开始到整个程序结束该数据类型里面表示假的值

extern全局变量

(不能扩展static全局变量)

整个程序整个程序执行开始到整个程序结束该数据类型里面表示假的值

变量的生命周期指的是在程序运行过程中,变量从创建到撤销的一段时间,下面将分情况说明不同的存储类型定义变量的生命周期、有效范围的影响。

4.2.1auto类型的局部变量

形参和局部变量,不加任何修饰时,默认为auto类型的局部变量。这类变量存放在内存中的动态存储区,生命周期与所在函数的代码块共存亡。

局部变量的生命周期:

 4.2.2static类型的局部变量、全局变量

static修饰的全局变量和局部变量称为静态全局变量和静态局部变量。这类变量存放在内存中的静态存储区,生命周期与程序共存亡。在程序开始执行前给它们分配内存,在程序执行完毕时释放内存。在程序执行过程中它们占据固定的存储空间。生命周期是到整个程序结束,有效范围是到所在的源文件结束。生命周期比有效范围长。

静态局部变量的生命周期:

4.2.3全局变量

普通的全局变量存放在内存中的静态存储区,生命周期到整个程序结束。它的有效范围可以通过将其声明为extern类型扩展到整个程序结束。

虽然全局变量A的生命期是整个程序,在整个程序中都占有内存,但是它的有效区域是test1.c文件,在test2.c文件中不能使用test1.c

4.2.4 extern类型的全局变量

extern类型的全局变量存放在内存中的静态存储区,生命周期到整个程序结束,它的有效范围是到整个程序结束,两者一致。

 extern int A还可以写成 extern A,这不是重新定义变量A,而是将定义的全局变量A的有效区域扩展到test2.c文件中。

用extern扩展static类型全局变量的有效区域

静态全局变量A的有效区域是其定义所在文件test1.c,不能扩展它的有效范围到程序中的其他文件。

4.2.5register类型的全局变量

 有些使用频繁的变量,为了节省存取变量时花费的时间,提高程序效率,可以将其设置为register类型的变量,直接从寄存器中存取。例如:在一个函数中执行100000此循环,每次循环都要用到某个局部变量i,就可以将其说明为register类型。

5、多文件程序

5.1C源文件的划分

C源文件可以分为两类,一类是包含实际代码的基本程序文件,另一类是为基本程序文件提供信息的辅助文件。基本程序文件通常以.c为扩展名,称为头文件、head文件、或h文件。

若决定采用多文件方式实现程序,应该将哪些内容放入头文件,哪些放入程序文件?多文件程序的内容安排需要遵循以下原则:

(1)头文件中只写可执行语句以外、不分配内存空间的描述,包含:文件包含命令、公共类型的定义、结构/联合/枚举说明:函数声明;变量extern说明;公用的宏定义等。

(2)程序文件中定义所有的全局变量、函数和只在一个文件中使用的类型等。

(3)只用#include包含头文件;不用它来包含程序文件。

(4)通过头文件解决文件间信息传递的问题。将多个文件有关的函数声明、全局变量的声明写入头文件。在定义和使用它们的程序文件中都包含此头文件,就可以正确使用它们。

5.2C源文件的格式

一般情况下,源程序中所有的行都参加编译。但是有时希望按照不同的条件去编译不同的程序部分,这就是“条件编译”。

条件编译的一种常用格式:

#indef 标识符

        程序段1

#else

        程序段2

#endif

功能:如果标识符未被#define命令定义过,则对程序段1进行编译,否则对程序段2进行编译,本格式中的#else可以省略

在编写大型程序时,通常将所用到的函数原型、外部变量、全局类型的声明,头文件的包含命令统一编写在一个头文件中,将函数实现统一编写在一个源程序文件(文件名与头文件同名)中实现。主函数main放在主函数文件main.c中。

(1)student.h的一般形式:

/*student.h 头文件 */

#ifdef_STUDENT_H__

/*如果未用#define定义标识符__STUDENT_H__,则编译如下程序段 */

#define _STUMENT_H__

        头文件包含命令

        全局类型声明

        全局变量声明

        函数声明

#endif

(2)student.c的一般形式:

/*student.c源程序文件,写函数的定义*/

#include "student.h"

……

(3)main.c 一般形式

/*main.c源程序文件,写函数的调用

#include "student.h"

int main()

{

……

}

代码演示:

题目1:输入4个学生的5门课的成绩,分别用函数实现下列功能:

(1)计算每个学生的平均成绩

(2)计算每门课程的平均成绩

(3)查找最高成绩,输出最高成绩对应的学生序号和课程序号。

 student.h文件

#ifndef _STUDENT_H__   
#define _STUDENT_H__
#define N 4
#define M 5
extern float score[N][M];
extern float max;
extern int s_num,c_num;
float aver_stu(int n);
float aver_course(int m);
void high_score();
#endif

 student.c文件

#include<stdio.h>
#include "student.h"
float aver_stu(int n){
	int i;
	float sum=0.0f;
	for(i=0;i<=M-1;i++)
	{
		sum+=score[n][i];
	}
	return sum/M;
}

float aver_course(int m){
	int i;
	float sum=0.0f;
	for(i=0;i<=N-1;i++)
	{
		sum+=score[i][m];
	}
	return sum/N;
}
void high_score(){
	int i,j;
	max=score[0][0];
	for(i=0;i<=N-1;i++){
		for(j=0;j<=M-1;j++)
		{
			if(max<score[i][j])
			{
				max=score[i][j];
				s_num=i+1;
				c_num=j+1;
			}
		}
	}
}

main.c文件

#include<stdio.h>
#include "student.h"
float score[N][M];
float max;
int s_num,c_num;
int main()
{
	int i,j;
	printf("请分别输入%d名学生的%d门成绩:\n",N,M);
	for(i=0;i<=N-1;i++)
	{
		for(j=0;j<=M-1;j++)
		{
			scanf("%f",&score[i][j]);
		}
	}
	for(i=0;i<=N-1;i++)
	{
		printf("输出第%d个学生的平均成绩:",i+1);
		printf("%.1f\n",aver_stu(i));
	}
		for(j=0;j<=M-1;j++)
	{
		printf("输出第%d门课程的平均成绩:",j+1);
		printf("%.1f\n",aver_course(j));
	}

high_score();
printf("最高分是第%d个学生的第%d门成绩:%.1f\n",s_num,c_num,max);
return 0;
}

输出结果:

6、用带参数的宏代替公式型函数

我们在之前学习过使用宏定义来定义符号常量,例如 #define PI 3.14159,这属于无参数的宏定义。C语言允许宏定义中包含参数。带参数的宏定义的一般形式为:

        #define 宏名(形参列表) 宏体

说明:

①宏名一般用大写字母表示

②形参列表中的形参多于1个时,各个参数之间用逗号隔开。形参在这里是标识符,不分配内存单元,因此不必作类型说明。

③宏体是被替换用的字符串,宏体中的字符串是由参数表中的各个参数组成的表达式。

④宏定义属于预编译命令的一种,不是C语言中的语句,因此结尾不需要加分号。

        带参数宏调用的一般形式为:

        宏名(实参序列);

利用带参数的宏求两个整数的较大值

用带参数的宏求圆的面积

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很好用的东西很经典的一本C教程,TKS这算是谭浩强C语言设计比较新的版本了!目录很详细,使用很方便目录 第1章 C语言程序设计的概念  1.1 程序程序设计语言   1.1.1 计算机与程序   1.1.2 计算机程序设计语言   1.1.3 高级语言程序开发过程  1.2 C语言及其标准   1.2.1 C语言的出现   1.2.2 C语言的标准  1.3 C语言程序概要   1.3.1 函数   1.3.2 语句   1.3.3 名字与声明   1.3.4 变量及其赋值   1.3.5 算术运算   1.3.6 赋值类运算符的副作用及限制  习题一 第2章 基本数据类型  2.1 基本数据类型的特征   2.1.1 数值的定点表示与浮点表示   2.1.2 整数的有符号类型与无符号类型   2.1.3 类型宽度与取值范围  2.2 数据常量   2.2.1 整型常量   2.2.2 字符类型及其常量   2.2.3 实型常量   2.2.4 符号常量  2.3 数据类型转换   2.3.1 几个概念   2.3.2 数据类型的隐式转换   2.3.3 数据类型的显式转换   2.4 数据的控制台输入与输出   2.4.1 格式化输出函数pIintf()   2.4.2 格式化输入函数scanf()   2.4.3 字符输入/输出函数getchar()与putchar()  习题二 第3章 C语言程序的流程控制  3.1 算法   3.1.1 算法的组成要素与基本性质   3.1.2 算法描述工具   3.1.3 自项向下、逐步细化的算法设计过程  3.2 判断   3.2.1 命题的“真”、“假”与C语言的逻辑值   3.2.2 关系运算与关系表达式   3.2.3 逻辑运算与逻辑表达式  3.3 选择型程序设计   3.3.1 if...else结构的应用   3.3.2 if.elseif结构的应用   3.3.3 switch结构的应用   3.3.4 条件表达式  3.4 循环型程序设计   3.4.1 迭代与穷举算法   3.4.2 while结构   3.4.3 dowhile结构   3.4.4 for结构   3.4.5 循环结构的途退出与重复周期的途结束  习题三 第4章 模块化程序设计  4.1 函数   4.1.1 设计C语言程序就是设计函数   4.1.2 函数结构   4.1.3 函数定义与函数声明   4.1.4 虚实结合与传值调用   4.1.5 递归函数  4.2 变量的存储属性   4.2.1 变量作用域生存期   4.2.2 C语言变量的存储类型   4.2.3 通过const声明将变量存储在只读区  4.3 模块的编译与链接   4.3.1 分别编译   4.3.2 用项目管理多文件程序的编译与链接过程   4.3.3 头文件  4.4 宏定义与宏替换   4.4.1 字符串宏定义及其基本格式   4.4.2 使用宏需注意的问题   4.4.3 撤销己定义的宏   4.4.4 带参数的宏定义  习题四 第5章 数组  5.1 一维数组   5.1.1 一维数组定义及数组元素引用   5.1.2 数组元素的引用方法   5.1.3 一维数组的初始化   5.1.4 一维数组元素的查找与排序   5.1.5 数组与函数  5.2 字符串   5.2.1 字符数组与字符串   5.2.2 字符串的输入/输出   5.2.3 字符串处理函数  5.3 二维数组与多维数组   5.3.1 二维数组及其定义   5.3.2 二维数组的初始化   5.3.3 向函数传送二维数组   5.3.4 多维数组  习题五 第6章 指针  6.1 指针基础   6.1.1 地址与指针   6.1.2 指针变量及其定义   6.1.3指针变量的引用   6.1.4 指针的移动与比较   6.1.5 指向指针变量的指针与多级指针   6.1.6 指向void类型的指针  6.2 指针与数组   6.2.1 数组元素的指针引用   6.2.2 多字符串的存储与处理   6.2.3 内存的动态分配与动态数组的建立  6.3 指针与函数   6.3.1 指针参数与函数的地址传送调用   6.3.2 带参数的主函数   6.3.3 返回指针值的函数   6.3.4 指向函数的指针  习题六 第7章 用户定制数据类型  7.1 结构体类型基础   7.1.1 结构体类型及其定制   7.1.2 定义结构体类型变量及对变量的初始化   7.1.3 结构体变量的操作   7.1.4 嵌套结构体类型   7.1.5 位段  7.2 结构体数组   7.2.1 结构体数组的定义与初始化   7.2.2 对结构体数
CruiseYoung提供的带有详细书签的电子书籍目录 http://blog.csdn.net/fksec/article/details/7888251 该资料是《C语言入门经典(第4版)》的源代码及课后练习答案 对应的书籍资料见: C语言入门经典(第4版) 基本信息 原书名: Beginning C: From Novice to Professional, Fourth Edition 原出版社: Apress 作者: (美)Ivor Horton 译者: 杨浩 出版社:清华大学出版社 ISBN:9787302170839 上架时间:2008-4-15 出版日期:2008 年4月 开本:16开 页码:571 版次:4-1 编辑推荐    本书是编程语言先驱者Ivor Horton的经典之作,是C语言方面最畅销的图书品种之一,在世界范围内广受欢迎,口碑极佳。    本书的目标是使你在C语言程序设计方面由一位初学者成为一位称职的程序员。 内容简介   本书是编程语言先驱者Ivor Horton的经典之作,是C语言方面最畅销的图书品种之一。本书集综合性、实用性为一体,是学习C语言的优秀入门教材,在世界范围内广受欢迎,口碑极佳。书除了讲解C程序设计语言,还广泛介绍了作为一名C程序设计人员应该掌握的必要知识,并提供了大量的实用性很强的编程实例。本书的目标是使你在C语言程序设计方面由一位初学者成为一位称职的程序员。读者基本不需要具备任何编程知识,即可通过本书从头开始编写自己的C程序。 作译者 作者   Ivor Horton是世界著名的计算机图书作家,主要从事与编程相关的咨询及撰写工作,曾帮助无数程序员步入编程的殿堂。他曾在IBM工作多年,能使用多种语言进行编程(在多种机器上使用汇编语言和高级语言),设计和实现了实时闭环工业控制系统。Horton拥有丰富的教学经验(教学内容包括C、C++、Fortran、PL/1、APL等),同时还是机械、加工和电子CAD系统、机械CAM系统和DNC/CNC系统方面的专家。IvorHorton还著有关于C、C++和Java的多部入门级好书,如《C语言入门经典(第4版)》和《C++入门经典(第3版)》。 译者   杨浩,知名译者,大学讲师,从事机械和计算机方面的教学和研究多年,发表论文数篇,参编和翻译的图书多达20余部,还曾多次获得市部级奖项。近几年一直在跟踪.NET技术的发展,积极从事.NET技术文档和图书的翻译工作。 目录 封面 -12 封底 572 前言 -9 目录 -6 第1章 C语言编程 1 1.1 创建C程序 1 1.1.1 编辑 1 1.1.2 编译 2 1.1.3 链接 2 1.1.4 执行 3 1.2 创建第一个程序 4 1.3 编辑第一个程序 4 1.4 处理错误 5 1.5 剖析一个简单的程序 6 1.5.1 注释 6 1.5.2 预处理指令 7 1.5.3 定义main()函数 7 1.5.4 关键字 8 1.5.5 函数体 8 1.5.6 输出信息 9 1.5.7 参数 10 1.5.8 控制符 10 1.6 用C语言开发程序 12 1.6.1 了解问题 12 1.6.2 详细设计 12 1.6.3 实施 13 1.6.4 测试 13 1.7 函数及模块化编程 13 1.8 常见错误 17 1.9 要点 17 1.10 小结 18 1.11 习题 18 第2章 编程初步 19 2.1 计算机的内存 19 2.2 什么是变量 21 2.3 存储数值的变量 21 2.3.1 整数变量 21 2.3.2 变量的命名 25 2.3.3 变量的使用 26 2.3.4 变量的初始化 28 2.3.5 算术语句 28 2.4 变量与内存 34 2.5 整数变量类型 35 2.5.1 无符号的整数类型 35 2.5.2 使用整数类型 36 2.5.3 指定整数常量 37 2.6 浮点数 38 2.7 浮点数变量 38 2.8 使用浮点数完成除法运算 39 2.8.1 控制小数位数 40 2.8.2 控制输出的字段宽度 41 2.9 较复杂的表达式 41 2.10 定义常量 44 2.10.1 极限值 46 2.10.2 sizeof运算符 49 2.11 选择正确的类型 50 2.12 强制类型转换 53 2.12.1 自动转换类型 53 2.12.2 隐式类型转换的规则 54 2.12.3 赋值语句的隐式类型转换 54 2.13 再谈数值数据类型 55 2.13.1 字符类型 56 2.13.2 字符的输入输出 57 2.13.3 宽字符类型 60 2.13.4 枚举 60 2.13.5 存储布尔值的变量 63 2.13.6 复数类型 63 2.14 赋值操作的op=形式 66 2.15 数学函数 68 2.16 设计一个程序 69 2.16.1 问题 69 2.16.2 分析 69 2.16.3 解决方案 71 2.17 小结 75 2.18 练习 76 第3章 条件判断 79 3.1 判断过程 79 3.1.1 算术比较 80 3.1.2 涉及关系运算符的表达式 80 3.1.3 基本的if语句 81 3.1.4 扩展if语句:if-else 84 3.1.5 在if语句使用代码块 86 3.1.6 嵌套的if语句 87 3.1.7 更多的关系运算符 90 3.1.8 逻辑运算符 93 3.1.9 条件运算符 97 3.1.10 运算符的优先级 99 3.2 多项选择问题 103 3.2.1 给多项选择使用else-if语句 104 3.2.2 switch语句 104 3.2.3 goto语句 113 3.3 按位运算符 114 3.3.1 按位运算符的op=用法 116 3.3.2 使用按位运算符 117 3.4 设计程序 120 3.4.1 问题 120 3.4.2 分析 120 3.4.3 解决方案 121 3.5 小结 124 3.6 练习 124 第4章 循环 127 4.1 循环 127 4.2 递增和递减运算符 128 4.3 for循环 129 4.4 for循环的一般语法 132 4.5 再谈递增和递减运算符 133 4.5.1 递增运算符 133 4.5.2 递增运算符的前置和后置形式 134 4.5.3 递减运算符 134 4.6 再论for循环 135 4.6.1 修改for循环变量 137 4.6.2 没有参数的for循环 138 4.6.3 循环内的break语句 138 4.6.4 使用for循环限制输入 141 4.6.5 生成伪随机整数 143 4.6.6 再谈循环控制选项 145 4.6.7 浮点类型的循环控制变量 146 4.7 while循环 147 4.8 嵌套循环 150 4.9 嵌套循环和goto语句 153 4.10 do-while循环 154 4.11 continue语句 157 4.12 设计程序 157 4.12.1 问题 157 4.12.2 分析 157 4.12.3 解决方案 158 4.13 小结 170 4.14 习题 170 第5章 数组 173 5.1 数组简介 173 5.1.1 不用数组的程序 173 5.1.2 什么是数组 175 5.1.3 使用数组 176 5.2 内存 179 5.3 数组和地址 182 5.4 数组的初始化 184 5.5 确定数组的大小 184 5.6 多维数组 185 5.7 多维数组的初始化 187 5.8 设计一个程序 191 5.8.1 问题 192 5.8.2 分析 192 5.8.3 解决方案 193 5.9 小结 200 5.10 习题 200 第6章 字符串和文本的应用 201 6.1 什么是字符串 201 6.2 处理字符串和文本的方法 203 6.3 字符串操作 206 6.3.1 连接字符串 206 6.3.2 字符串数组 208 6.4 字符串库函数 210 6.4.1 使用库函数复制字符串 210 6.4.2 使用库函数确定字符串的长度 211 6.4.3 使用库函数连接字符串 212 6.4.4 比较字符串 213 6.4.5 搜索字符串 216 6.5 分析和转换字符串 219 6.5.1 转换字符 222 6.5.2 将字符串转换成数值 225 6.7 使用宽字符串 225 6.8 设计一个程序 228 6.8.1 问题 229 6.8.2 分析 229 6.8.3 解决方案 229 6.9 小结 237 6.10 习题 237 第7章 指针 239 7.1 指针初探 239 7.1.1 声明指针 240 7.1.2 通过指针访问值 241 7.1.3 使用指针 244 7.1.4 指向常量的指针 248 7.1.5 常量指针 248 7.1.6 指针的命名 249 7.2 数组和指针 249 7.3 多维数组 252 7.3.1 多维数组和指针 255 7.3.2 访问数组元素 257 7.4 内存的使用 260 7.4.1 动态内存分配:malloc()函数 260 7.4.2 分配内存时使用sizeof运算符 261 7.4.3 用calloc()函数分配内存 265 7.4.4 释放动态分配的内存 265 7.4.5 重新分配内存 267 7.5 使用指针处理字符串 268 7.5.1 更多地控制字符串输入 268 7.5.2 使用指针数组 269 7.6 设计程序 280 7.6.1 问题 280 7.6.2 分析 281 7.6.3 解决方案 281 7.7 小结 291 7.8 习题 291 第8章 程序的结构 293 8.1 程序的结构 293 8.1.1 变量作用域生存期 294 8.1.2 变量作用域函数 297 8.2 函数 297 8.2.1 定义函数 298 8.2.2 return语句 301 8.3 按值传递机制 304 8.4 函数声明 305 8.5 指针用作参数和返回值 307 8.5.1 常量参数 310 8.5.2 从函数返回指针值 318 8.5.3 在函数递增指针 322 8.6 小结 322 8.7 习题 323 第9章 函数再探 325 9.1 函数指针 325 9.1.1 声明函数指针 325 9.1.2 通过函数指针调用函数 326 9.1.3 函数指针数组 329 9.1.4 作为变元的函数指针 331 9.2 函数变量 334 9.2.1 静态变量函数内部的追踪 334 9.2.2 在函数之间共享变量 336 9.3 调用自己的函数:递归 338 9.4 变元个数可变的函数 341 9.4.1 复制va_list 344 9.4.2 长度可变的变元列表的基本规则 344 9.5 main()函数 345 9.6 结束程序 346 9.7 函数库:头文件 347 9.8 提高性能 348 9.8.1 内联声明函数 348 9.8.2 使用restrict关键字 348 9.9 设计程序 349 9.9.1 问题 349 9.9.2 分析 349 9.9.3 解决方案 351 9.10 小结 367 9.11 习题 368 第10章 基本输入和输出操作 369 10.1 输入和输出流 369 10.2 标准流 370 10.3 键盘输入 371 10.3.1 格式化键盘输入 371 10.3.2 输入格式控制字符串 372 10.3.3 输入格式字符串的字符 377 10.3.4 输入浮点数的各种变化 378 10.3.5 读取十六进制和八进制值 379 10.3.6 用scanf()读取字符 381 10.3.7 scanf()的陷阱 383 10.3.8 从键盘上输入字符串 383 10.3.9 键盘的非格式化输入 384 10.4 屏幕输出 389 10.4.1 使用printf()格式输出到屏幕 389 10.4.2 转义序列 391 10.4.3 整数输出 392 10.4.4 输出浮点数 394 10.4.5 字符输出 395 10.5 其他输出函数 398 10.5.1 屏幕的非格式化输出 398 10.5.2 数组的格式化输出 399 10.5.3 数组的格式化输入 400 10.6 打印机输出 400 10.7 小结 401 10.8 习题 401 第11章 结构化数据 403 11.1 数据结构:使用struct 403 11.1.1 定义结构类型和结构变量 405 11.1.2 访问结构成员 405 11.1.3 未命名的结构 408 11.1.4 结构数组 408 11.1.5 表达式的结构 411 11.1.6 结构指针 411 11.1.7 为结构动态分配内存 412 11.2 再探结构成员 414 11.2.1 将一个结构作为另一个结构的成员 414 11.2.2 声明结构的结构 415 11.2.3 将结构指针用作结构成员 416 11.2.4 双向链表 420 11.2.5 结构的位字段 423 11.3 结构与函数 424 11.3.1 结构作为函数的变元 424 11.3.2 结构指针作为函数变元 425 11.3.3 作为函数返回值的结构 426 11.3.4 修改程序 430 11.3.5 二叉树 433 11.4 共享内存 442 11.4.1 联合 442 11.4.2 联合指针 444 11.4.3 联合的初始化 444 11.4.4 联合的结构成员 444 11.5 定义自己的数据类型 446 11.5.1 结构与类型定义(typedef)功能 446 11.5.2 使用typedef简化代码 447 11.6 设计程序 448 11.6.1 问题 448 11.6.2 分析 448 11.6.3 解决方案 448 11.7 小结 459 11.8 习题 459 第12章 处理文件 461 12.1 文件的概念 461 12.1.1 文件的位置 462 12.1.2 文件流 462 12.2 文件访问 462 12.2.1 打开文件 463 12.2.2 文件重命名 465 12.2.3 关闭文件 465 12.2.4 删除文件 466 12.3 写入文本文件 466 12.4 读取文本文件 467 12.5 将字符串写入文本文件 470 12.6 从文本文件读入字符串 471 12.7 格式化文件的输入输出 474 12.7.1 格式化文件输出 474 12.7.2 格式化文件输入 475 12.8 错误处理 477 12.9 再探文本文件操作模式 478 12.10 二进制文件的输入输出 479 12.10.1 指定二进制模式 479 12.10.2 写入二进制文件 480 12.10.3 读取二进制文件 480 12.11 在文件移动 488 12.11.1 文件定位操作 489 12.11.2 找出我们在文件的位置 489 12.11.3 在文件设定位置 490 12.12 使用临时文件 496 12.12.1 创建临时文件 496 12.12.2 创建唯一的文件名 496 12.13 更新二进制文件 497 12.13.1 修改文件的内容 502 12.13.2 从键盘读取记录 503 12.13.3 将记录写入文件 504 12.13.4 从文件读取记录 505 12.13.5 写入文件 506 12.13.6 列出文件内容 507 12.13.7 更新已有的文件内容 508 12.14 文件打开模式小结 515 12.15 设计程序 516 12.15.1 问题 516 12.15.2 分析 516 12.15.3 解决方案 516 12.16 小结 522 12.17 习题 522 第13章 支持功能 523 13.1 预处理 523 13.1.1 在程序包含头文件 523 13.1.2 外部变量函数 524 13.1.3 替换程序源代码 525 13.1.4 宏替换 526 13.1.5 看起来像函数的宏 526 13.1.6 多行上的预处理指令 528 13.1.7 字符串作为宏参数 528 13.1.8 结合两个宏展开式的结果 529 13.2 预处理器逻辑指令 530 13.2.1 条件编译 530 13.2.2 测试指定值的指令 531 13.2.3 多项选择 531 13.2.4 标准预处理宏 532 13.3 调试方法 533 13.3.1 集成的调试器 533 13.3.2 调试阶段的预处理器 533 13.3.3 使用assert()宏 537 13.4 其他库函数 539 13.4.1 日期和时间函数库 539 13.4.2 获取日期 543 13.5 小结 549 13.6 习题 549 附录A 计算机的数学知识 551 附录B ASCII字符代码定义 559 附录C C语言的保留字 565 附录D 输入输出格式指定符 567 前言   欢迎使用《C语言入门经典(第4版)》。研读本书,你就可以成为一位称职的C语言程序员。从许多方面来说,C语言都是学习程序设计的理想起步语言C语言很简洁,因此无须学习大量的语法,就能够开始编写真正的应用程序。除了简明易学外,它还是一种功能非常强大的语言,至今仍被专业人士广泛使用。C语言的强大之处主要体现在,它能够进行各种层次的程序设计,从硬件设备驱动程序和操作系统组件到大规模的应用程序,都能胜任。事实上,任何计算机都支持C语言编译器,因此,当我们学会了C语言,就可以在任何环境下进行程序设计。最后一点,掌握了C语言,就为理解面向对象的C++语言奠定了良好的基础。.   积极热情的程序员都必将面对三大障碍,即掌握适用于所有程序设计语言的术语,理解如何使用一种语言的元素(而不仅仅只知道它们的概念)以及领会如何在实际环境应用这种语言,本书的目的就是将这些障碍降到最低。   术语是专业人士与优秀的业余人士们进行交流时必不可少的,因此掌握它们是必需的。本书会让你理解这些术语,并自如地在各种环境下使用它们。这样才能更有效地使用大多数软件产品附带的文档,且能轻松地阅读和学习大多数程序设计语言的相关文献。   显然,理解语言元素的语法和作用是学习一门语言的关键,不过认识语言的特性如何发挥作用和如何应用它们,也同等重要。在说明每种语言特性与特定问题的关系时,本书采用实际应用的程序示例,而不只是代码片断。这些示例提供了实践的基础,你可以任意改动它们,研究改动后的效果。   要理解在特定背景程序设计方法,需要理解应用独立语言元素的机理。为了帮助理解它们,本书每章最后都给出一个较复杂的程序,该程序应用了本章前面已经学习的知识。这些程序可帮助你获得开发程序的能力和信心,了解如何综合运用各种语言元素。最重要的是,它们能让你了解设计真实程序时会遇到的问题以及如何管理实际的代码。   学习任何程序设计语言,都要认识几件事情。首先,要学的东西很多,但是掌握了它们之后,你会有极大的成就感。其次,学习的过程很有趣,你将体会到这一点。第三,你只有通过动手实践才能学会程序设计。最后,学习程序设计语言比你想象的容易得多,所以你肯定能掌握它。   如何使用本书   作者认为动手实践是最好的方法,你应当立刻开始编写自己的第一个程序。每一章都有几个把理论应用于实践的程序,这些示例是学习本书的关键。建议读者输入并运行文的示例,因为输入程序对记住语言元素有极大的帮助。此外,你还应该做每章后面的练习。当你第一次使一个程序运行起来,尤其是在试图解决自己的问题时,快速的进展会使你有很大的成就感。..   刚开始,学习的进展不会太快,不过随着逐渐深入,我们会加快学习的速度。每一章都会涉及很多基础知识,因此在学习新的内容之前,需要花些时间,确保理解了前面学过的所有知识。实践各部分的代码,并尝试实现自己的想法,这是学习程序设计语言的一个重要部分。尝试修改书程序,看看还能让它们做什么,这是很有趣的。不要害怕尝试,如果不明白某一点如何使用,输入几种变体,看看会出现哪些情况。好的学习方法是先通读整章,全面了解其介绍的内容,然后再实践其的所有程序示例。   你可能会觉得某些章末尾的程序非常难。如果第一次读这样的程序没有完全理解,不必担心。第一次难免会觉得难以理解,因为它们通常都是把你所学的知识应用到了相当复杂的问题。如果你真的不能理解,可以略过那些章末尾的程序,继续学习下一章,然后再回头研究这些程序。甚至可以在学完全书之后再来研究它们。之所以演示这些程序是因为即使读完了本书,它们对你来说仍是非常有用的资源。   本书读者对象   本书的目的是教你如何尽可能简单快速地编写有用的程序,如果你属于下列情况之一,那么本书就非常适合你:   ●刚接触程序设计,但想直接深入了解C语言,从头开始学习程序设计及编写C语言程序。   ●以前有一点程序设计经历,对其基本概念有一定了解,也许曾经使用过BASIC或PASCAL。现在想学习C语言,进一步提高自己的程序设计技能。   本书并未假设此前你对程序设计的知识有所了解,不过本书会很快地从基本概念转入到实际应用。学完了本书,你就为自己的C语言程序设计奠定了全面的基础。   使用本书的条件   要使用本书,需要一台安装了C语言编译器和库的计算机,这样才能执行书的示例,还需要一个程序文本编辑器,用于创建源代码文件。你使用的编译器要很好地支持C语言国际标准:ISO/IEC 9899。你还需要一个用于创建和修改代码的编辑器,可以采用任何纯文本编辑器创建源程序文件,如Notepad或vi。不过,采用专为编辑C语言代码设计的编辑器更有帮助。   要最大限度地发挥本书的功效,你需要有学习的意愿、成功的渴望,当学习不顺利,觉得前途渺茫时,还要有坚持下去的决心。几乎每个人在初次学习程序设计时都会在某处觉得迷茫。当你发现自己艰难地掌握了C语言的某个方面时,要坚持下去,迷雾一定会消散,你会觉得为什么当初我不明白这一点呢?也许你明白要做到这些将会很难,不过相信你一定会惊讶自己能在较短的时间内取得很大进步。本书会帮助你开始自己的实践之旅,使你成为成功的程序设计员。   本书采用的约定   本书的文本和布局采用了许多不同的样式,以便区分各种不同的信息。大多数样式表达的含义都很明显,其程序代码以类似下面的样子出现: .  int main(void)   {   printf("\nBeginning C");   return 0;   }   如果代码片段是从前面的实例修改而来的,修改过的代码行就用粗体显示,如下所示:   int main(void)   {   printf("\nBeginning C by Ivor Horton");   return 0;   }   程序代码还使用了各种“括号”。它们之间的差别非常重要,不能互换。本书称( )为圆括号,{ }为大括号,[ ]为方括号。   本书源代码下载   从Apress的站点可以下载本书的所有代码和练习的解决方案:http://www.apress.com。也可以访问www.tupwk.com.cn/downpage下载本书的所有代码和解决方案。...   
C语言是编程语言的一朵奇葩,虽已垂垂老矣,但却屹立不倒,诞生了数十年,仍然是最流行的编程语言之一。C语言看似简单,却不易吃透,想要运用好,更是需要积淀。本书是一本修炼C程序设计能力的进阶之作,它没有系统地去讲解C语言的语法和编程方法,而是只对C语言不容易被初学者理解的重点、难点和疑点进行了细致而深入的解读,揭露了C语言那些鲜为普通开发者所知的秘密,旨在让读者真正掌握C语言,从而编写出更高质量的C程序代码。 全书一共11章:第1章重点阐述了C语言不易被理解的多个核心概念,很多初学者在理解这些概念时都会存在误区;第2~8章对预处理、选择结构和循环结构的程序设计、数组、指针、数据结构、函数文件等知识点的核心问题和注意事项进行了讲解;第9章介绍了调试和异常处理的方法及注意事项;第10章对C语言的若干容易让开发者误解误用的陷阱知识点进行了剖析;第11章则对所有程序员必须掌握的几种算法进行了详细的讲解;附录经验性地总结了如何养成良好的编码习惯,这对所有开发者都尤为重要。 本书主要内容:  堆和栈、全局变量和局部变量生存期作用域、内部函数和外部函数、指针变量、指针数组和数组指针、指针函数函数指针、传址和传值、递归和嵌套、结构体和共用体、枚举、位域等较难理解的核心概念的阐述和对比;  预处理的疑难知识点,包括文件的包含方式、宏定义及其常见错误解析、条件编译指令和#pragma指令的使用等;  if、switch等选择结构语句的使用注意事项和易错点解析;  for、while、do while等循环结构语句的使用注意事项和易错点解析;  循环结构break、continue、goto、return、exit的区别;  一维数组、二维数组、多维数组、字符数组、动态数组的定义和引用,以及操作数组时的各种常见错误解析;  不同类型的指针之间的区别,以及指针的一般用法和注意事项;  指针与地址、数组、字符串、函数之间的关系,以及指针与指针之间的关系;  枚举类型的使用及注意事项,结构体变量和共用体变量的初始化方法及引用;  传统链表的实现方法和注意事项,以及对传统链表实现方法的颠覆;  与函数参数、变参函数函数调用、函数指针相关的一些难理解和容易被理解错的知识点解析;  文件和指针的使用原则、技巧和注意事项;  函数调用和异常处理的注意事项和最佳实践;  与strlen、sizeof、const、volatile、void、void*、#define、typedef、realloc、malloc、calloc等相关的一些陷阱知识点的解析;  时间复杂度、冒泡排序法、选择排序法、快速排序法、归并排序法、顺序排序法、二分查找等常用算法的详细讲解;  良好的编码习惯和编程风格。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值