C语言第 2 天学习笔记:从数据类型到内存存储的底层之旅

发布于:2025-07-23 ⋅ 阅读:(23) ⋅ 点赞:(0)

C语言第02天学习笔记

内容提要

  • 变量
  • 基本数据类型
  • 常量
  • 标识符
  • 各类数据在内存中的存储形式

数据类型

C语言的数据类型可分为基本类型、构造类型、指针类型和空类型。

基本类型(C语言内置)

整型
  • 短整型:short(2字节)
  • 基本整型:int(4字节)
  • 长整型:long(32位系统4字节/64位系统8字节)
  • 长长整型:long long(8字节,C99新增)
浮点型
  • 单精度型:float(4字节)
  • 双精度型:double(8字节)
  • 长双精度型:long double(如GCC通常是16字节,MSVC可能是8字节),取决于编译器。
字符型

char(1字节),C语言中1字节 = 1字符,因为C语言没有字节对应的类型,所以一般用char表示字节。

构造类型(C语言提供了构建语法,由程序员自己创建类型)

  • 结构体:struct
  • 共用体/联合体:union
  • 枚举:enum

指针类型

空类型

void

常量

定义

程序运行过程中值不变的量。

存储位置

常量存储在数据段(字符串常量)或代码段,具体由编译器来决定。变量默认存储在栈内存,但静态变量和全局变量存储在数据段。(后续深入)

常量的分类

  • 整型常量:十进制整型常量、八进制整型常量、十六进制整型常量
  • 浮点型常量:十进制表示法、指数表示法
  • 字符型常量
  • 字符串常量
  • 符号常量:宏定义

变量

概念

  • 定义:在程序运行过程中值可变的量,称之为变量。
  • 变量代表内存中(栈内存)具有特定属性的一个存储单元,它是用来存储数据的,也就是存放变量的值。
  • 变量应该有一个名字,以便于通过名字访问变量。
    在这里插入图片描述

格式

数据类型 变量名列表;

举例(demo01.c)

#include <stdio.h>

int main(int argc,char *argv[])
{
    // 1. 声明变量并初始化
    // 解释:向内存申请一块存储空间,并给这个空间添加一个初始数据
    // 命名:变量名就是标识符的一种,命名规则:以字母或者下划线开头,只能包含数字、字母、下划线,举例:set_user
    // 演示变量名的命名:_int,num2
    int age = 21; // 注意:= 不是关系运算符等于,这里称作赋值运算符,意思是将右边的常量21赋值给左边的变量。顺序:由右到左
    
    // 2. 先声明,再赋值
    int count;
    count = 10;
    
    // 3. 初始化和赋值并行
    int number = 12;
    printf("%d\n", number); // 12 %d:以十进制int的方式格式化输出
    number = 22; // 此时会覆盖掉number原本的值
    printf("%d\n", number); // 22
    
    // 4. 我们可以为多个变量定义同一类型,多个变量之间使用逗号分隔
    int a, b = 10, c; // 此时我们定义了3个变量,只有b初始化了,其他两个变量未初始化
    
    // 访问未初始化的变量?
    // 访问一个未初始化的变量不会报错,但是不建议访问,因为此时变量空间中的数据是系统分配的随机值。
    printf("%d,%d,%d\n",a,b,c);
    
    return 0;
}

基本类型:(整型、浮点型、字符型)我们创建变量的同时,在内存中开辟对应的内存空间。

命名规范

  • 以字母或者下划线开头,后面跟字母、数字、下划线。举例:_int, __int, number, num1
  • 不能与关键字(如:if、int、float等)或者预定义标识符(如:printf、main等)重名。

变量名、变量值、变量所占存储单元之间的关系

变量名是变量首地址对应的内存空间(存储单元)的标识,变量值存储在该内存空间中。
在这里插入图片描述

标识符

定义

用来表示对象名字的有效字符。对象变量、常量、函数、数组、构造类型等。也就是标识符是这些对象的名字。

构成

C语言规定的标识符只能由字母、数字、下划线三种字符构成,且只能以下划线或者字母开头。如:_int, num。

大小写敏感性

编译系统对字母的大小写敏感(区分大小写)。变量名和函数名一般用小写字母+下划线,常量名和枚举名一般用大写字母+下划线,举例:

  • 变量:set_count(setCount在C语言也支持,但是不推荐)
  • 函数:set_count()(setCount()在C语言也支持)
  • 常量、枚举:SET_COUNT

C语言中的3类标识符

  1. 关键字:有32个,系统有特定的含义和用途,不能用作自定义标识符:
    auto、break、case、char、const、continue、default、do、double、else、enum、extern、float、for、goto、if、int、long、register、return、short、signed、sizeof、static、struct、switch、typedef、union、unsigned、void、volatile、while
  2. 系统预定义的标识符:如系统提供的函数名(如printf、scanf等)以及预处理指令(如include、define等)。C语言中有12个预处理指令:define、endif、elif、error、line、include、ifdef、ifnodef、pargma、undef、if、else。注意:以上预处理指令使用的时候,在前面需添加#,如#include。
  3. 用户标识符:用户定义的标识符,用来给变量、自定义函数、符号常量、数组、构造类型、文件等命名。

小贴士

在C语言中,要求对所用到的变量,在使用前必须强制定义,先定义,后使用。

基本类型变量的定义与使用

基本类型(整型、浮点型、字符型)我们创建变量的同时,在内存中开辟对应的内存空间。

同类型变量的定义方式

  1. 一个类型说明语句定义多个变量
    • 优点:简洁
    • 缺点:可读性较差
    int a, b, c, d; // 定义多个同类型变量
    int a1 = 3, b1 = 4, c1 = 5, d1 = 6;
    
  2. 多个类型说明语句定义多个同类型变量
    • 优点:可读性强
    • 缺点:繁琐
    int aa;
    int bb;
    int cc;
    int dd;
    int aa1 = 3;
    int bb1 = 4;
    int cc1 = 5;
    int dd1 = 6;
    

未初始化变量的使用

同类型说明语句定义的变量只是为这些变量分配了内存空间,在未对这些变量赋值前,这些变量中的值是随机的(具体的随机由内存状态来决定)。在C标准中访问未初始化的变量是“未定义行为(UB)”。

案例
#include <stdio.h>

int main(int argc,char *argv[])
{
    int a, b, c, d;
    printf("%d,%d,%d,%d\n",a,b,c,d);// 此时的变量访问,属于未定义行为(UB),不建议这样做
    return 0;
}
// 第一次运行结果:-1543118880,32767,0,0
// 第二次运行结果:243305312,32766,0,0

变量的初始化

  • C语言允许定义变量的同时为变量赋初始值。
  • 在为长整型变量初始化或者赋值时,如果被赋值的数据为基本整型常量,则C编译系统自动将被赋值数据转换为与之相应变量类型一致的数据。
long a = 12L; // 将一个long类型的常量数据12赋值给long类型的变量a,=左右两边类型一致
long b = 12; // 将一个int类型的常量数据12赋值给long类型的变量b,此时=左右两边类型不一致

在这里插入图片描述

  • 由于各种整型变量所占的字节数有限,因此,它们存储的整数有一定的范围。在这里插入图片描述

整型数据

定义

用来存放整型数据的变量,定义一个整型的变量,C编译系统实际是在内存中分配了能够存储一个整型数据的存储空间,并用变量名来标识这个空间,对该空间的使用可以通过变量名来访问。

查看变量存储空间大小

如果不知道所用的C编译系统对变量分配的存储空间的大小,可以通过sizeof运算符查询,如:

int a = 10;
printf("%d,%d\n",sizeof(int), sizeof(a)); // 4,4 sizeof返回的大小是以字节为单位,返回类型long unsigned int

整型数据在内存中的存储形式

数据在内存中是以二进制形式存放,整型数据在内存中是以补码的形式表示的。使用补码主要是为了统一加减法运算,使CPU可以使用同一套加法电路处理所有整数运算(包括正数和负数),同时消除了+0和-0的歧义,简化硬件设计。

  • 正数的补码和原码(该数的二进制形式)相同,三码(原码、反码、补码)唯一。
  • 负数的补码是将该数绝对值的二进制形式,针对数据位按位取反+1(反码+1为补码)。
示例

在这里插入图片描述

内存数据的读写

① 向内存存数据(二进制形式):程序原始数据 → 二进制原码 → 二进制反码 → 二进制补码
② 从内存取数据(二进制形式):二进制补码 → 二进制反码 → 二进制原码 → 程序原始数据

案例

整型变量的分类使用
#include <stdio.h>
int main(int argc,char *argv[])
{
    // 定义有符号整型变量,可以存放正数、0、负数,默认就是有符号数
    int a,b,c,d; // 等价于 signed int a,b,c,d;
    
    // 定义无符号整型变量,可以存放正数、0,不能存放负数,必须添加关键字unsigned
    unsigned int u;
    
    // 赋值
    a = 12;
    b = -24;
    u = 10;
    c = a + u, d = b + u;
    printf("a+u=%d,b+u=%d\n",c,d); // a+u=22,b+u=-14
    
    // 注意:计算机硬件支持加法运算,不支持减法运算,程序中的减法运算,实际上是有负数参与的加法运算,比如5-2实际上5+(-2)
    
    return 0;
}

有符号和无符号数在内存中的存储形式(以char类型举例)

类型 分类 二进制范围 十进制范围 备注
有符号 正数(原码) 00000000-01111111 0至127 最高位0表示正
正数(补码) 00000000-01111111 0至127 实际计算机使用方式
负数(原码) 10000001-11111111 -1至-127 最高位1表示负
负数(补码) 10000000-11111111 -128至-1 -128是特殊表示
无符号 正数 00000000-11111111 0至255 所有位表示数值
  • 有符号char的范围:-128 ~ 127
  • 无符号char的范围:0 ~ 255

浮点型数据

定义

用来表达实数(小数)的数据类型。

浮点型变量的分类

  • 单精度浮点型(float):在64位系统中尺寸是4字节,精确到小数位6位,格式化符号%f
  • 双精度浮点型(double):在64位系统中尺寸是8字节,精确到小数位15~16位,格式化符号%lf
  • 长双精度浮点型(long double):在Linux下64位尺寸是16字节。
示例
float f1 = 12.25f; // 单精度
double f2 = 12.5; // 双精度
long double f3; // 长双精度

浮点型数据在内存中的存储形式

浮点型数据在内存中按照指数形式(IEEE 754标准)存放。系统将一个浮点型数分成尾数部分和指数部分,分别存放。

类别 字节数 符号位 指数位(指数部分) 尾数位(小数部分) 指数偏移量
单精度浮点数 4 1位[31] 8位[30~23] 23位[22~00] 127
双精度浮点数 8 1位[63] 11位[62~52] 52位[51~00] 1023

float内存示意图:
在这里插入图片描述

案例:27.5f在内存中的存放形式
  • 27.5f的二进制为11011.1
  • 转换为指数形式:11011.1→1.10111*2⁴
  • 指数:4 + 127 = 131,转换为二进制:10000011
  • 尾数:10111,需要补够23位,右侧补0:10111000000000000000000
  • 最终表示:符号位(1位)、指数位(8位)、尾数位(23位)组成的二进制数。

浮点型数据转二进制方法

  1. 整数部分:采用辗转除2直到商为0为止。
  2. 小数部分:采用辗转乘2直到整数位出现1,小数位出现0为止,但是有时候会出现乘不尽的情况,此时需根据内存大小来决定保留位数。

科学计数法(指数法)

C语言中一般浮点数有两种表示形式:

  • 十进制形式:指的是数字必须以整数形式+小数形式组成,比如10.0、3.14等。
  • 指数形式(科学记数法):以字母e或者E来表示指数,并且要求字母e或者E的前面必须有数字,字母e或者E的后面必须为整数。如-3.14E-2、2E-3、0.3E4。
错误示例
  • E3:错误,因为E的前面没有数据
  • 3.1e5.6:错误,因为E的后面必须是整数

字符型数据

概念

字符型变量用来存放字符常量。

定义

char 变量列表;
示例(demo04.c)
#include <stdio.h>

int main(int argc,char *argv[])
{
    char c1,c2;
    
    c1 = 'A';
    c2 = 'B';
    
    printf("c1=%c\n",c1);//  %c是字符的格式化符号
    printf("c1=%c\n",c2);
    printf("c1=%d\n",c1);
    printf("c2=%d\n",c2);
    
    
    return 0;
}

运行结果:

c1=A
c1=B
c1=65
c2=66

存储特点

一个字符变量只能存放一个字符。C编译系统规定以一个字节的存储空间来存放一个字符,因此,一个字符变量在内存中的大小是1个字节(1字节=1字符)。

字符数据在内存中的存储形式

将一个字符常量存入一个字符变量,实际上是将该字符对应的ASCII码存入内存单元。

范例

char c1 = ‘a’, c2 = ‘b’;'a’的ASCII为97,'b’的ASCII码为98,它们在内存中的存储形式为97和98对应的二进制形式:01100001和01100010。

字符型数据和整型数据的通用性

在内存中字符数据的存储形式与整型数据类似,这就使得字符型数据和整型数据之间可以通用,也就是1个字符数据既可以以字符形式输出,也可以以整数形式输出。

  • 以字符形式输出时,编译系统将内存单元中的ASCII码转换为相应的字符,然后输出。
  • 以整型输出时,直接将ASCII码作为整数输出。

因此,可以对字符数据进行算数运算,这时相当于对其ASCII码进行算数运算。

案例:给字符变量赋整数值(demo03.c)
#include <stdio.h>

int main(int argc,char *argv[])
{
    char c1,c2;
    c1 = 97;// char既能赋值字符,也能赋值整数(ASCII码)
    c2 = 98;
    
    printf("%c %c \n",c1,c2);// a b, 以字符形式输出
    printf("%d %d \n",c1,c2);// 97 98, 以整数形式输出
    
    return 0;
}

说明:char类型可以赋值为字符,也可以赋值为整数(char a = 128,显示的结果范围:-128~127),演示案例:
在这里插入图片描述
c1在内存的存储形式以及不同形式的输出,如下图所示:
在这里插入图片描述

案例:大小写字母转换(demo06.c)
#include <stdio.h>

int main(int argc,char *argv[])
{
    char c1,c2;
    
    c1 = 'm';
    c2 = 'Y';
    
    printf("转换前:%c,%c\n",c1,c2);
    
    // 转换
    c1 = c1 - 32;
    c2 = c2 + 32;
    
    printf("转换后:%c,%c\n",c1,c2);
    
    
    return 0;
}
总结

变量、数据类型、常量、标识符以及各类数据在内存中的存储形式等内容的学习,我们对 C 语言的基础要素有了更清晰的认识。这些知识是后续深入学习 C 语言编程的重要基石,希望大家能扎实掌握,为应对更复杂的编程问题和完成章节作业打下坚实基础。
注:后续笔记将围绕C语言知识展开,建议每日实操时长不少于3小时


网站公告

今日签到

点亮在社区的每一天
去签到