WHCSRL 技术网

【C语言初阶】初识C语言(计算机眼中的数据)

一、计算机眼中的数字

计算机的世界

  • 二进制数的换算

通常再生活中我们所使用的是十进制数,数字都是0~9这十个数字,除开数学领域外,普通人几乎不会涉及到其他进制的应用,正因为十进制在生活中的使用的快捷性和实用性,人类对其的应用非常广泛。

而对于计算机来说,它认识哪些东西呢?

相信大家都知道,计算机中的一切数据其实都是由1和0组成的,也就是说计算机所认识的数字只有1和0,与我们习惯使用十进制数一样,计算机所使用的数字也与计算机的组成息息相关。电路可以说是计算机最重要的元件,而每一条电路都只有两种状态:开或者关,两种状态恰好与1和0相对应,这也就解释了计算机使用二进制的原因。

1.二进制数的换算

我们如果想将二进制数与十进制数互相转换,那该如何实现呢?
下面我会用例子给大家说明
例:二进制数 ‘1010’ 如果转化为十进制数是多少呢?

运用类比思想 ,我们可以想:十进制数例如 ‘121’
个位上1的权重为10的零次方
十位上的权重为10的一次方
百位上的权重为10的二次方,于是可以表示为
1*102+2 *101+1 *100 运算结果是 121。
所以对于‘1010’
最低为为第一位,则第n位的权重位2的n-1次方,于是可表示为
1 *23+0 *22+1 *21 +0 *20运算结果是 10。
即等于十进制的10.
而对于二进制数的各种运算就不做详细阐述了,运用类比的思想,将十进制数的运算方法照搬过来,其实也就是二进制数的运算方式了。

二、计算机的内存

1.内存的基本单位bit

通常我们的电脑有32位计算机和64位计算机,而这里的‘位’到底是什么呢?
这里所说的位数其实是计算机的地址线根数,而我们知道每根地址线会存在两种状态,即正和负,这些所有的地址线的状态则可以表示为很多个二进制数。
在高中数学中我们学习过排列组合,因此不难知道,假如地址线有x根,则这些地址线状态总共就有2的x次方种(每一根有两种,x根的组合).
这里我们以32位计算机为例子:

00000000000000000000000000000000
这里有32个0,代表32根地址线都处于负

我们一直对其进行加1的操作

00000000000000000000000000000000
(+1)
00000000000000000000000000000010
(+1)
…………
……

(+1)
11111111111111111111111111111111

最终变成了32个1组成的二进制数
那这个数为多少呢?
根据排列组合的知识很容易的出其值为
2的32次方-1=4294967295.

2. 内存大小的换算

仍然以32位计算机为例,可以知道32位计算机可以表示从0到4294967295这么多的数字。
在日常生活中,每户人都有属于自己的街道名称,门牌号等住址信息,这样就方便了我们寻找一个地址。
计算机也是这样,计算机中的数据也会有一个自己的”地盘“,并且拥有明确的编号,像下面这样每一个编号都代表着一块空间,于是内存就被分配了编号和大小。
|

000000000000000000000000000000000
000000000000000000000000000000011
000000000000000000000000000000102
111111111111111111111111111111104294967294
111111111111111111111111111111114294967295

而这里的每一个编号所代表的空间的大小就为1个byte(字节)
不同内存大小的换算如下:
1pb=1024tb
1tb=1024gb
1gb=1024mb
1mb=1024kb
1kb=1024byte
1byte=8bit
通过这样的计算方法也可以计算出32位计算机的内存大小约为4GB.

三、C语言是什么

1.一门语言

既然是一门语言,那么如同日语、英语一样,是供人们之间交流的。
计算机语言就是人和计算机交流的媒介,它使得我们可以命令计算机处理执行一些我们想让他做的事。

2.main函数-程序的入口

1.main函数一定要有
2.main函数在一个程序中有且只有一个
框架:

int main()
{
	return 0;
}
  • 1
  • 2
  • 3
  • 4

接下来我们在VS2019环境下证实一下

我们将断点设置在引用头文件的位置,看看其从哪里开始执行
在这里插入图片描述
调试后直接跳到了主函数内部的第一个位置
据此,我们可以证明main函数的确是程序的入口

四、常见数据类型

如果我们想表示一个人的年龄,那么可以用一个整数来表示,那如果想表示一本书的价格呢?那是不是就该用一个小数来表示了呢?于是浮点型和整型的数据类型便诞生了。

1.整型

数据类型解释
int整型
char字符
short短整型
long长整型
longlong超长整型

2.浮点型

数据类型解释
float单精度浮点型
double双精度浮点型
  • 注意:双精度浮点型精度更高

3.变量的定义方式

通常定义一个变量的方式为: 数据类型+变量名;
以int为例
我们来定义一个名字为i的变量

		int i=0;//使用int类型创建了一个变量i,
		//i向内存申请了一块空间,空间名叫i
		i=10;//向i空间内放入整型10
  • 1
  • 2
  • 3

于是一个类型为int,名称为i的变量就创建好并被赋值啦。

注意:C语言没有字符串类型

五、常量和变量

一、常量

常量即为不能改变的量

  • 字面常量
  • 常变量
  • 标识符常量
  • 枚举常量

1.字面常量

  • 字面常量就是直接写出来的数

例如:10,99等这样的数字

2.常变量

  • 常变量即被const修饰的变量
    例如:const int i=9;// i 就不能再被赋予其他值了,我们来尝试一下:
int main()
{
	//const-常属性
	const int i = 9;
	i = 1;
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

可以看到这里已经报错了
在这里插入图片描述
在这里插入图片描述

值得一提的是该定义方式下的变量为常变量,之所以叫常变量,是因为虽然不能再被赋值,但是 i 仍为变量,只不过具有了常属性,所以叫常变量。

  • 注意:这里的 i 不能作为定义数组时的数组元素个数[i]

3.标识符常量

  • 标识符常量是由#define定义的常量

例如:#define MAX 10
即定义了MAX为常数 10
在程序中遇到MAX后会直接将MAX替换为10
接下来我们来试试:

#include<stdio.h>
#define MAX 10
int main()
{
   printf("%%d", MAX);
   return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

运行结果如下:
在这里插入图片描述

注意:这里的 a 能作为定义数组时的数组元素个数[a]

4.枚举常量

字面意思就可以知道”枚举“就是一一列举
并且由关键字enum修饰
接下来举一个例子:

#include<stdio.h>
enum sex		//枚举关键
{
	MALE,		//表示枚举出来的可能值
	FEMALE,
	neutrality
};
int main()
{
	enum sex a = MALE;		//给相应的变量赋值
	enum sex b = FEMALE;
	enum sex c = neutrality;
	printf("a=%%d
", a);		//依次打印出变量的值
	printf("b=%%d
", b);
	printf("c=%%d
", c);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

输出为:
a=0
b=1
c=2
表明在枚举时系统会按照顺序依次从0开始对枚举出来的MALE/FEMALE/neutrality的赋值

如果我们稍稍改变一下上面的代码,来看看它如何对枚举常量赋值。

#include<stdio.h>
enum sex
{
	MALE,
	FEMALE=2,
	neutrality
};
int main()
{
	enum sex a = MALE;
	enum sex b = FEMALE;
	enum sex c = neutrality;
	printf("a=%%d
", a);
	printf("b=%%d
", b);
	printf("c=%%d
", c);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

输出依次为:
a=0
b=2
c=3

可以看出其赋值是依次递增1的,如果人为的给其赋值,则下一个仍然是递增一个1

二、变量

  • 全局变量
  • 局部变量
  • 变量的使用

代码块— { }

1.全局变量

全局变量—定义在块之外的变量

2.局部变量

局部变量—定义在块之内的变量

3.变量的使用

接下来举一个例子来更好的认识全局变量和局部变量

#include<stdio.h>
int a = 0;
int b = 0;
int main()
{
	int x = 0;
	int y = 0;
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

a和b是定义在{ }之外的叫做全局变量
x和y是定义在{ }之内的叫做局部变量

C语言规定:定义变量必须在当前代码块的最前面(C99之前)

4.变量的作用域和生命周期

生命周期大家都知道指的是事物的存在时间,人的生命周期是从出生到死亡,而在我们活着的这段时间里我们可以做很多事情,而当我们的生命周期结束——即死亡后,便彻底消失在了这世界上。
因此,我们所创建的变量在内存中也有它的生命周期

在创建一个变量时就会占用一部分内存,这个变量的生命周期开始,而内存时有限的,我们不能只向内存索取,而不给予内存空间反馈,这样最终内存会耗尽。
因此,在变量使用结束后我们会销毁这个变量,并将空间还给操作系统,这样,一个变量的生命周期就结束了

作用域
我仍然使用人来作为例子,在人处于生命周期内,也就是活着的时候,我们可以做很多事情,旅游、学习,甚至时改变世界,因此我们活着时,所处的世界就是我们的作用域…
而当我们的生命结束,便无法对这个世界再产生影响,也就是脱离了我们的作用域了。

局部变量也是这样,变量的作用域就是其所在的块内,在它的块内时,它处于生命周期中,并且可以发挥作用。
因此局部变量的作用域:其所在的块内。

而全局变量就如同长生不老的神一般,世界创世之初就存在,只有这个世界消失了,它才会跟着消失。
而对于全局变量来说它所处的世界就是一个工程,因此
全局变量作用域是整个工程。

总结:

1、局部变量的生命周期:进入作用域开始,出作用域结束
2、全局变量的作用域:整个工程

六、字符与字符串

  • 字符
  • 字符串

1.字符

字符:被‘ ’括起来的一个字母数字或者是符号
例:‘a’,’c’,‘#’ 这些都是字符

  • 可我们之前说了计算机只认识0和1两个数字,那么字符在计算机中是如何存储的呢?

我们从计算机的数据的存储方式来说:

数据在计算机上存储的时候,存储的是二进制的数,因此需要存储字符时,实际存储的是某一个数,也就是ASCII码值。

2.字符串

” “括起来的一串字符
例如:”hello world!“就是一个字符串。
接下来我将会使用一个代码讲述字符串一个很容易忽视的细节

int main()
{
	char arr[] = "hello";
	char arr1[] = { 'h','e','l','l','o' };
	printf("%%d
", sizeof(arr));
	printf("%%d
", sizeof(arr1));
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

运行结果输出为:
6
5

通过上运行结果可看出可以看出,arr和arr1的大小是不同的。
表面上看好像上面两个数组中存放的都是 ‘h’ ’e‘ ’l‘ ’l‘ ’o’ ,但我们通过调试可以看到:
在这里插入图片描述
arr比arr1这里多了一个’‘(终止字符)
也就是说在字符串“hello”中实际在末尾还有一个’‘作为字符串结束的标志。
也就能解释在用sizeof对两个数组求大小时出现的大小不同的情况了。

除此以外还有一种情况让我们值得思考:
strlen函数是用于求出字符串的长度,并且不包括’‘,仅仅知道即可,目前不必深究。
那就是利用strlen函数求出arr和arr1的字符串长度,代码如下:

int main()
{
	char arr[] = "hello";
	char arr1[] = { 'h','e','l','l','o'};
	printf("%%d
", strlen(arr));
	printf("%%d
", strlen(arr1));
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

运行结果输出为:
在这里插入图片描述

这里又是为什么呢?明明strlen求的是字符串的长度,与’‘无关了,为什么还会得出一个相差如此大的结果呢?

这就要从strlen的实现来解释了,strlen函数是从字符串的第一个字符开始,每跳过一个一个字符计数器count就会+1,直到遇到字符串结束标志为止。
而arr1在内存中的位置是随机的,无法确定arr1后面遇到的第一个’‘在哪里,所以strlen(arr1)是个随机值。

如果将上面的代码改为:

int main()
{
	char arr[] = "hello";
	char arr1[] = { 'h','e','l','l','o',''};
	printf("%%d
", sizeof(arr));
	printf("%%d
", sizeof(arr1));
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输出结果为:
6
6
就符合我们的预期啦!

同时上述写法中arr和arr1是完全相同的,并无差异。

首次写文,如有错误,还请指正!

推荐阅读