【学习笔记】【C语言】变量的内存分析,学习笔记c语言变量

C语言入门:05.scanf函数,语言入门05.scanf

在前面一节中简单介绍了变量的使用,当我们定义一个变量的时候,系统就会为变量分配一块存储空间。而变量的数值在内存中是以二进制的形式存储的,这讲来深入研究变量在内存中的一些存储细节。

1. 字节和地址

为了更好地理解变量在内存中的存储细节,先来认识一下内存中的“字节”和“地址”。

1> 内存以“字节为单位”

上面的写法是不建议的

 

3.课程代码

 

 1 #include <stdio.h>
 2 
 3 
 4 // 1.内存寻址由大到小,优先分配内存地址比较大的字节给变量 
 5   
 6 // 2.变量越先定义,内存地址就越大 
 7   
 8 //3.取得变量的地址:&变量名 
 9   
10 // 4.输出地址:%p 
11   
12 //5.一个变量一定先进行初始化,才能使用 
13  
14 
15 int main() 
16 { 
17     // 内存寻址由大到小 
18     int a = 10; 
19     
20     int b = 20; 
21     
22     int c; 
23     
24     // &是一个地址运算符,取得变量的地址 
25     // %p用来输出地址 
26     // 0x7fff56f09bc8 
27     printf("a的地址是:%p\n", &a); 
28     // 0x7fff56f09bc4 
29     printf("b的地址是:%p\n", &b); 
30     // 0x7fff56f09bc0 
31     printf("c的地址是:%p\n", &c); 
32     
33     //由于变量c没有经过初始化,所以直接拿来使用是不对的 
34     //int d = c  + 1; 
35     
36     
37     printf("c的值是%d\n", c); 
38     
39     return 0;
40 
41 }

 

  1. 字节和地址
    为了更好地理解变量在内存中的存储细节,先来认识一下内存中…

一、变量的内存分析

一、字节和地址

为了更好地理解变量在内存中的存储细节,先来认识一下内存中的“字节”和“地址”。

1.计算机中的内存是以字节为单位的存储空间。内存的每一个字节都有一个唯一的编号,这个编号就称为地址。就好像酒店是以房间为单位的,每个房间都有一个唯一的房号,我们根据房号就能找到对应的房间。

图片 1

里面的每个小框框就代表着内存中的一个字节,白色数字就是每个字节的地址(这里采取十六进制来显示,地址值是随便写的,仅作为参考,真实情况中的地址值不一定是这个),可以发现,内存中相邻字节的地址是连续的。

 

2.大家都知道,一个字节有8位,所能表示的数据范围是非常有限的,因此,范围较大的数据就要占用多个字节,也就是说,不同类型的数据所占用的字节数是不一样的。

 

1.字节和地址

为了更好地理解变量在内存中的存储细节,先来认识一下内存中的“字节”和“地址”。

(1)内存以“字节为单位”

图片 2

0x表示的是十六进制,不用过于纠结,能看懂这些数字之间谁大谁小就行了

(2)不同类型占用的字节是不一样的,数据越大,所需的字节数就越多

二、变量的存储

2.变量的存储

(1)所占用字节数跟类型有关,也跟编译器环境有关

图片 3

(2)变量实例

int b = 10;

int a = 20;

●内存由大到小寻址,优先分配内存地址较大的字节给变量。b的内存地址比a大

●每个变量都有地址:第一个字节的地址就是变量的地址

(3)查看内存地址:

int a;

printf("a的地址是:%p\n", &a);

(4)注意:下面写法是不建议的

在变量未经初始化之前,不要尝试使用变量的值

int a;

printf("a的值是:%d\n", a);

 

1.变量类型的作用

跟其他编程语言一样,C语言中用变量来存储计算过程使用的值,任何变量都必须先定义类型再使用。为什么一定要先定义呢?因为变量的类型决定了变量占用的存储空间,所以定义变量类型,就是为了给该变量分配适当的存储空间,以便存放数据。比如char类型,它是用来存储一个字符的,一个字符的话只需要1个字节的存储空间,
因此系统就只会给char类型变量分配1个字节,没必要分配2个字节、3个字节乃至更多的存储空间。

 

二、scanf函数

2.变量占用多少存储空间

1>
一个变量所占用的存储空间,不仅跟变量类型有关,而且还跟编译器环境有关系。同一种类型的变量,在不同编译器环境下所占用的存储空间又是不一样的。我们都知道操作系统是有不同位数的,比如Win7有分32位、64位,编译器也是一样的,也有不同位数:16位、32位、64位(Mac系统下的clang编译器是64bit的)。由于我们是Mac系统下开发,就以64位编译器为标准。

2>
下面的表格描述了在64位编译器环境下,基本数据类型所占用的存储空间,了解这些细节,对以后学习指针和数组时是很有帮助的。

图片 4

3> 下面的表格描述了在不同编译器环境下的存储空间占用情况

图片 5

 

1.简介

这也是在stdio.h中声明的一个函数,因此使用前必须加入#include
<stdio.h>。调用scanf函数时,需要传入变量的地址作为参数,scanf函数会等待标准输入设备(比如键盘)输入数据,并且将输入的数据赋值给地址对应的变量

3.变量示例

当定义一个变量时,系统就会为这个变量分配一定的存储空间。

1 int main()  2 {  3     char a = 'A';   4       5     int b = 10;  6       7     return 0;  8 }

1>
在64bit编译器环境下,系统为变量a、b分别分配1个字节、4个字节的存储单元。也就是说:

  • 变量b中的10是用4个字节来存储的,4个字节共32位,因此变量b在内存中的存储形式应该是0000
    0000 0000 0000 0000 0000 0000 1010。
  • 变量a中的’A’是用1个字节来存储的,1个字节共8位,变量a在内存中的存储形式是0100
    0001,至于为什么’A’的二进制是这样呢,后面再讨论。

2> 上述变量a、b在内存中的存储情况大致如下表所示:

图片 6

(注:”存储的内容”那一列的一个小格子就代表一个字节,”地址”那一列是指每个字节的地址)

  • 从图中可以看出,变量b占用了内存地址从ffc1~ffc4的4个字节,变量a占用了内存地址为ffc5的1个字节。每个字节都有自己的地址,其实变量也有地址。变量存储单元的第一个字节的地址就是该变量的地址。变量a的地址是ffc5,变量b的地址是ffc1。
  • 内存寻址是从大到小的,也就是说做什么事都会先从内存地址较大的字节开始,因此系统会优先分配地址值较大的字节给变量。由于是先定义变量a、后定义变量b,因此你会看到变量a的地址ffc5比变量b的地址ffc1大。
  • 注意看表格中变量b存储的内容,变量b的二进制形式是:0000 0000 0000
    0000 0000 0000 0000
    1010。由于内存寻址是从大到小的,所以是从内存地址最大的字节开始存储数据,存放顺序是ffc4
    -> ffc3 -> ffc2 -> ffc1,所以把前面的0000
    0000都放在ffc2~ffc4中,最后面的八位0000 1010放在ffc1中。

 

2. 简单用法

int age;

scanf("%d", &age);

●scanf函数时,会等待用户的键盘输入,并不会往后执行代码。scanf的第1个参数是”%d”,说明要求用户以10进制的形式输入一个整数。这里要注意,scanf的第2个参数传递的不是age变量,而是age变量的地址&age,&是C语言中的一个地址运算符,可以用来获取变量的地址

● 输入完毕后,敲一下回车键,目的是告诉scanf函数我们已经输入完毕了,scanf函数会将输入的值赋值给age变量

4.查看变量的内存地址

在调试过程中,我们经常会采取打印的方式查看变量的地址

1 #include <stdio.h>  2   3 int main()  4 {  5     int a = 10;  6     printf("变量a的地址是:%p", &a);  7     return 0;  8 }

第6行中的&是一个地址运算符,&a表示取得变量a的地址。格式符%p是专门用来输出地址的。输出结果是:

变量a的地址是:0x7fff5fbff8f8

这个0x7fff5fbff8f8就是变量a的内存地址

 

3.其他用法

(1)用scanf函数接收3个数值,每个数值之间用中划线-隔开

scanf("%d-%d-%d", &a, &b, &c);

3个%d之间是用中划线-隔开的,因此我们在每输入一个整数后都必须加个中划线-,比如这样输入10-14-20,不然在给变量赋值的时候会出问题

●注意:数值之间的分隔符是任意的,不一定要用中划线-,可以是逗号、空格、星号*、井号#等等,甚至是英文字母

// 逗号,

scanf("%d,%d,%d", &a, &b, &c); // 输入格式:10,14,20 

// 井号#

scanf("%d#%d#%d", &a, &b, &c); // 输入格式:10#14#20 

// 字母x

scanf("%dx%dx%d", &a, &b, &c); // 输入格式:10x14x20

(2)用scanf函数接收3个数值,每个数值之间用空格隔开

scanf("%d %d %d", &a, &b, &c);

3个%d之间是用空格隔开的,我们在每输入一个整数后必须输入一个分隔符,分隔符可以是空格、tab、回车

 

三、负数的二进制形式

1 int main()  2 {  3     int b = -10;  4     return 0;  5 } 

在第3行定义了一个整型变量,它的值是-10。-10在内存中怎样存储的呢?其实任何数值在内存中都是以补码的形式存储的。

  • 正数的补码与原码相同。比如9的原码和补码都是1001
  • 负数的补码等于它正数的原码取反后再+1。(取反的意思就是0变1、1变0)

那么-10的补码计算过程如下:

1> 先算出10的二进制形式:0000 0000 0000 0000 0000 0000 0000 1010

2> 对10的二进制进行取反:1111 1111 1111 1111 1111 1111 1111 0101

3> 对取反后的结果+1:1111 1111 1111 1111 1111 1111 1111 0110

因此,整数-10在内存中的二进制形式是:1111 1111 1111 1111 1111 1111 1111
0110

图片 7

 

4.注意

scanf的第一个参数中不要包含\n,比如scanf(“%d\n”, &a);
这将导致scanf函数无法结束

四、变量的作用域

5.习题

提示用户输入两个整数n,然后计算并输出两个整数的和

 

一、变量的内存分析 1.字节和地址
为了更好地理解变量在内存中的存储细节,先来认识一下内存中…

1.作用域简介

变量的作用域就是指变量的作用范围。先来看看下面的程序:

1 int main()  2 {  3     int a = 7;  4       5     return 0;  6 }
  • 在第3行定义了一个变量a,当执行到这行代码时,系统就会为变量a分配存储空间
  • 当main函数执行完毕,也就是执行完第5行代码了,变量a所占用的内存就会被系统自动回收
  • 因此,变量a的作用范围是从定义它的那行开始,一直到它所在的大括号{}结束,也就是第3~6行,一旦离开这个范围,变量a就失效了

 

2.代码块

1> 代码块其实就是用大括号{}括住的一块代码。

 1 int main()   2 {   3     {   4         int a = 10;   5            6         printf("a=%d", a);   7     }   8        9     a = 9;  10       11     return 0;  12 }
  • 注意第3~7行的大括号,这就是一个代码块
  • 当执行到第4行时,系统会分配内存给变量a
  • 当代码块执行完毕,也就是执行完第6行代码后,变量a所占用的内存就会被系统回收
  • 因此,变量a的作用范围是从定义它的那行开始,一直到它所在的大括号{}结束,也就是第4~7行,离开这个范围,变量a就失效了
  • 所以,上面的程序是编译失败的,第9行代码是错误的,变量a在第7行的时候已经失效了,不可能在第9行使用

 

2> 如果是下面这种情况

 1 int main()   2 {   3     int a = 9;   4        5     {   6         int a = 10;   7            8         printf("a=%d", a);   9     }  10       11     return 0;  12 }
  • 注意第3、6行,各自定义了一个变量a,这种情况是没问题的。C语言规定:在不同作用域中允许有同名变量,系统会为它们分配不同的存储空间。
  • 在第3行定义的变量a的作用域是:第3~12行;在第6行定义的变量a的作用域是:第6~9行。
  • 最后注意第8行:尝试输出变量a的值。那这里输出的是哪一个变量a呢?先看输出结果:

    a=10

这里采取的是“就近原则”,也就是第8行访问的是在第6行定义的变量a,并不是在第3行的变量a。

 

五、变量的初始化

变量在没有进行初始化之前,不要拿来使用,因为它里面存储的是一些垃圾数据

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

注意第5行的变量c,只是定义了变量,并没有给它赋初值。输出结果:

1606422622

可以发现,变量c里面存储的是一些乱七八糟的数据

 

 

 

 


Author

发表评论

电子邮件地址不会被公开。 必填项已用*标注