0 在虚拟机上(linux)运行程序的步骤
1.编写代码 后缀.c 2.编译 把我们的代码翻译成 机器能够识别的文件 gcc xxx.c -o xxx gcc 是编译器, 用来把我们写的.c文件编译成 机器可以识别的文件(可执行文件) xxx.c 是你的代码 -o output xxx 是生成的可执行文件 也可以这样做 gcc xxx.c 省略后面的 -o xxx ,这样的话,就默认生成的可执行文件 a.out 3.运行可执行文件 ./xxx
1 问题的引入
计算机只是人类用来解决某些问题的工具.
"某些问题" 是指哪些问题? 可以用计算机 计算 来解决问题.
计算 : 计算机通过把问题域中的数据抽象出来, 保存 , 然后对这些数据进行有目的的计算
从而得出结果.
如 : 3 + 8 ==> 11
计算机首先要保存数据, 在保存这些数据之前, 我们要知道这些数据的大小, 取值范围等数据属性.
我们要开辟多大的空间去存储数据呢?
数据的大小,取值范围, 类型,等等属性.
数据类型
2 数据类型
描述数据对象的类型的, "给数据分类"
不同的类型的数据, 属性不一样.
2.1 C语言中的数据类型
-
(1) 基本类型
C语言内置的,已经为我们定义好的, 程序员直接可以用,称之为"基本类型"
"数" : 整数 , 浮点数
- 整数
char/unsigned char : 8bits 的整数类型(或字符类型) short/unsigned short : 一般来说, short占16个bits int/unsigned int : 4个字节 32bits long/unsigned long :
区别在哪里?
保存的数据的bits不一样.
- 浮点数
用来保存有小数的数字
float : 4 bytes(一般来说) double : 8bytes long double 10 bytes
区别 :
保存浮点数的位数不一样,精度不一样
浮点数的默认类型是 : double
-
(2) 构造类型
C语言中, 允许程序员自定义类型, 自定义的组合/复合类型, 称之为 "构造类型"
数组
int a[10];//定义了一个数组, 名为a,里面有10个int类型的元素 //a表示一个数组. typeof(a) : int[10] double b[100];
...
结构体
联合体
枚举
-
(3) 指针类型
后面再讲
-
(4) void 类型
空类型 , 在C语言中, 有且仅有三个地方用到void
- void 可以做函数返回值的类型, 表示函数没有返回值
//函数func没有返回值 void func(int a) { } //函数sum有返回值, 返回值的类型是int int sum(int a,int b) { }
- void 可以做函数的形式参数,表示该函数无参数
int abc(void) { } int sum(int a,int b) { }
- void *
通用指针
有了数据类型后, 我们在程序里面, 就可以定义对象
数据对象 :
变量 : 在程序运行期间,里面的值可以被改变的数据对象, 叫变量.
常量 : 在程序运行期间,里面的值不可以被改变的数据对象, 叫常量.
3 变量的定义
"先定义 , 后使用 "
定义变量的格式 :
数据类型 变量名 { = 初始值}; { } 内表示可选
数据类型 : 代表该变量的类型,系统会根据这个类型来分配合理的空间存储变量 任意合法的类型都可以(基本类型,构造类型,指针类型) 变量名 : 就是你给变量取的名字,给变量取名字要符合"C语言标识符的规范" 标识符(取名字) : 字母数字下划线,第一个字符不能为数字,不能和关键字冲突. 如 : sb 可以 sb250 可以 250 不可以 _250 可以 ssb 可以 int 不可以.//不能和C语言的关键字冲突 "见其名知其意" 如 : int sum; int sum = 0;
4 变量的属性
int a = 5;
int a = 5;
在程序运行时,系统会为变量a分配一个四字节的存储空间,并且把数组5 存入到内存中,
"存储单元" : 系统会为每一个存储单元(以字节为单位)分配一个唯一的编号,用来区分这些存储单元.
这些存储单元的编号,称之为"存储单元的地址"
变量的属性 :
变量名
变量的地址 : 变量存储单元的地址
变量的值 : 变量存储单元的内容
练习 : 分析一下如下代码的输出结果
int main()
{
int a;
printf("a = %d\n",a);//输出变量a的值
return 0;
}
5 变量的操作
read
读取一个变量的值 : 是从变量的存储单元中, 读取值
write
把一个值写入到变量的存储单元中去.
= 赋值符号, 把右边的值赋值给左边的变量.
int a = 5; int b; a = 1024;//把数值1024存储到变量a的地址中去 //"变量的地址" b = a;//把变量a的值,赋值给b. //"变量的值"
上面的两条语句,同样是a , 含义不一样!!!
通过刚才的分析,得出结论 :
C语言中, 任何变量都有两层含义 :
- (1) 右值 : 代表变量的值
可读的值
- (2) 左值 : 代表变量的地址
可以定义的地址,可写的地址
"在赋值 = 的左边"
请问 : 何时代表变量的值, 何时代表变量的地址
#include <stdio.h> int main() { int a; scanf("%d",&a);//scanf是从键盘中获取值,存储到变量的地址中去 printf("a = %d\n",a); return 0; }
6 整数在存储器(计算机)是如何存放的?
int a = 5;
整数在计算机中是以"二进制补码" 形式存放的.
补码
正数的补码
正数的补码就是其原码的本身.
13 : 8bits 13 = 8 + 4 + 1 0000 1101 255 : 8bits 255 = 256 - 1 1111 1111
负数的补码
负数的补码是 ==其绝对值的原码取反+1==得到
-13 8bits 13 0000 1101 取反 1111 0010 +1 1111 0011 < ---- -13在计算机中的存放形式(8bits)
练习 :
(1) 假设计算中用32bits来存放整数, 请写出123 和 -123 的存放形式.
123 : 00000000 00000000 00000000 0111 1011 -123 : 00000000 00000000 00000000 0111 1011 11111111 11111111 11111111 1000 0100 取反 11111111 11111111 11111111 1000 0101 +1 <--- -123在计算机中存放形式
(2) 假设计算机中用8bits来存放整数
请写出 -1 和 255 的存放形式
请写出 -2 和 254 的存放形式
请写出 -3 和 253 的存放形式
....
写到你找到规律为止.
结论 1 :
一个负整数在计算机中的存储形式, 会 和 另外一个正整数的存放形式相同.
-x 与 2^n - x(2的n次幂 - x)
n为存放整数的bits位数.
练习 :
假设计算机中用32bits来存放整数, 存放形式为 :
11111111 11111111 11111111 11111111 请问这个整数是多少? -1 或 2^32 -1
结论2 :
在cpu底层没有符号位的概念,都是数值位,参与运算, 这个数是正数还是负数,
看你编译器的词义,意识是说, 你是把这个数当做一个有符号数(signed) ,还是
一个无符号数(unsigned)来解释.
编译器(逻辑层面)
有符号数(signed)
符号位(最高位) + 数值位(其他位)
1 负数
0 正数
无符号数(unsigned)
所有的bits位是数值位
练习 :
假设int 是 32 bits
(1) 分析如下程序的输出结果
int main() { int a = -3; printf("%d\n",a);//-3 //%d是把后面a 当做一个有符号数(signed)输出(十进制形式) printf("%u\n",a);//2^32 -3 //%u是把后面a 当做一个无符号数(unsigned)输出(十进制形式) return 0; } 求-3的补码 计算机中的存储形式 3 : 00000000 00000000 00000000 0000 0011 11111111 11111111 11111111 1111 1100 取反 11111111 11111111 11111111 1111 1101 +1 <-- -3 存储形式 变量a存储单元的内容 %d是把后面a 当做一个有符号数(signed)输出(十进制形式) 最高位表示符号位,并且1 , 表示负数 11111111 11111111 11111111 1111 1101 知道了负数补码 到底是多少? 求绝对值的原码, ==> 逆运算 11111111 11111111 11111111 1111 1101 -1 11111111 11111111 11111111 1111 1100 取反 00000000 00000000 00000000 0000 0011 <--- 负数绝对值的原码 -3 %u是把后面a 当做一个无符号数(unsigned)输出(十进制形式) 11111111 11111111 11111111 1111 1101 所有的位数都是数值位 11111111 11111111 11111111 1111 1101 2^32-1-2 ==> 2^32-3
(2) 分析如下程序的输出结果
int main() { int a = 4; printf("%d\n",a);//4 //%d是把后面a 当做一个有符号数(signed)输出(十进制形式) printf("%u\n",a);//4 //%u是把后面a 当做一个无符号数(unsigned)输出(十进制形式) return 0; }
(3) 分析如下程序的输出结果
int main() { unsigned int a = -4u; printf("%d\n",a);//-4 printf("%u\n",a);//2^32 - 4 //-4/-4u // 00000000 00000000 00000000 00000100 // 11111111 11111111 11111111 11111011 取反 // 11111111 11111111 11111111 11111100 +1 <--- -4/-4u 在计算机中的存储形式(32bits) return 0; }
typeof(-4) : 在C语言中, 整数默认是int
typeof(-4u) : unsigned int
(4) 分析如下程序的输出结果
int main() { unsigned char c = 250; char d; d = c + 8; printf("%d\n",d); printf("%d\n",d); return 0; }
7 不同的整型之间的赋值问题
C语言允许不同的整型之间的相互赋值.
char a;//8bits 整数 short b;//16bits 整数 int c;//32bits 整数 b = a; a = c; b = c; //.... //允许不同的整型之间的相互赋值
有人提出 :
长度不一样,如何来赋值?
C语言的标准委员会建议如下策略 :
长的 ---> 短的
低字节直接拷贝,高字节直接舍弃(丢掉)
短的 --> 长的
低字节直接拷贝,高位补什么?
如果短的是 无符号,高位全部补0.
如果短的是有符号的, 高位全部补符号位.