一、字节和地址
为了更好地理解变量在内存中的存储细节,先来认识一下内存中的“字节”和“地址”。
1.计算机中的内存是以字节为单位的存储空间。内存的每一个字节都有一个唯一的编号,这个编号就称为地址。就好像酒店是以房间为单位的,每个房间都有一个唯一的房号,我们根据房号就能找到对应的房间。

里面的每个小框框就代表着内存中的一个字节,白色数字就是每个字节的地址(这里采取十六进制来显示,地址值是随便写的,仅作为参考,真实情况中的地址值不一定是这个),可以发现,内存中相邻字节的地址是连续的。
2.大家都知道,一个字节有8位,所能表示的数据范围是非常有限的,因此,范围较大的数据就要占用多个字节,也就是说,不同类型的数据所占用的字节数是不一样的。
二、变量的存储
1.变量类型的作用
跟其他编程语言一样,C语言中用变量来存储计算过程使用的值,任何变量都必须先定义类型再使用。为什么一定要先定义呢?因为变量的类型决定了变量占用的存储空间,所以定义变量类型,就是为了给该变量分配适当的存储空间,以便存放数据。比如char类型,它是用来存储一个字符的,一个字符的话只需要1个字节的存储空间,
因此系统就只会给char类型变量分配1个字节,没必要分配2个字节、3个字节乃至更多的存储空间。
2.变量占用多少存储空间
1> 一个变量所占用的存储空间,不仅跟变量类型有关,而且还跟编译器环境有关系。同一种类型的变量,在不同编译器环境下所占用的存储空间又是不一样的。我们都知道操作系统是有不同位数的,比如Win7有分32位、64位,编译器也是一样的,也有不同位数:16位、32位、64位(Mac系统下的clang编译器是64bit的)。由于我们是Mac系统下开发,就以64位编译器为标准。
2> 下面的表格描述了在64位编译器环境下,基本数据类型所占用的存储空间,了解这些细节,对以后学习指针和数组时是很有帮助的。

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

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在内存中的存储情况大致如下表所示:

(注:"存储的内容"那一列的一个小格子就代表一个字节,"地址"那一列是指每个字节的地址)
- 从图中可以看出,变量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中。
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是专门用来输出地址的。输出结果是:
这个0x7fff5fbff8f8就是变量a的内存地址
三、负数的二进制形式
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 11111111
11111111 1111 1111 0101
3> 对取反后的结果+1:1111
11111111 11111111 1111 11110110
因此,整数-10在内存中的二进制形式是:1111
11111111 11111111 1111 11110110

四、变量的作用域
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呢?先看输出结果:
这里采取的是“就近原则”,也就是第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,只是定义了变量,并没有给它赋初值。输出结果:
可以发现,变量c里面存储的是一些乱七八糟的数据
分享到:
相关推荐
"03 嵌入式C语言高级---内存空间"这一主题,着重探讨了C语言在处理内存管理方面的高级概念,这对于理解和优化物联网设备的性能至关重要。以下是对这个主题的详细讲解: 内存空间在计算机系统中被划分为几个主要区域...
- 指针变量:存储内存地址的变量,允许我们直接操作内存。 - 指针运算:通过指针访问和修改变量,实现动态内存管理。 - 函数指针:可以将函数作为参数传递,实现回调和高阶函数的概念。 5. **数组与字符串** - ...
2. **变量与数据类型**:C语言有多种数据类型,包括整型(如`int`)、浮点型(如`float`和`double`)、字符型(`char`)以及布尔型(通过`#define`宏定义)。变量是用来存储值的容器,需要在使用前先声明。 3. **...
首先,变量是内存中的一个位置,它有一个特定的名称,用于存放不同类型的数据。在C语言中,我们有基本数据类型,包括整型(如int)、字符型(如char)、浮点型(如float和double)等。每种类型都有其固定的存储大小...
预处理器用于处理宏定义、包含文件等,内存管理包括动态内存分配(malloc/calloc/free)和栈与堆的概念,错误处理则涉及到异常和错误检测机制。 最后的“C语言程序设计导论.ppt”很可能是整个课程的概述或总结,...
在C语言中,指针是极其重要且强大的概念,它允许程序员直接操作内存,从而实现高效的数据处理和灵活的程序设计。本教程将深入讲解指针的各个方面。 10.1 地址和指针的概念 地址是内存中每个存储单元的唯一标识,...
- 变量与数据类型:理解C语言中的基本数据类型,如整型(int)、浮点型(float)、字符型(char)等,以及如何声明和初始化变量。 - 运算符:掌握算术、比较、逻辑和位运算符的用法,以及它们在程序中的作用。 - ...
在C语言中,内存管理是编程过程中的一个关键部分,特别是在中级阶段,理解并熟练掌握内存使用至关重要。本文将深入探讨C语言中的内存区域、内存分配方式以及如何有效地使用内存。 1. 内存区域 C语言中的内存分为三...
书中会详细讲解指针的类型、运算符、指针与数组的关系,以及指针在函数参数传递和动态内存管理中的应用。 其次,文件操作是C语言中的一个重要部分,本书会介绍如何打开、读写和关闭文件,以及错误处理机制。读者还...
5. **结构体与联合体**:结构体允许将不同类型的变量组合成一个整体,联合体则是在同一内存空间内存储不同类型数据的一种方式。 6. **文件操作**:C语言提供了标准I/O库,可以进行文件的读写操作,如fopen()打开...
在编程世界里,C语言以其高效、灵活的特点深受程序员喜爱,而指针是C语言中的一个核心概念,它使得程序能够直接操作内存地址,从而实现更底层的数据操作和控制。本篇文章将深入探讨C语言中的指针,揭示其独特魅力和...
在C语言中,变量在内存中都有一个特定的地址,可以通过这个地址来存取变量的值。例如,当声明一个整型变量`int num`并为其分配内存时,系统会为`num`分配两个字节的存储空间,并赋予其起始地址,比如3000。通过`&num...
- 局部与全局变量:理解作用域规则,以及静态与自动变量的区别。 8. 输入/输出: - 标准输入输出:使用scanf, printf进行基本的输入输出操作。 - 文件操作:掌握fopen, fclose, fread, fwrite等文件操作函数。 ...
### 使用C语言编程时变量内存分配 在C语言编程中,理解变量在内存中的存储方式对于提高代码效率、避免潜在的内存泄漏问题至关重要。本文将详细介绍C语言中不同类型的变量在内存中的分配机制,并通过一个具体的示例...
- 变量与数据类型:讲解了C语言中的基本数据类型,如整型、浮点型、字符型等,以及变量的声明和初始化。 - 运算符与表达式:涵盖算术运算符、比较运算符、逻辑运算符、赋值运算符等,以及它们在表达式中的应用。 ...
- 变量与数据类型:了解C语言中的基本数据类型,如int、float、char等,以及它们的存储大小和取值范围。 - 运算符与表达式:学习各种运算符(算术、关系、逻辑、位操作)的用法,并能正确计算表达式。 - 控制结构...
在变量和数据类型这一部分,你将学习如何声明、初始化和使用不同类型的变量,以及它们在内存中的存储方式。运算符章节则会涵盖基本的数学运算以及如何使用比较和逻辑运算来测试条件。 控制流程包括条件语句(if-...
### C语言入门:堆与栈的区别 在C语言的学习过程中,理解堆(Heap)与栈(Stack)的概念及其区别是非常重要的。本文将详细介绍这两种数据结构的特点、用途以及它们之间的主要区别,帮助初学者更好地掌握C语言中的...
指针在C语言中扮演着至关重要的角色,因为它允许直接操作内存地址,提供了高效的数据操作和强大的功能。 首先,我们需要理解指针的基本概念。指针是一个特殊的变量,其值是内存地址,即存储其他变量位置的数值。在...
在C语言的世界里,中级阶段的学习是对基础知识的巩固与深入理解。"C语言中级-1C语言回顾"这个主题旨在帮助我们重温C语言的核心概念,为后续的高级学习打下坚实的基础。C语言,作为一门强大的系统编程语言,被广泛...