C语言基础1

内容简介

本书一共有八个项目,分别是导言、类型、运算符与表达式、控制流、函数与程序结构、指针与数组、结构、输入与输出、UNIX系统接口。

前言

本书是C语言基础,其实就是把《The C Programming Language》的读书笔记。

读书要写笔记,读一点写一点,可以写成有系统的笔记。

每天写作的内容不能确定,有空就写,没空就不写。方证大师说:“练一天有一天的好处,练一时有一时的好处。”写一段有一段的好处,写一句有一句的好处。

项目一 导言

1.2 变量与算术表达式

温度转换程序

#include <stdio.h>
int main()
{
	int fahr, celsius;
	int lower, upper, step;

	lower = 0;
	upper = 300;
	step = 20;
	fahr = lower;
	while (fahr <= upper)
	{
		celsius = 5 * (fahr - 32) / 9;
		printf("%d\t%d\n", fahr, celsius);
		fahr = fahr + step;
	}
}

1.4 符号常量

在1.2节变量与算术表达式中讲过一个温度转换程序,程序如下。

#include <stdio.h>
int main()
{
	int fahr, celsius;
	int lower, upper, step;

	lower = 0;
	upper = 300;
	step = 20;
	fahr = lower;
	while (fahr <= upper)
	{
		celsius = 5 * (fahr - 32) / 9;
		printf("%d\t%d\n", fahr, celsius);
		fahr = fahr + step;
	}
}

在这个程序里面,变量upper和step是幻数。幻数没有具体意义,不能提供信息,修改困难。幻数的处理办法是定义幻数,通过符号常量将其定义为字符串。符号常量的语法如下。

#define 名字 替换文本

使用名字的本质是使用“替换文本”


注意

符号常量不等于变量,不出现在声明中,全用大写,没有分号。

用符号常量对温度转换程序进行修改


#include <stdio.h>
#define LOWER  0
#define UPPER  300
#define STEP   20

main()
{
    int fahr;
    for(fahr = LOWER; fahr <= UPPER; fahr = fahr + STEP)
        printf("%3d  %6.1d\n",fahr,(5.0/9.0)*(fahr-32));
}

1.7 函 数

函数为“计算过程的封装”,也就是说函数是对计算过程进行的封装。比如一个一元二次方程,我们列竖式进行计算,列竖式就是计算过程。函数将这个计算过程进行封装,使用者将看不到计算过程。函数就是一个黑盒子。

使用函数,不用管函数是如何实现的。只需要知道函数具有哪些功能,无需管功能是怎样实现的。

函数分为两种,一种是自定义函数,一种是函数库函数。

自定义函数,需要使用者自己定义,要学习函数定义的方法。

函数库函数,是已经封装好的函数,如printf()、getchar()、putchar()函数等。

对于函数库函数,使用者只需要知道函数具有的功能即可,无需自定义函数的功能。

下面自定义一个指数计算函数,函数命名为power(m,n),能够实现的功能是计算整数m的n次幂。

该程序分为三步完成,第一步是定义函数,第二步是主程序调用函数,第三步是合并程序

第一步,定义函数

#include<stdio.h>
int power(int base,int n)
{
	int i,p;
    p = 1;
    for(i=1;i<=n;++i)
        p = p * base;
    return p;
}

第二步:main()函数调用power(m,n)函数

int power(int m,int n);
main()
{
    int i;
    for(i=0;i<10;++i)
        printf("%d %d %d\n",i,power(2,i),power(-3,i));
    return 0;
}

第三步:合并程序

#include<stdio.h>
int power(int m,int n);
main()
{
    int i;
    for(i=0;i<10;++i)
        printf("%d %d %d\n",i,power(2,i),power(-3,i));
    return 0;
}

int power(int base,int n)
{
	int i,p;
    p = 1;
    for(i=1;i<=n;++i)
        p = p * base;
    return p;
}

难点

变量base干什么的?

程序的目的是连续输出2的0~9次幂,-3的0~9次幂。也就是20~9,(-3)0~9

找个数带进去试试,不明白自定义函数的调用不要紧,先带进去,明天再学自定义函数的调用方法。

函数定义的一般形式

返回值类型 函数名(参数列表)

{

声明部分

语句序列

}

函数定义的位置随意,但整体是不能分隔的。

要清楚函数定义、函数调用。函数定义是指函数声明,函数调用是指传递参数。

比如

printf("%d	%d	%d \n",i,power(2,i),power(-3,i))

这是main()函数调用power()函数的过程,一共调用了两次,第一次是power(2.i),第二次是power(-3.i)

调用过程是指main()函数向power()函数传递2个参数,第一次传递(2,i)两个参数;第二次传递(-3,i)两个参数。

调用完成后,power()函数向main()函数返回一个格式化的整数并打印。

打印是printf()函数执行的。不是power()函数执行的。

详细地说,main()函数除了调用power()函数外,还调用了printf()函数。这两个被调用的函数不同,power()函数是自定义函数,printf()函数是函数库函数。函数库函数是不用声明的,直接用即可。power()函数是需要声明的。

power()函数

函数声明(函数定义)的语句如下。

int power(int base,int n)

返回值类型为int,函数名为power,参数列表中有两个参数,参数类型声明为int。函数声明中的参数只对此函数可见,其他函数不可见。power中的i和main中的i没有关系。


注意

函数定义中的参数(int base,int n)是形式参数,

函数调用中与形式参数对应的值是实际参数。

分别简称为形参和实参。


函数中的最后一个语句序列是

return p;

power()函数计算的值通过return语句返回给main()函数,也就是将p指返回给power(2,i),也就是说

power(2,i)计算的结果是一个p,这个参数通过“%d”打印出来了。

变量base是干什么的?

变量base是形参,占位置的。

函数调用的方法,定义函数后,main函数传过来一个实参,power接收到实参后进行计算,出来结果后,返回一个p,然后用printf函数打印出来了。

以后main函数都要写return 0;

main函数要向执行环境汇报状态,0表示正常状态。表示正常结束了。执行环境需要得到0这个状态。

习题

重新编写1.2节的温度转换程序,使用函数实现温度转换计算。

1.2节温度转换程序如下

#include <stdio.h>
int main()
{
	int fahr, celsius;
	int lower, upper, step;

	lower = 0;
	upper = 300;
	step = 20;
	fahr = lower;
	while (fahr <= upper)
	{
		celsius = 5 * (fahr - 32) / 9;
		printf("%d\t%d\n", fahr, celsius);
		fahr = fahr + step;
	}
}

使用函数实现温度转换计算,步骤如下。

第一步:函数定义

int conversion()
{
	int fahr, celsius;
	int lower, upper, step;
	

	lower = 0;
	upper = 300;
	step = 20;
	fahr = lower;
	while (fahr <= upper)
	{
		celsius = 5 * (fahr - 32) / 9;
		printf("%d\t%d\n", fahr, celsius);
		fahr = fahr + step;
	}
	return 0;
}

第二步:main函数调用

#include <stdio.h>
int conversion();
int main()
{
	conversion();
}

第三步:合并程序

#include <stdio.h>
int conversion();
int main()
{
	conversion();
}

int conversion()
{
	int fahr, celsius;
	int lower, upper, step;
	

	lower = 0;
	upper = 300;
	step = 20;
	fahr = lower;
	while (fahr <= upper)
	{
		celsius = 5 * (fahr - 32) / 9;
		printf("%d\t%d\n", fahr, celsius);
		fahr = fahr + step;
	}
	return 0;
}

运行结果如下。

注意

第一,函数里面没有参数,如果有参数,没处都要用参数,在主函数中也要定义参数。

第二,没有参数可以直接运行出结果。

第三,严格按照函数调用的格式书写,比如main函数上面要声明函数(定义函数),初次定义函数,容易忽略定义。

1.8 参数——传值调用

所有函数中的参数,都是通过值来传递的。

在函数的调用中分为主调函数和被调函数。比如上节的程序,其中main函数就是主调函数,power函数就是被调函数,被调函数中的参数int power(int base,int n)是通过值来传递的。main函数将值传递给临时变量n,被调函数使用临时变量n进行计算。

被调函数不能直接修改主调函数中变量的值,也就是说,power函数不能直接修改main函数传递过来的n的值。这里说的是不能“直接修改”,可以通过其他操作进行间接的修改。比如指针地址的方法修改主调函数中的参数值。

如果被调函数要修改主调函数中的参数值(变量值),主调函数要向被调函数提供“待设置的变量的地址”,地址是指向变量的至真。而被调函数要将对应参数声明为指针类型,通过指针间接访问或修改变量。

通常情况下,被调函数不能修改主调函数中参数的值,只能修改私有的临时变量的值。

主调函数传递的参数值(实参)存储在被调函数的临时变量中(形参)。

/*power函数求底数n的n次幂*/
int power(int base,int n)
{
	int p;
    for(p = 1;n > 0; --n)
        p = p*base;
    return p;
}

其中,变量base和n是形参,参数值由主函数传递过来。实参传递给形参n之后,power函数对形参n进行计算操作,循环递减,改变了n的值,这是可以的。因为变量n是power的局部变量,是私有的。变量n在power函数中的改变不会影响到主函数中的原始n值(参数值)。

如果参数是数组,情况比以上要复杂。

数组名作为参数,传递的是数组其实元素的位置或地址,并不是传递数组中元素的本身。被调函数通过数组下标访问或修改数组元素的值。

1.9 字符数组

通过一个程序来解释字符数组。程序是这样的,读入一组文本行,并把最长的文本行打印出来。

伪代码如下。

while(还有未处理的行)

if(该行比已处理的最长行还要长)

保存该行

保存该行的长度

打印最长的行

这个设计思路很简单,只有三步:读入新行、测试读入的行、保存该行。

这个程序用两个独立函数来实现。第一个函数为getline,用于读取输入的下一行,读到文件末尾符号返回信号,遇到结束符返回0,返回该行长度;第二个函数为copy,保存新行长度,保存新行内容。

打印最长文本行程序编写步骤如下。

第一步,声明getline函数

int getline(char s[],int lim)
{ 
    int c,i;
    for(i=0;i<lim-1&&(c=getchar())!=EOF&&c!='\n';++i}
        s[i]=c;
    if(c=='\n')
        {
            s[i]=c;
            ++i;
        }
    s[i]='\0';
    return i;
}

第二步,声明copy函数

void copy(char to[],char from[])
{
    int i;
    i=0;
    while((to[i]=from[i])!='\0')
        ++i;
}

第三步,main函数

#include <stdio.h>
#define MAXLINE  1000

int getline(char line[],int maxline);
void copy(char to[],char from[]);
main()
{
    int len;
    int max;
    char line[MAXLINE];
    char longest[MAXLINE];
    max = 0;
    while((len=getline(line,MAXLINE)>0))
        if(len>max)
        {
            max=len;
            copy(longest,line);
        }
}

第四步,合并程序

#include <stdio.h>
#define MAXLINE  1000

int getline(char line[],int maxline);
void copy(char to[],char from[]);
main()
{
    int len;
    int max;
    char line[MAXLINE];
    char longest[MAXLINE];
    max = 0;
    while((len=getline(line,MAXLINE)>0))
        if(len>max)
        {
            max=len;
            copy(longest,line);
        }
}

int getline(char s[],int lim)
{ 
    int c,i;
    for(i=0;i<lim-1&&(c=getchar())!=EOF&&c!='\n';++i}
        s[i]=c;
    if(c=='\n')
        {
            s[i]=c;
            ++i;
        }
    s[i]='\0';
    return i;
}
        
void copy(char to[],char from[])
{
    int i;
    i=0;
    while((to[i]=from[i])!='\0')
        ++i;
}

解读程序

声明getline、copy函数,假定他们存放在一个文件里

main函数和getline函数之间通过一对参数和一个返回值进行数据交换。

getline函数中的参数声明

int  getline(char s[], int lim)

其中s为数组,lim为整型。一般数组都是要进行长度声明的,为什么在getline函数里面没有呢?因为我们知道main函数进行了调用,直接在main函数里面进行了声明。因此就没有再getline函数中声明长度。

getline函数用return语句将值返回给调用者。

这个值声明为int类型。

copy函数声明为void类型,表明不返回任何值。只执行一些操作。

1.10 外部变量与作用域

外部变量是指全局变量,全局范围内都能访问的变量。

局部变量是指在某个函数中声明的变量,只能在这个函数中用,其他函数不能使用。

main函数中的变量只能main函数用,这是局部变量,在调用时变量存在,结束时变量消失,并没有存储变量的值。局部变量在每次调用时值都是不同的。每次进入函数时都要显式赋值。

外部变量声明在所有函数外边,所有函数都能调用,全局范围内可以访问,其值一直存在,是不变的。

第一,定义在所有函数外

第二,只能定义一次

第三,编译后分配存储单元

第四,访问时函数要先声明

下面改写1.9节的打印最长文本行程序,程序一共分为五部分

第一,头文件声明

#include <stdio.h>
#define  MAXLINE  1000
int  max;
char line[MAXLINE];
char longese[MAXLINE];
int  getline(void);
void  copy(void);

第二,主函数调用

main()
{
    int len;
    extern  int  max;
    extern  char  longest[];
    max = 0;
    while( (len = getline()) > 0)
        if( len > max )
        {
            max = len;
            copr();
        }
    if(max>0)
        printf("%s",longest);
    return 0;
}

第三,getline()函数

int getline(void)
{
    int  c,i;
    extern  char  line[];
    for(i=0;i<MAXLINE-1&&(c = getchar()) != EOF && c!= '\n'; ++i)
        line[i] = c;
    if(c=='\n')
    {
        line[i] = c;
        ++i;
    }
    line[i] = '\0';
    return i;
}

第四,copy()函数

void copy(void)
{
    int  i;
    extern  char line[],longest[];
    i=0;
    while((longest[i]=line[i])!='\0')
        ++i;
}

第五,合并函数

#include <stdio.h>
#define  MAXLINE  1000
int  max;
char line[MAXLINE];
char longese[MAXLINE];
int  getline(void);
void  copy(void);

main()
{
    int len;
    extern  int  max;
    extern  char  longest[];
    max = 0;
    while( (len = getline()) > 0)
        if( len > max )
        {
            max = len;
            copr();
        }
    if(max>0)
        printf("%s",longest);
    return 0;
}

int getline(void)
{
    int  c,i;
    extern  char  line[];
    for(i=0;i<MAXLINE-1&&(c = getchar()) != EOF && c!= '\n'; ++i)
        line[i] = c;
    if(c=='\n')
    {
        line[i] = c;
        ++i;
    }
    line[i] = '\0';
    return i;
}

void copy(void)
{
    int  i;
    extern  char line[],longest[];
    i=0;
    while((longest[i]=line[i])!='\0')
        ++i;
}

项目二 类型、运算符与表达式

项目三 控制流

项目四 函数与程序结构

项目五 指针与数组

项目六 结构

项目七 输入与输出

项目八 UNIX系统接口

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值