C语言基本概念(下)【C语言入门到精通】

C语言基本结构(下)

Every program is a part of some other program and rarely fits.1

码字不易,对你有帮助 点赞/转发/关注 支持一下作者

思维导图


在这里插入图片描述


写在前面


如果只是写个人学习总结的博客很容易,简单写一些感悟然后贴上代码走人就可以了,甚至不用校审。但是我命名本系列为【C语言必知必会】帮助你从入门到精通 C语言,那势必要“事无巨细”一些:既要考虑到没有基础的初学者,又不能止于基础。所以本教程适合各类人群学习,只要你看就一定会有帮助。

本教程是本人纯手打并排版,校审由我与我的搭档汤圆君一起完成的。你们看这一篇文章我要写好几个小时。如果文章对你有帮助,请不要“白嫖”。支持一下作者,作者会发更多干货好文。

》 此符号表示该内容以后的章节会讲解,此章节内不要求理解。

简单的程序结构


下面是一个简单的程序,身高是给出的,体重是在程序中得到的,我们输出的是体重与身高/体重的值。

这里我们更注重的是程序的结构而非程序本身。

示例

在这里插入图片描述

1. 类型

每一个变量都有类型(type)。类型用来描述变量的数据的种类,也称数据类型

扫描二维码关注公众号,回复: 10240986 查看本文章

数值型变量的类型决定了变量所能存储的最大值与最小值,以及是否允许小数点后出现数字。

示例中只有一种数据类型:int

int(integer):即整型,表示整数。

数据类型还有很多,目前除了 int 以外,我们只再使用另一种:

float(floating-point): 浮点型,可以表示小数

注意:虽然 float 型可以带小数,但是进行算术运算时,float 型要比 int 型慢,而且 float 通常只是一个值的近似值。(比如在一个float 型变量中存储 0.1, 但其实可能这个变量的值为 0.09999987,这是舍入造成的误差)

题外话:我当时学的时候,就没有人告诉我这些知识,你们如果现在是初学,我都感觉到羡慕,你们要少走多少弯路啊!

2. 关键字

int 与float 都是C语言的关键字(keyword),关键字是语言定义的单词,不能用做其他用途。比如不能用作命名函数名与变量名。

关键字:斜体代表C99新增关键字

auto enum unsigned break extern
return void case float short
volatile char for signed while
const goto sizeof continue if
static default struct do int
switch double long typedef else
register union
restrict inline _Bool _Complex _Imaginary

如果关键字使用不当(关键字作为变量名),编译器会将其视为语法错误。

保留标识符(reserved identifier):下划线开头的标识符和标准库函数名(如:printf())

C语言已经指定了这些标识符的用途或保留了它们的使用权,如果你使用它们作为变量名,即使没有语法错误,也不能随便使用。

3. 声明

声明(declaration):在使用变量(variable)之前,必须对其进行声明(为编译器所作的描述)。

声明的方式为:数据类型 + 变量名(程序员自己决定变量名,命名规则后面会讲)

示例中的 int weight完成了两件事情。第一,函数中有个变量名为 weight。第二,int 表明这个变量是整型。

编译器用这些信息为变量 weight 在内存中分配空间。

C99 前,如果有声明,声明一定要在语句之前。(就像示例那样,函数体中第一块是声明,第二块才是语句。)

C99 和 C11 遵循 C++ 的惯例,可以把声明放在任何位置。即可以使用时再声明变量。以后C程序中这种做法可能会很流行。但是目前不建议这样。

书写格式而言,我建议将声明全部放在函数体头部,声明与语句之间空出一行

4. 命名

weight,height 都是标识符,也就是一个变量,函数或其他实体的名称。因此,声明将特定标识符与计算机内存的特定位置联系起来,同时也就确定了存储在某位置的信息类型或数据类型。

给变量命名时要使用有意义的变量名或标识符。如果变量名无法清楚的表达自身的用途,可以在注释中进一步说明,这是一种良好的编程习惯与编程技巧。

C99 与 C11 允许使用更长的标识符,但是编译器只识别前 63个字符。对于外部标识符,只允许 31 个字符。事实上,你可以使用更长的字符,但是编译器可能忽略超出的部分。(比如有两个标识符都是 64 个字符,但只有最后一个字符不同。编译器可能会视其为同一个名字,也可能不会。标准并未定义在这种情况下会发生什么。)

命名规则:可以用小写字母,大写字母,数字和下划线(_)来命名。名称的第一个字符必须是字符或下划线,不能是数字

操作系统和C库经常使用一个下划线或两个下划线开始的标识符(如:_kcab),因此最好避免在自己的程序中使用这种名称。(避免与操作系统和c库的标识符重复)

C语言的名称区分大小写。即:star,Star,STAR 是不同的。

声明变量的理由

  1. 把所有变量放在一处,方便读者查找和理解程序的用途。
  2. 声明变量可以促使你在编写程序之前做好计划(比如你的程序要用什么变量,你可以提前规划)。
  3. 声明变量有助于发现程序中的小错误,如拼写错误。
  4. 不提前声明变量,C程序编译将无法通过

5. 赋值

赋值(assignment):变量通过赋值的方式获得值。

示例中,weight = 160;是一个 赋值表达式语句。意思是“把值 160 赋给 变量 weight”。

在执行 int weight;时,编译器在计算机内存中为变量 weight 预留的空间,然后在执行这行代码时,把值存储在之前预留的位置。可以给 weight 赋不同的值,这就是 weight 之所以被称为变量的原因。

注意:

  • 该行表达式将值从右侧赋到左侧。

  • 该语句以分号结尾。

  • = 在计算机中不是相等的意思,而是赋值。我们在读 weight = 160;时,我们应该这么读:“将 160 赋给 weight”

  • ==表示相等

6. printf() 函数

printf(“我的体重是:%d斤\n,身高与体重的比为:%d”, weight, height / weight);

这是我们示例中的 printf 函数,我们来看两个不那么复杂的:

main(void);
printf("Hi");

首先,printf() 的 圆括号是不是很像 main() ?这表示 printf 是一个函数名,它也是一个函数。圆括号内的内容是从 main() 函数传递给 printf() 函数的信息。该信息被称为参数,更确切的说,是实际参数(actual argument),简称实参

既然是函数,它其实也是像我们看到的 main函数一样,也有函数头和函数体。

printf() 函数是一个库函数,库函数我们上一节讲函数种类时说过,这是一种不需要程序员去写的,只需要引用头文件 stdio.h就可以直接使用的。但是我们应该知道这一点,详细情况我们后面会说讲。

当程序运行到 printf() 函数这一行时,控制权被转给了printf()函数。函数执行结束后,控制权被返回至主调函数(calling function),该例中是 main()

printf() 函数的作用是向我们的显示器输出内容。

此例中,printf() 函数的括号内 分为两部分,一部分在双引号内,另一部分在双引号外,它们中间以逗号隔开。双引号外有两个参数 weight 和 height / weight ,他们分别是变量和表达式(含有常量,变量和运算符的式子),也是指定要被打印的参数(打印到你的屏幕上)。

我们发现,最终我们屏幕上看到的是引号内的内容。我们可以来看一下输出的内容:

我的体重是:160斤
身高与体重的比为:1

我们发现:首先引号内的 %d\n并没有被输出,%d的位置被替换成了一个整数。为什么会这样呢?

\n代表一个换行符(newline character)。对于 printf 函数来说,它的意思是:“在下一行的最左边开始新的一行”。

也就是说换行符和在键盘上按下 Enter按键相同。既然如此,为何不在键入 printf() 参数时直接使用 Enter键呢?因为编辑器可能认为这是直接的命令,而不是存储在源代码中的指令。换句话说,如果直接按下 Enter键,编辑器会退出当前行并开始新的一行。但是,换行符会影响程序输出的(显示)格式。

换行符是一个转义序列(escape sequence)。转义序列用于难以表示或无法输入的字符。如,\t代表 Tab键,即制表符。\b代表 Backspace键,即退格键。我们在后面会继续讨论。

这样就解释了为何一行的printf() 函数会输出两行。

以下这部分不能理解可以只看结论,能理解更好。

在解释 %d 之前我们先来看一下,weight 和 height / weight 所代表的值。

weight 是被赋值为 160 的,所以 weight 的值就是 160

C语言中,/表示除法, * 表示乘法。

那么 height / weight 的值是多少呢?我们现在不知道这个表达式的值是多少,但是我们知道这个它肯定代表 180 / 160

而最终输出的值是 1 ,这和我们想的不一样,我们知道结果应该是个小数,那么这是为什么呢?

我想可能的原因有两个:

  1. %d 将小数转换为整数
  2. 180 / 160 本身在C语言中的值就是整数

我们来测试一下:

int main(void) {

	int a = 3;
	int b = 2;
    float c = 1.1f;//f 表示1.1是浮点数

	printf("%d\n", c);//%d 用来输出整型
	printf("%f\n", a / b);//%f 用来输出浮点型
	
	return 0;
}

输出:

-1717986918
0.000000

输出并不是我们想要的内容,我们来看一下编译器的警告:

编译器警告:

	“printf”: 格式字符串“%d”需要类型“int”的参数,但可变参数 1 拥有了类型“double”	
	“printf”: 格式字符串“%f”需要类型“double”的参数,但可变参数 1 拥有了类型“int

可以不去理解报错的内容。输出与报错至少说明了一点:

%d 在我的编译器上无法输出浮点型;整型 / 整型 不是浮点型。

那就说明了原因2是对的,即:180 / 160 的值就是 1

为什么 180 / 160 == 1(180 / 160 的值是 1)呢?

因为 weight 和 height 都整数,它们相除结果取整数(向下取整)。

如何输出 float 类型的浮点数?

printf("%f", 2.0f);

%d是一个占位符,其作用是指明 num 值的位置。d 代表 以十进制的格式。

还有一点要注意的是,在示例中,第二个输出的整数的参数(height / weight )是一个表达式,我们也可以在程序中添加一个新的变量,然后用这个变量代替上面的表达式作为 printf() 的参数。如:

int main(void)
{
	int height = 180;
	int weight, scale;//scale:比例
	weight = 160;
    scale = height / weight;
	printf(“我的体重是:%d斤\n,身高与体重的比为:%d”, weight, scale);
	return 0;
}

合理的使用表达式作为函数的参数可以简化程序。

也说明在任何需要数值的地方,都可以使用具有相同类型的表达式

7. 初始化

当程序开始执行时,某些变量会被自动设置为0,而大多数不会。没有默认值并且尚未在程序中被赋值的变量时未初始化的(uninitialized)。

如果试图访问未初始化的变量,可能会得到不可预知的值。在某些编译器中,可能会发生更坏的情况(甚至程序崩溃)。

我们可以用赋值的办法给变量赋初值,但还有更简洁的做法:在变量声明中加入初始值。

例如示例中的 int height = 180数值 180 就是一个初始化式(initializer)。

同一个声明中可以对任意数量的变量进行初始化。如:

int a = 10, b = 15, c = 20;

上述每个变量都拥有属于自己的初始化式。接下来的例子,只有 c 有初始化式,a,b没有。

int a, b, c = 20;

参考资料:《C Primer Plus》《C语言程序设计:现代方法》

本文GitHub已更新,所有教学和练习代码都会上传上去,欢迎 star !

https://github.com/hairrrrr/C-CrashCourse


以上就是本次的内容。

如果文章有错误欢迎指正和补充,感谢!

最后,如果你还有什么问题或者想知道到的,可以在评论区告诉我呦,我可以在后面的文章加上你们的真知灼见。

关注我,看更多干货!

我是程序圆,我们下次再见。


  1. 每个程序都是其他程序不合适的一部分。 ↩︎

发布了65 篇原创文章 · 获赞 226 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_44954010/article/details/104678394