C语言-第2章-基本概念(顺序结构程序设计)

本文主要介绍了C语言中顺序结构程序设计的基础知识,包括变量的声明、赋值、显示,以及常量、标识符的使用。通过案例分析了计算圆面积的程序,强调了变量初始化的重要性,并提醒了在编程中避免使用未初始化变量的错误。此外,还讨论了程序的书写规范和常见问题,如变量声明顺序、输入输出操作的注意事项等。

  • 本章内容包括变量、变量的使用、输出、输入、常量、标识符、注释等。
  • 本章目标是语法上理解上述内容,能编写含有输入、输出的简单顺序结构程序。
  • 本章重点是变量含义、基本(顺序)程序的结构和编写、输入和输出的理解和编写、难点是输入、输出语句。

2.0 一个导入的例子

printf函数不但能显示字符,而且能显示数值

printf("出生年份是%d\n", 2000);

在这里插入图片描述
这样的形式的输出语句输出的是整数值2000,这与将2000写到双引号里面是不同的

printf("出生年份是2000\n");

比如,

printf("出生年份是%d\n", 2000 + 1);

会显示,

在这里插入图片描述

而写到双引号里面的东西是直接用来显示的字符,

printf("出生年份是2000+1\n");

会显示

在这里插入图片描述

因此,给出出生年份,算出年龄的代码可以写成如下

printf("出生年份是%d,年龄是%d\n", 2000, 2019 - 2000);

在这里插入图片描述

上述程序的一个缺陷如果要修改出生年份,要在两处修改2000。

printf("出生年份是%d,年龄是%d\n", 2001, 2019 - 2001);

那么可以声明变量保存数值,在需要这个值的地方访问这个变量即可

int birth_year = 2000;

printf("出身年份是%d的年龄是%d\n", birth_year, 2019 - birth_year);

上述程序的一个缺陷是每次要计算不同的出生年份的年龄值,还要修改源代码,使用不方便。比如,计算2001出生的年龄

int birth_year = 2001;

printf("出身年份是%d的年龄是%d\n", birth_year, 2019 - birth_year);

可以使用scanf语句将值输入到变量中。

#include <stdio.h>

int main()
{
   int birth_year;
   
   printf("请输入出生年份:");
   scanf("%d", &birth_year);
   
   printf("出生年份是%d,年龄是%d\n", birth_year, 2019 - birth_year);
   
   return 0;
}

程序运行后,会弹出窗口

在这里插入图片描述
输入2000,并按下回车,程序的运行结果为
在这里插入图片描述

同理,可以声明年龄变量age保存年龄,如果之后需要访问这个年龄值,访问变量age即可。

#include <stdio.h>

int main()
{
   int birth_year, age;
   
   printf("请输入出生年份:");
   scanf("%d", &birth_year);
   
   age = 2019 - birth_year;
   
   printf("出生年份是%d,年龄是%d\n", birth_year, age);
   
   return 0;
}

上述程序逻辑上可以分为3块,分别为输入、处理、输出

#include <stdio.h>

int main()
{
   int birth_year, age;
   // 1. 输入
   printf("请输入出生年份:");
   scanf("%d", &birth_year);
   // 2. 处理
   age = 2019 - birth_year;
   // 3. 输出
   printf("出生年份是%d,年龄是%d\n", birth_year, age);
   
   return 0;
}

这也是一般程序的逻辑结构。

2.2 变量的使用

2.2.1 变量的声明

程序运行过程中可能需要保存一些可以变化的值。保存这些变化的值的地方就是变量。变量可以理解成是保存值的容器。

C语言中的变量具有一定的类型,而C语言的变量在使用前需要声明其类型以及名称,语法为:

类型名 变量名;

类型名用来指明变量可以保存的值的类型,包括int,float等等。int表示整数类型(integer的缩写),float表示单精度浮点类型,即可以存储小数的类型,double表示双精度浮点类型,其表示的值的范围和精度高于float类型。

变量名称是编程人员自己决定的,一般以其存储的值的含义来命名。同时,变量命名也要符合一定的规范。声明变量有时候也称为定义变量。

下面,给出2个变量声明的例子,

  • 声明类型为整数,名称是age的整数变量:

    int age;
    
  • 声明float类型变量height:

    float height;
    
  • 声明double类型变量distance:

  • double distance;
    

如果多个变量的类型一致,可以将它们的声明放在一起,比如,

int birth_year, age;

以及

float height, weight, bmi;

注意,C语言中变量的类型一旦声明就不能改变。

在这里插入图片描述

int类型的变量可以精准的保存一个整数,缺点是整数范围有限,当前计算机中一个整数是用4个字节存储的,故整数的范围是最小值为负的2的31次方,即-2147483648(负的二十多亿),最大值为2的31次方-1,即2147483647(正的二十多亿)。float可以存储有小数的数,而且比int型整数的范围大的多,但是浮点类型的缺点是变量存储的值往往只是期望存储数值的近似值,而且浮点数运算起来比整数类型的慢。比如,如果0.1就不能精确地存储在float类型的变量中。

整型和浮点类型各有其优缺点,我们在根据程序的环境来决定把变量声明为什么类型。一般情况下,如果只需要存储整数,而且整型的范围足够容下要存储的整数或者计算出来的整数,就可以使用int类型,否则使用浮点类型。而浮点类型也有好几种,有单精度浮点类型float和双精度浮点类型double,double类型在表示范围和精度上比float还要强大,实际编程中建议直接使用double类型,本章的例子对浮点数的精度和范围没有特别高的要求,故先使用float类型做演示。

可能有同学好奇不同的类型是怎样保存数值的。实际上,整数变量里面保存1和浮点变量里面保存1.0的二进制序列是很可能一样的。反过来说相同的二进制序列在以整数值和浮点值来解释,表示的值也很可能是不一样的。这方面的知识可以参考课本第2章-信息在计算机中的表示。

后续有单独的一章介绍C语言中的类型。

2.2.2 变量的赋值

变量声明后就可以使用了。对变量常见的操作之一是向变量赋值,比如

birth_year = 1998;

或者

radius = 20.0;

上述式子中的等号是赋值运算符,表示将其右边的值保存到左边变量中,它表示一个动作,与数学中的等号表示左右两边的值是相等的是不同的。

赋值号左边必须是变量,或者其它可以存储值的地方(在C语言中被称为“左值”),像下面的使用就是错误的

2000 = 1998;

赋值号右边可以是值,也可以是式子,

age = 2019 - 1998;

上述式子的含义是先计算式子的值2019 - 1998,得到21,然后将21赋给左边变量age

在变量已经保存了某个明确的值后,它自己也可以放到赋值号右边参与运算,比如。

age = 2019 - birth_year;
age = age + 1;
bmi = weight / (height * height);

语句age = 2019 - birth_year;的含义是算出赋值号右边式子2019 - birth_year的值,然后将该值赋给左边变量age

语句age = age + 1;的含义是算出赋值号右边式子age + 1的值,然后将该值赋给左边变量age,最终效果就是age的值增加了1。

语句bmi = weight / (height * height);的含义是将体重变量weight的值除以身高变量height的值的平方,得到的值(体重指数)再保存到变量bmi中。注意,C语言中同数学中运算一样,除法运算符/和乘法运算符*的优先级是一样的,而且式子从左向右计算,因此式子不能去掉小括号,写成bmi = weight / height * height;,否则右边式子算出来的值就是weight变量的值。

在以上几个例子中,赋值号右边的式子2019 - birth_yearage+1weight / (height * height)也称为表达式。C语言中表达式是由变量、运算符、常量组成的式子。

C语言中的二元算术运算符有+ 、 - 、 * 、 / 、 %,其中%是取余运算符,它要求运算数都是整数,比如7%2等于1,10%2等于0。+ 、 - 、 * 、 / 四个运算符与数学中含义一样,只是/运算当运算符两边的运算数都是整数时,结果也是整数,比如7/2等于3,而不是3.5,这与数学中不一样,请小心。

注意,C语言中没有平方运算符。计算height的平方不能写成height ^ 2

2.2.3 显示变量/表达式的值

一个程序的目标往往是计算出某个值,比如年龄,体重指数等等,程序的往往需要输出这些值给用户查看。在控制台环境下可以使用printf函数输出/打印变量的值。

比如,在算出年龄age后,希望输出:

年龄是***岁

可以这样调用printf函数:

printf("年龄是%d岁\n", age);

printf函数的作用输出双引号里面的字符串,字符串中的%d表示输出的是一个整型值,而具体的值需要放在字符串后面的表达式里面(单独的变量也属于表达式),和字符串之间用逗号隔开。%d也称为转换说明,可以理解成它用来指明要显示的值的位置和类型。%d用来显示整数值。如果要显示浮点值(float和double),需要使用%f。

下图为printf函数的一般使用形式:

在这里插入图片描述
比如要显示:

当前年龄是***岁,下一年年龄是***岁

printf函数就要这样调用:

printf("当前年龄是%d岁,下一年年龄是%d岁\n", age, age + 1);

注意,第二个显示的值不是变量的值,而是表达式age + 1的值,这与赋值运算符右边允许是表达式的道理是一样。在C语言中,需要值的地方都可以写成表达式,C语言知道先计算表达式的值,然后使用它。即上面的语句与下面的代码等价:

int temp = age + 1;
printf("当前年龄是%d岁,下一年年龄是%d岁\n", age, temp);

下表列出输出不同类型数值的转换说明符:

类型符号
int%d
float%f
double%f(C99允许使用%lf)

因为scanf输入函数处理double值的转换说明符是%lf,故为了方便理解和使用,C99标准允许输出double值时使用转换说明符%lf。

默认情况下,%f会显示小数点后6位数字,如果要强制%f显示小数点后p位数字,可以把.p放在%和f之间。比如,在算出体重指数bmi后,希望小数点后显示2位,那么printf函数可以这样调用:

printf("体重指数是%.2f\n", bmi);

后续有单独的一章介绍C语言中的输入和输出函数。

2.2.4 案例-计算圆的面积(半径固定)

根据圆的半径可以计算出相应圆的面积,下面编写程序计算半径是20的圆的面积。首先我们要有程序的基本模板(一般小程序都要用到输入和输出,使用它们需要包含头文件stdio.h,因此这里有包含)

#include <stdio.h>
int main()
{
    // 程序代码
    return 0;
}

然后理清程序基本步骤/流程

#include <stdio.h>
int main()
{
    // 1. 定义浮点类型变量radius并赋初值20,area
    // 2. 计算半径为radius的圆的面积,并存储到变量area中
    // 3. 输出
    return 0;
}

最后完成相应的代码

#include <stdio.h>
int main()
{
    // 1. 定义浮点类型变量radius并赋初值20,area
    float radius = 20.0, area;
    // 2. 计算半径为radius的圆的面积,并存储到变量area中
    area = 3.14 * radius * radius;
    // 3. 输出
    printf("半径为%.2f的圆的面积是%.2f\n", radius, area);
    return 0;
}

当然,上述程序完全可以不需要定义变量,下面的一条语句就可以满足程序的需要。

printf("半径为%.2f的圆的面积是%.2f\n", 20.0, 3.14 * 20.0 * 20.0);

对比起来,定义变量来存储半径值和面积虽然开始的时候麻烦了一些,但是在需要引用半径值的地方就可以直接写出存储半径值的变量名radius,而不需要写数值20.0。像20.0这样的数字直接写在表达式中其含义就比较模糊,甚至有时候被称为magic number,不如用引用radius的方式来引用20.0更增加代码的可读性和可维护性。

2.2.5 输入值到变量中

案例-计算圆的面积(固定半径)中,圆的半径值是固定的20,如果要计算半径是30的圆的面积,我们要修改radius为30,再编译、运行程序才可以计算。这非常麻烦,能否不用修改程序的源代码,而在程序的运行过程中输入半径值到变量radius中呢?这是可以的,scanf函数的作用就是在程序的运行过程中将值赋给变量,只要将原程序中radius = 20;替换为语句:

scanf("%f", &radius);  // 替代radius = 20;

可以使用简单的程序来验证输入函数scanf的效果

#include <stdio.h>

int main()
{
	int x;

	scanf("%d", &x);

	printf("x等于%d\n", x);

	getchar();
	getchar();
	return 0;
}

运行上述程序,
在这里插入图片描述
输入10并按下"Enter"回车键,程序运行结果为
在这里插入图片描述
注意,scanf函数开始运行后只有按下回车键才能触发scanf函数真正工作,即读取值到变量中,否则,输入的字符串只是被暂存到输入缓冲区中。(输入的东西本质就是一串字符,scanf函数将它们解析为数值并保存到相应的变量中)

下面的图片是scanf函数使用形式:

在这里插入图片描述
与输出函数printf类似,向不同类型变量输入值需要使用不同的转换说明符:

类型符号
int%d
float%f
double%lf

注意,向double类型变量输入值的转换说明符必须是%lf,这与输出double类型的值时转换说明符可以是%f也可以是%lf不同。

与printf函数不同,scanf函数里面的变量名称前需要加&符号。&是取地址运算符,表示或取变量的在计算机中的地址。为什么这里要得到变量的地址?这个在指针章节会详细描述。

输出语句可以辅助输入语句使用,提示用户输入什么样的值。尤其是为了输入多个值,可以在输入各个值之前用输出语句提示用户下一步输入什么值,否则用户可能会搞不清要以什么顺序输入值。

float weight, height;

printf("请输入身高:");
scanf("%f", &height);
printf("请输入体重:");
scanf("%f", &weight);

printf("输入的身高是%.2f,体重是%.2f\n", height, weight);

运行上述代码,依次输入身高值和回车键,

在这里插入图片描述

体重值和回车键,

在这里插入图片描述

与一条printf函数可以输出多个值一样,scanf函数可以一次输入多个值到多个变量中,比如

float weight, height;

printf("请输入身高和体重:");
scanf("%f%f", &height, &weight);

printf("输入的身高是%.2f,体重是%.2f\n", height, weight);

注意,在用一条scanf语句来输入多个值到多个变量的情况下,输入值的时候,各个值之间需要用一个或者多个空白字符来分隔开来,否则,scanf可能无法把这些数值相互分开。C语言中空白字符是指空格符、回车符(Enter键对应的字符)、以及制表符(Tab键对应的字符)。

在这里插入图片描述
上述程序输入值时,在输入1.8之后输入了一个空格键再输入的75。

2.2.6 案例-计算圆的面积(半径输入)

基于半径值固定的代码,下面直接给半径值输入的代码

#include <stdio.h>
int main()
{
    // 1. 定义浮点类型变量radius,area
    float radius, area;
    // 2. 输入半径值到radius变量中
    printf("请输入半径值:");
    scanf("%f", &radius);
    // 3. 计算半径为radius的圆的面积,并存储到变量area中
    area = 3.14 * radius * radius;
    // 4. 输出
    printf("半径为%.2f的圆的面积是%.2f\n", radius, area);
    return 0;
}

2.2.7 变量的初始值和初始化

float radius;

这样的语句声明变量radius后,radius里面的值是多少呢?并不像某些语言(比如PHP)一样声明一个变量后语言会自动给它一个初始值,比如0,在C语言中以上述形式声明的变量的值是未知的,或者说变量没有初始值,或者说变量没有进行初始化。
在这里插入图片描述
上图展示了没有初始化的变量birth_year。

没有初始值的变量,对它的使用有什么影响呢?试图访问未初始化的变量,可能会得到不可预知的结果,在某些编译器中,可能会造成程序崩溃(比如VC2010)。关于未初始化的变量不能访问的说明后续会给出。下面看一下变量的初始化的含义:即在声明变量的时候就赋给它一个初值:

比如

在这里插入图片描述
变量初始化

float radius = 20.0f;

这个语句与先声明变量,后用赋值语句给变量赋值最终效果是一样的

float radius;
radius = 20.0f;

这种在声明变量的时候就可以给变量一个初始值的做法被称为变量的初始化

在同一个语句中可以对任意数量的变量进行初始化:

int height = 8, length = 12, width = 10;

下面来展示试图访问未初始化变量的后果,首先说明什么叫试图访问未初始化变量。下面声明的radius是未初始化的

float radius;

,而例如在表达式中使用它或者printf显示它的值都属于访问它

area = 3.14 * radius * radius;

以及

printf("半径为%.2f\n", radius);

可以看出,对未初始化变量的访问指的是对它的值进行读取的场景。

这是因为这些语句都需要读取变量radius的值,而radius是未初始化的,即没有明确值的,C语言认为当变量里面没有明确的值但是程序还要读取这个值是一种对变量的错误使用。故在VS2010中,上述两句话会被编译器警告(但不算语法错误,程序可以运行),如果运行程序,程序运行到这样的语句处就会崩溃。

在这里插入图片描述
上述程序编译有警告

在这里插入图片描述
运行会中断。

容易理解,对没有明确值(初始值)的变量进行读取在逻辑上是有问题的,故在VC2010环境中会出现以上现象。上述错误应该可以算作运行时错误。我们在编程中应该避免这种情况的发生。如果在声明变量的时候就知道变量的值应该是多少,不妨对它初始化。这样后续对它的访问就不会有不可预知的问题了。

显然,即使在变量没有初始化的情况下,对变量进行赋值,以及输入值到变量中是合理的操作

float radius;
radius = 20.0;

float radius;
scanf("%f", &radius);

否则,变量中永远也无法存储有意义的值了。无论是赋值还是用scanf函数输入值到变量中,本质上都是向变量中写值,故未初始化的变量不能访问特指不能读取变量的值而不包括向变量中写值。

2.2.8 声明变量的位置

C89要求只能在代码开头的地方声明变量,开始编写非声明变量的代码之后就不能再声明其它变量了。而C99要求没有那么严格,只要在使用变量之前声明变量,不论声明变量是在代码开头,还是在其它地方都可以。这样就做到了变量的随用随声明。

案例-计算圆的面积(半径固定)中的代码就是在函数开头声明所有变量的例子,ANSI C要求在正式程序的语句之前声明所以用到的变量。

如果是C99环境,计算圆的面积的程序中的变量area可以在使用之前再声明,比如:

#include <stdio.h>
int main()
{
    // 1. 定义浮点类型变量radius
    float radius;
    // 2. 输入半径值到radius变量中
    printf("请输入半径值:");
    scanf("%f", &radius);
    // 3. 声明area并计算半径为radius的圆的面积,并存储到变量area中
    float area;
    area = 3.14 * radius * radius;
    // 或者声明和赋值写到一条语句中
    // float area = 3.14 * radius * radius;
    // 4. 输出
    printf("半径为%.2f的圆的面积是%.2f\n", radius, area);
    return 0;
}

因此如果不确定某个环境下使用的C语言的标准,那么保守起见,以C89的标准来写程序。否则,如果明确这个环境是支持C99标准的,那么可以使用C99标准来写代码。

2.3 常量

程序中出现类似于圆周率3.14这样的值称为字面量或常量,程序中尽量不要直接出现这样的字面量,这些字面量也被称为magic number,因为后期阅读程序的人不容易理解这些值的含义。可以为这些字面量声明常量,用常量来标识这些字面量。

可以使用宏定义的方式来命名常量:

#define PI 3.14

这里的#define是预处理指令,类似于#include,因而此行的结尾也不要加分号。当对程序进行编译时,预处理器会把每一个宏替换为其表示的值。例如,语句area = PI * radius * radius;将变为area = 3.14 * radius * radius;

#include <stdio.h>
#define PI 3.14
int main()
{
    // 1. 定义浮点类型变量radius,area
    float radius, area;
    // 2. 输入半径值到radius变量中
    printf("请输入半径值:");
    scanf("%f", &radius);
    // 3. 计算半径为radius的圆的面积,并存储到变量area中
    area = PI * radius * radius;
    // 4. 输出
    printf("半径为%.2f的圆的面积是%.2f\n", radius, area);
    return 0;
}

还可以用宏来定义表达式:

#define RECIPROCAL_OF_PI  (1.0f / 3.14159f)

当宏包含运算符时,必须用括号把表达式括起来。

常量名都用大写字母表示,这个不是必须的,只是大多数C语言程序员都遵循这个规范。

再次强调,宏定义本质上是文字替换,不是C语言的语句,故宏定义的行尾不要加分号,对宏常量进行赋值也是错误的。

#define PI 3.14;  // 错误的写法
#define PI 3.14
...
PI = 3.141593; // 错误的用法

2.4 标识符

到目前为止,我们已经声明了若干个变量,比如

float radius, area;
int birth_year, age;

等等,可以观察到这些变量的名称反映了这些变量存储的值的含义,这对编写和维护代码是很有必要的。编写程序时,需要对变量、函数、宏和其它实体进行命名,这些名称称为标识符。C标准规定,标识符只能由字母、数字、下划线组成,而且必须以字母、下划线开头(不能以数字开头)。比如,下面是一些合法的标识符:

times10get_next_int

下面是一些非法的标识符:

10timesget-next-int

C语言是区分大小写的,也就是说radiusRadius是不同的变量。大多数程序员遵循在标识符中只使用小写字母的规范,常量使用大写字母。为了使名字清晰,必要时还会插入下划线:

symbol_table current_page name_and_address

另外一些程序员把名字中的除第一个单词的首字母用大写字母开头:

sysbolTable currentPage nameAndAddress

不论使用哪种方式,只要在程序中统一即可。用较为详细的名称命名变量比用缩写好,比如currentPagecp更容易理解。

下表中的关键字对C编译器有特殊的含义,因此它们不能作为标识符来使用。因为C语言是区分大小写的,因此这些关键字必须全部使用小写字母。
C语言关键字

2.5 程序的书写规范

我们可以把C程序看成一连串记号(token),即许多在不改变意思的基础上无法再分割的字符组。标识符和关键字都是记号。像+和-这样的运算符、逗号和分号这样的标点符合以及字符串字面量,也都是记号。例如,语句

printf("Height:%d\n", height);

是由7个记号组成的:

printf 标识符
( 标点符号
“Height:%d\n” 字符串字面量
, 标点符号
height 标识符
) 标点符号
; 标点符号

大多数情况下,程序中记号之间的空格数量没有严格的要求。除非两个记号合并后会产生第三个记号,否则严格从语法角度来说两个记号之间可以没有任何间隔。比如,下面的代码删除了计算圆的面积程序中的记号之间的空格或者换行:

#include <stdio.h>
#define PI 3.14
int main(){    float radius, area;   printf("请输入半径值:");    scanf("%f"
    ,&radius);    area=PI*
    radius*radius;   printf("半径为%.2f的圆的面积是%.2f\n",radius, 
    area);    return 0; }

显然,这样的程序的可读性是非常差的。因为C语言允许在记号之间插入任意数量的间隔,包括空格符、制表符和换行符(在C语言中这3个符号也被称为空白字符)。因此,源程序文件的文字安排有如下的一些默认的规范:

  1. 一行只放一条语句。
  2. 如果一行中的语句过长,可以分开放在多行内。但是一个记号内部不要有间隔。比如:
   printf("圆的半径是%.2f, 圆的面积是%.2f\n",
   radius, PI * radius * radius);

radius这样的记号内部不能有间隔,比如rad ius或者将它分两行写都是错误的。
3. 空行可以把程序划分成逻辑单元,从而使读者更容易辨别程序的结构。
4. 缩进有助于显示程序的嵌套(包含)结构。
5. 记号间的空格使我们更容易区分记号。基于这个原因,通常在每个运算符的前后都放上一个空格。比如,
c area = PI * radius * radius;
其中,areaPIradius是标识符,=*是运算符,;是标点符号。
6. 需要的话可以为程序添加适当的注释。

可读性较好的写法:

#include <stdio.h>
#define PI 3.14
int main()
{
    // 1. 定义浮点类型变量radius,area
    float radius, area;
    
    // 2. 输入半径值到radius变量中
    printf("请输入半径值:");
    scanf("%f", &radius);
    
    // 3. 计算半径为radius的圆的面积,并存储到变量area中
    area = PI * radius * radius;
    
    // 4. 输出
    printf("半径为%.2f的圆的面积是%.2f\n", radius, area);
    
    return 0;
}

2.6 常见问题

2.6.1 没有声明变量就使用变量或者先使用变量后声明。

比如,在没有声明age的情况下,出现了语句

  	age = 20;

或者,声明语句放到了使用变量语句之后

	age = 20;
	int age;

2.6.1 没有给变量值就使用变量

比如,

	  int age;
	  age = age + 1;

应该用包括初始化语句,赋值语句,以及用scanf函数输入的方式来给变量赋值后再使用变量。

2.6.3 程序顺序错误

这样的错误是比较明显的,比如计算圆的面积代码中步骤3、4顺序颠倒了

   #include <stdio.h>
   int main()
   {
       // 1. 定义浮点类型变量radius,area
       float radius, area;
       // 2. 输入半径值到radius变量中
       printf("请输入半径值:");
       scanf("%f", &radius);
       // 4. 输出
       printf("半径为%.2f的圆的面积是%.2f\n", radius, area);
       // 3. 计算半径为radius的圆的面积,并存储到变量area中
       area = 3.14 * radius * radius;
       return 0;
   }

或者步骤2和步骤3颠倒了

	#include <stdio.h>
	int main()
	{
	    // 1. 定义浮点类型变量radius,area
	    float radius, area;
	    // 3. 计算半径为radius的圆的面积,并存储到变量area中
	    area = 3.14 * radius * radius;
	    // 2. 输入半径值到radius变量中
	    printf("请输入半径值:");
	    scanf("%f", &radius);
	    // 4. 输出
	    printf("半径为%.2f的圆的面积是%.2f\n", radius, area);
	    return 0;
	}

因为程序结构是顺序的,即从第一条语句依次执行下来,所以上述语句颠倒都是错误。

2.6.4 变量类型不合适

这个问题属于程序是否合理,比如在计算圆的面积的程序中,将area变量声明成了int类型,显然,这样就是不合适的,因为算出来的圆的面积值是浮点类型的,将浮点类型的值赋值给整数类型,小数点后面的数值会丢失。

2.6.5 printf语句使用问题

  1. 格式占位符和变量类型不匹配

    比如,整数变量用printf输出或者scanf输入,对应占位符应该是%d,而不能像下面代码一样用%f,反之亦然。

     int age = 20;
     printf("年龄是%f\n", age);
    
  2. 格式字符串中没有出现占位符或者占位符与待显示的值的个数不匹配

     int age = 20;
     printf("年龄是\n", age);
    

    或者

    int age = 20;
    printf("年龄是%d,下一年的年龄是\n", age, age + 1);
    

    或者

       int age = 20;
       printf("年龄是%d,下一年的年龄是%d\n", age);
    
  3. 在printf函数调用时在变量前面放置&。

    printf("%d %d\n", &i, &j);  // 错误
    

2.6.6 scanf语句使用问题

如2.6.5中指出的那些问题,scanf语句也可能出现类似1.和2.的问题。除此之外,scanf语句可能出现一些特有的问题。

  1. 没有加取地址运算符&

    比如,

    scanf("%d", age);
    

    这会导致数值没有输入到age中。

  2. 误解了scanf函数的作用,在scanf的格式字符串中出现了非转换说明符的其它字符。

    比如, 如果希望先输出提示文字,“请输入年龄:”,然后用户再输入年龄数值到变量age中,正确的代码应该是

       printf("请输入年龄:");
       scanf("%d", &age);
    

    但是,可能错误的写成了

       scanf("请输入年龄:%d", &age);
    

    这样写就误以为scanf函数有printf函数的作用,可以输出提示文字。但是实际上,scanf函数的作用是约定输入的文字。比如scanf("请输入年龄:%d", &age);这样的写法要求用户输入:

    请输入年龄:***

    注意,上面的“请输入年龄:”是用户输入的文字,用户只有输入这段文字和年龄值,scanf函数才能正确的将年龄值输入到变量age中,否则就会出错。所以说,scanf函数没有输出功能,它的字符串的含义是规定用户输入什么。

    类似的,如果scanf函数写成了

      scanf("%d,%d", &i, &j);
    

    的形式,需要在输入一个整数后立即输入逗号,然后再输入一个整数,这样scanf函数才能正确的读入两个整数到变量i和j中。

    所以一般情况下,scanf语句中不要出现除转换说明符的其它字符。要读入两个整数,就用如下形式:

        scanf("%d%d", &i, &j);
    

    printf函数的格式控制字符串里面的内容是会输出的内容。scanf函数实际上与之相反,它的格式控制字符串里面的内容规定了需要用户输入的内容。scanf函数的工作过程是以输入内容匹配格式控制字符串里面的内容的过程。一旦发生匹配错误,scanf函数就会提前结束。

  3. scanf的格式控制字符串里面出现了空格、\n这样的空白字符,这会导致scanf函数一直无法结束,直到输入了任意一个非空白字符并输入回车键为止。就像下面的代码在运行过程中表现的那样。

        scanf("%d\n", &i);
    

    这是因为空格、\n会匹配输入的若干个空白字符(空格、制表符、回车符),直到匹配到了某个非空白字符为止。所以无论输入多少次回车scanf函数都无法结束scanf函数,因为回车符属于空白字符。

  4. scanf输入浮点数时,不能规定输入的小数个数(与printf可以规定输出的小数个数不同)

     scanf("%.2f", &x);  // 错误
     ```
    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值