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) 左值 : 代表变量的地址

​ 可以定义的地址,可写的地址

"在赋值 = 的左边"

image-20230629114607012

请问 : 何时代表变量的值, 何时代表变量的地址

#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位是数值位

image-20230629142130334

练习 :

​ 假设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语言的标准委员会建议如下策略 :

  1. 长的 ---> 短的

    低字节直接拷贝,高字节直接舍弃(丢掉)

  2. 短的 --> 长的

    低字节直接拷贝,高位补什么?

    如果短的是 无符号,高位全部补0.

    如果短的是有符号的, 高位全部补符号位.