2.1 数据类型、关键字、常量与变量深度解析

目录

1 数据类型分类

2 关键字

3 常量

4 变量

4.1 变量名

4.2 变量的命名规范

4.3 大小驼峰命名法

5 整型数据

5.1 符号常量(宏定义)

5.2 整型变量(int等)

5.3 sizeof 运算符

6 浮点型数据

6.1 浮点型常量(小数、指数)

6.2 浮点型变量(float、double)

7 字符型数据

7.1 字符型常量

7.2 转义字符

7.3 字符型变量与ASCII码

8 字符串型常量


1 数据类型分类

裁缝做衣服时需要用到化纤、纯棉、丝绸等不同类型的布料,那么程序员在编写程序时需要用到哪些数据类型呢?数据类型的分类如下图所示:

 除此之外,还有枚举类型(Enumeration Types)、联合类型(Union Types)、类型定义(Type Definitions)等。


2 关键字

C 语言中有许多关键字,在后面的章节中将详细介绍这些关键字 (不用去记),这里罗列它们的目的是让大家知道 C 语言中的关键字有哪些, 避免命名变量时与关键字重名 (完全不用担心,CLion 开发环境重名后会自动提醒大家的)。 下表列出了 C 语言中的关键字:

关键字分类关键字
数据类型关键字void, char, short, int, float, double, long, signed, unsigned, struct, union, enum
控制流程关键字break, continue, return, if, else, switch, do, while, for, goto
存储类关键字auto, extern, register, static
修饰符关键字const, volatile
其他关键字case, default, sizeof, typedef
C99新增关键字inline, restrict, _Bool, _Complex, _Imaginary
C11新增关键字_Alignas, _Alignof, _Atomic, _Generic, _Noreturn, _Static_assert, _Thread_local

C 语言(包括 C99 和 C11 标准)中的关键字总数是:

32(传统 C 语言) + 5( C99 新增) + 7( C11 新增) = 44个

但请注意,并不是所有的 C 语言编译器或环境都默认支持 C99 和 C11 的所有特性,因此在某些情况下,可能无法直接使用这些新增的关键字。此外,_Bool_Complex 和 _Imaginary 这些关键字通常是通过 <stdbool.h><complex.h> 等头文件提供的宏或类型定义来使用的,而不是直接作为关键字使用。在这种情况下,我们可能会将它们视为与关键字相关的特性,而不是严格意义上的关键字。


3 常量

常量是指在程序运行过程中,其值不发生变化的量。

常量又可分为整型、实型(也称浮点型)、字符型和字符串型,如下所示:

整型:100, 125, -100, 0
实型(浮点型):3.14, 0.125, -3.789
字符型:'a', 'B', '2'
字符串型:"a”, "ab", "1c34", "你好,世界!", "一战成硕"

整型常量、实型常量、字符型常量和字符串型常量都是在编译时可以直接编入代码段的常量。这些常量在程序编写时就已经确定了它们的值

  • 整型常量:如100、-5等,它们的值在编译时就已确定,并且直接用于程序的计算或比较中。

  • 实型常量(浮点型常量):如3.14、-0.001等,它们的值同样在编译时确定,并用于需要浮点运算的场合。需要注意的是,由于浮点数的表示方式,它们可能会受到精度限制。

  • 字符型常量:如'a'、'3' 等,它们表示单个字符,在编译时其ASCII码值或对应的字符编码值会被确定,并用于字符操作或字符串操作中。

  • 字符串型常量:如"Hello, world!"、""(空字符串)等,它们是由零个或多个字符组成的序列,以空字符'\0'结尾。字符串常量在编译时会被存储在程序的某个部分(通常是数据段),并在需要时通过指针或数组名进行访问。

考研不会考汉字的字符串常量(CLion需要设置编码格式),无需掌握。


4 变量

变量代表内存中具有特定属性的一个存储单元,它用来存放数据,即变量的值。这些值在程序的执行过程中是可以改变的。

4.1 变量名

变量名实际上以一个名字代表一个对应的存储单元地址。编译、链接程序时,由编译系统为每个变量名分配对应的内存地址(就是空间)。

变量名本身并不直接存储在内存中,存储在内存中的是变量的值以及与之相关联的元数据(如类型信息、作用域等)。

变量名是在编译过程中由编译器处理的,用于在源代码中引用变量。一旦程序被编译成机器代码,变量名就不再需要了,取而代之的是变量的内存地址

从变量中取值实际上是通过变量名找到内存中存储单元的地址,并从该存储单元中读取数据。

4.2 变量的命名规范

C 语言规定标识符只能由字母、数字和下画线三种字符组成,并且第一个字符必须为字母或下画线(即数字不能开头。例如:

正确的变量命名示例
studentName1:以字母开头,后跟字母和数字的组合,符合C语言的命名规则。
ageOfStudent:清晰表达了变量的用途(学生的年龄),且完全由字母、数字和下划线组成。
_isFirstTime:以下划线开头,用于表示某种特殊含义的变量(如全局变量或成员变量)。
maxScore:简短且描述性强,用于表示最高分。
total_sales:使用下划线分隔单词,提高了变量的可读性。

错误的变量命名示例
1stYear:以数字开头,违反了C语言的命名规则。
my-age:包含连字符,不是有效的C语言标识符。
temp temp:包含空格,不是有效的C语言标识符。
M.DJohn:包含点,不是有效的C语言标识符。
¥123:包含¥,不是有效的C语言标识符。
a>b:不是有效的C语言标识符。

不建议的变量命名示例
class:虽然不是C语言的关键字,但它是许多编程语言中的关键字,用作变量名可能会引起混淆。
intScore:尽管这里intScore本身是一个合法的标识符,但它看起来像是一个类型声明(int Score),这可能会导致代码阅读者的混淆。在命名变量时,应避免使用与类型名相似的名称。

大小写敏感性:C 语言的编译系统严格区分大写字母和小写字母,这意味着 myVariable 和  MyVariable 会被视为两个不同的变量。

先定义后使用:在 C 语言中,所有变量在使用之前必须先进行定义。这是编程的基本规则之一,有助于编译器理解变量的类型和作用域。变量定义告诉编译器变量的类型,并为其分配存储空间。

见名知意:选择变量名和其他标识符时,应尽可能遵循“见名知意”的原则。这意味着变量名应该能够直观反映其用途或内容,使用具有含义的英文单词(或其合理的缩写)作为标识符,以提高代码的可读性和可维护性。

避免与关键字同名:在选择变量名时,必须避免与上文提到的关键字重名,否则会导致编译错误。

4.3 大小驼峰命名法

大驼峰命名法(UpperCamelCase)每个单词的首字母都大写,不使用下划线连接单词。例如,MyVariable、ThisIsAnExample。在C语言中,这种风格可能不太常见用于变量命名,但可能会用于常量、宏定义或全局变量的命名,以区别于局部变量和函数参数。

小驼峰命名法(lowerCamelCase)第一个单词的首字母小写,之后每个单词的首字母大写,不使用下划线连接单词。例如,myVariable、thisIsAnExample。在C语言中,这种风格更常用于变量命名,因为它既清晰又易于阅读。

需要注意的是,C 语言中的宏定义(使用 #define 指令)和枚举常量(使用 enum 关键字)通常使用全大写字母和下划线(如 MAX_VALUE、ERROR_CODE)来命名,以区别于变量和函数。


5 整型数据

5.1 符号常量(宏定义)

在 C 语言中,最常用的定义整型符号常量的方法是使用 #define 预处理指令宏定义是在预处理阶段进行的文本替换。这种方法允许你在代码中为某个整型值定义一个易于记忆和理解的名称(即标识符),然后在整个程序中通过该名称来引用这个值。

#include <stdio.h>  
  
// 定义一个整型符号常量  
// 注意这后面不要加分号
#define MAX_VALUE 100  
  
int main() {  
    int array[MAX_VALUE]; // 使用符号常量定义数组大小  
    printf("The array size is %d\n", MAX_VALUE);  
    return 0;  
}

在这个例子中,MAX_VALUE 是一个整型符号常量,它在预处理阶段被替换为100。

C语言中整型数据中的“符号常量”除了通过宏定义还可以通过枚举或 const修饰符来定义的。

注意事项

#include <stdio.h>

#define PI 3+2

int main() {
    int i = PI * 2;
    printf("i=%d\n", i);//i=7
    return 0;
}

最终的输出结果是7,原因是符号常量 PI 是直接替换的效果,因此不可以写PI=8。

由于C语言中的宏替换是纯粹的文本替换,不考虑运算符的优先级或类型,所以 PI 会被直接替换为 3+2。但是,当这个表达式被用于计算 i 的值时,它会遵循C语言的运算符优先级规则,即乘法(*)的优先级高于加法(+)。因此,表达式 3+2 * 2 会被计算为 3 + (2 * 2),结果是 7。

5.2 整型变量(int等)

下表列出了关于标准整数类型的存储大小和值范围的细节:

1字节(Byte)== 8位(Bit)

类型存储大小值范围(次方表示)值范围
char1 字节-2^7 到 2^7-1-128 到 127
unsigned char1 字节0 到 2^80 到 255
short2 字节-2^15 到 2^15-1-32,768 到 32,767
unsigned short2 字节0 到 2^160 到 65,535
int4 字节-2^31 到 2^31-1-2,147,483,648 到 2,147,483,647
unsigned int4 字节0 到 2^320 到 4,294,967,295
long4 字节-2^31 到 2^31-1-2,147,483,648 到 2,147,483,647
unsigned long4 字节0 到 2^320 到 4,294,967,295

这里掌握 int 足以应对考研初试,后面高级阶段会详细讲解不同类型整型变量,没有时间的同学可以不掌握高级,变量i是4个字节(考研)

5.3 sizeof 运算符

注意,各种类型的存储大小与系统位数有关,但目前通用的以64位系统为主。

以下列出了32位系统与64位系统的存储大小的差别(windows 32位系统与64位系统的存储大小相同):

为了得到某个类型或某个变量在特定平台上的准确大小,可以使用 sizeof 运算符。表达式 sizeof(type) 得到对象或类型的存储字节大小。下面的实例演示了获取 int 类型的大小:

sizeof 的返回类型是 size_t,这是一个无符号整数类型,其大小足以表示对象在内存中占用的字节数。

对于 size_t 类型的变量或表达式,最好应该使用 %zu 格式说明符,因为这是 C99 及以后标准中专门为 size_t 设计的格式说明符。

#include <stdio.h>

int main() {
    int i = 10;
    printf("int 存储大小: %lu bytes\n", sizeof(int));
    printf("int 存储大小: %llu bytes\n", sizeof(int));
    printf("int 存储大小: %zu bytes\n", sizeof(int)); //推荐%zu
    printf("int类型变量i 存储大小: %zu bytes\n", sizeof(i));//推荐%zu
    return 0;
}

输出结果:


6 浮点型数据

6.1 浮点型常量(小数、指数)

表示浮点型常量的形式有两种,如下表所示,其中 e 代表10的幂次,幂次可正可负

基数部分:基数部分(也称为尾数或有效数字)可以是整数或小数,但不能为空(即至少有一位数字)。

指数部分:指数部分由一个e或E(不区分大小写)字符后跟一个整数(表示幂次)组成。这个整数可以是正数、负数或零。如果是正数,则可以不写加号,直接写数字;如果是负数,则必须写减号。

总结:字母e(或E)之前必须有数字,且e后面的指数必须为整数。

正确示例:

  • 1e-3 表示 1×10的-3次方,即 0.001
  • 1.8e-3 表示 1.8×10的−3次方
  • -123e-6 表示 −123×10的−6次方
  • -.1e-3 表示 −0.1×10的−3次方,也可以写成 -1e-4

错误示例及原因:

  • e3:错误,因为 e 前没有数字。
  • 2.1e3.5:错误,因为 e 后面的指数的是小数。
  • .e3:错误,因为没有有效的数字在 e 之前。
  • e:错误,没有有效的基数和指数。
#include <stdio.h>

int main() {
    float f1 = 3e-3;
    float f2 = 3e-3f;//f是float类型后缀
    float f3 = 3e+3f;
    float f4 = 3e3f;//+可以省略
    float f5 = 3e0f;//+可以省略
    printf("3e-3: %f1\n", f1);
    printf("3e-3f: %f2\n", f2);
    printf("3e+3f: %f3\n", f3);
    printf("3e3f: %f4\n", f4);
    printf("3e0f: %f5\n", f5);

    return 0;
}

输出结果:

6.2 浮点型变量(float、double)

下表列出了关于标准浮点类型的存储大小、值范围和精度的细节:

类型存储大小值范围精度
float4 字节1.2E-38 到 3.4E+386 位有效位
double8 字节2.3E-308 到 1.7E+30815 位有效位
long double16 字节3.4E-4932 到 1.1E+493219 位有效位

C标准只定义了有符号的浮点数类型,这些类型可以表示正数、负数和零。浮点数的符号是通过IEEE 754标准(或其变种)中的一位(称为符号位)来表示的。浮点数(包括float、double和long double)没有直接的“无符号”版本,尝试声明一个 unsigned float 或 unsigned double 类型的变量在C语言中是无效的,会导致编译错误,如下所示。

头文件 float.h 定义了宏,在程序中可以使用这些值和其他有关实数二进制表示的细节。下面的实例将输出浮点类型占用的存储空间以及它的范围值:

#include <stdio.h>
#include <float.h>

int main()
{
    printf("float 存储最大字节数 : %zu \n", sizeof(float));
    printf("float 最小值: %E\n", FLT_MIN );
    printf("float 最大值: %E\n", FLT_MAX );
    printf("精度值: %d\n", FLT_DIG );

    return 0;
}

输出结果: 

在C语言中,当你声明一个浮点数常量时,可以在其后面加上 f 或 F 后缀来明确指定它是一个float类型的常量,而不是默认的double类型。这是因为C语言标准规定,没有后缀的浮点数字面量默认是double类型的。

 float myFloat3 = 3.14; // 大多数编译器都会自动进行从double到float的隐式类型转换(尽管这可能会导致精度损失)

#include <stdio.h>

int main() {
    float myFloat1 = 3.14f; // 使用f后缀明确指定为float类型
    float myFloat2 = 3.14F; // 使用F后缀明确指定为float类型
    float myFloat3 = 3.14; // 大多数编译器都会自动进行从double到float的隐式类型转换(尽管这可能会导致精度损失)
    double myDouble = 3.14; // 没有后缀,默认为double类型

    printf("myFloat1: %f\n", myFloat1);  // float类型最好使用 %f格式输出
    printf("myFloat2: %lf\n", myFloat2); // 如果使用 %lf有的编辑器会报错
    printf("myFloat3: %f\n", myFloat3); //

    printf("myDouble: %f\n", myDouble); // double类型可以使用 %f格式输出
    printf("myDouble: %lf\n", myDouble);// 但最好使用 %lf格式输出

    return 0;
}

不加后缀 f 且定义为 float 类型,CLion会给出相提示:


7 字符型数据

7.1 字符型常量

单引号括起来的一个字符是字符型常量,且只能包含一个字符

例如,'a'、'A'、'1'、' '(单引号里面有一个空格)是正确的字符型常量,而 ''(两个单引号之间没有字符)、'abc' 、 "a"、""是错误的字符型常量。

字符型常量可以是普通的字符(如字母、数字、标点符号等),也可以是转义字符。

7.2 转义字符

转义字符描述
\反斜杠字符本身
\'单引号字符
\"双引号字符(在字符串常量中常用,但在字符常量中不常见)
\n换行符
\t水平制表符(通常用于在输出中创建制表位)
\r回车符,仅仅是将打印头重置到当前行的起始位置
\b

退格符(将光标向左移动一个位置,但不删除字符)

当退格符被发送到终端或文本编辑器时,它可能会导致光标左侧的字符被覆盖或隐藏,但这并不等同于删除字符。实际上,那些字符仍然存在于底层的数据结构中,只是不再在屏幕上可见而已。

\f换页符(在打印输出中通常不产生可见效果,但在某些设备或程序中可能用于分页)
\a响铃(或警报)字符(通常会产生一个可听见的铃声或系统提示音)
#include <stdio.h>

int main() {
    // 反斜杠字符本身
    printf("\\");

    // 单引号字符
    printf("It's a test. Or using escape sequence: It\'s a test.\n");

    // 双引号字符(在字符串中使用)
    printf("\"Hello, World!\"");

    // 换行符
    printf("Hello,\nWorld!\n");

    // 水平制表符
    printf("Name\tAge\nJohn\t30\n");

    // 回车符(注意:在大多数现代终端中,单独使用可能不会产生预期效果)
    // 这里为了演示,我们结合换行符使用
    printf("Hello\rWorld!\n"); // 可能在某些环境中只显示"World!"

    // 退格符
    printf("Hello\bWorld!"); // 可能显示为"HellWorld!"(取决于终端或环境)

    // 换页符(在大多数终端中不会产生可见效果)
    printf("Page 1\fPage 2\n"); // 这里只是为了展示写法

    // 响铃(或警报)字符(可能会产生声音或系统提示)
    printf("\a");


    return 0;
}

 输出结果:

7.3 字符型变量与ASCII码

字符型变量使用关键字 char 进行定义,一个字符型变量占用1字节大小的空间。

一个字符常量存放到一个字符型变量中时,实际上并不是把该字符的字型放到内存中,而是把该字符的ASCII码值放到存储单元中,每个字符的ASCII码值如下图所示。

常用的ASCII码:

        字符            十进制

          0                  48

          A                  65

          a                  97

打印字符型变量时,如果以字符形式打印,那么计算机会到 ASCII 码表中查找字符型变量的 ASCII码值,查到对应的字符后会显示对应的字符,如下图所示。这样,字符型数据和整型数据之间就可以通用。

字符型数据既可以以字符形式输出,又可以以整数形式输出,还可以通过运算获取想要的各种字符,对于字符型变量,无论是赋ASCII码值还是赋字符,使用%c打印输出时得到的都是字符,使用%d打印输出时得到的都是ASCII码值

#include <stdio.h>

int main() {
    // 声明并初始化字符变量
    char ch1 = 'A';
    char ch2;
    char ch3;
    char ch4;

    // 以字符形式输出ch1
    printf("字符形式输出ch1: %c\n", ch1);// A
    // 以整数形式输出ch1(即其ASCII码值)
    printf("整数形式输出ch1: %d\n", ch1);// 65

    // 通过运算获取新的字符:ch1 + 1
    ch2 = ch1 + 1; //ch1 首先被隐式地转换成整数(即它的ASCII码值65),然后加上1,结果是66。
    printf("通过运算获取的新字符(ch1 + 1): %c\n", ch2);// B
    // 大写+32变成小写
    ch2 = ch1 + 32; //ch1 首先被隐式地转换成整数(即它的ASCII码值65),然后加上32,结果是97。
    printf("通过运算获取的新字符(ch1 + 32): %c\n", ch2);// a
    // 小写-32变成大写
    ch3 = ch2 - 32; //ch2 首先被隐式地转换成整数(即它的ASCII码值97),然后减去32,结果是65。
    printf("通过运算获取的新字符(ch2 - 32): %c\n", ch3);// A

    // 通过字符运算获取数字字符
    ch4 = '0' + 5; // '0'的ASCII码是48,所以结果是'5'
    printf("通过运算获取的数字字符('0' + 5): %c\n", ch4);// 5
    // 显示ch3的ASCII码值
    printf("数字字符ch3的ASCII码值: %d\n", ch4);// 53

    return 0;
}

8 字符串型常量

字符串型常量是由一对双引号括起来的字符序列。例如 "How do you do"、"CHINA"、"a"和"$123.45"是合法的字符串型常量,我们可用语句 printf("How do you do.")输出一个字符串。但要注意的是, 'a'是字符型常量,而"a"是字符串型常量,二者是不同的

例如,如果先用语句char ch1定义字符型变量ch1,后令ch1="thank",那么这样的赋值是非法的,如下图所示。原因是不可以将字符串型常量赋值给字符型变量

C语言中没有定义字符串型变量的关键字,后续介绍字符数组时我们将详细讲解如何存放字符串。

C语言规定,在每个字符串型常量的结尾加一个字符串结束标志,以便系统据此判断字符串是否结束。C语言规定以字符'\0'作为字符串结束标志

例如,字符串型常量"CHINA"在内存中的存储结果如下图所示,它占用的内存单元不是5个字符,而是6个字符,即大小为6字节,最后一个字符为'\0'。然而,在输出时不输出'\0',因为'\0'无法显示

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thanks_ks

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值