首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >数据与关键字、标识符

数据与关键字、标识符

作者头像
Nullmian
发布2025-12-24 15:04:49
发布2025-12-24 15:04:49
30
举报

一、 常量的意义

意义:防止程序运行过程中被意外修改,增强代码的稳定性、安全性和可读性。

  • 稳定性:确保关键值(如圆周率π、配置参数)不变。
  • 安全性:避免在复杂逻辑中误修改重要数据。
  • 可读性:给魔法数字起一个有意义的名字,如 #define MAX_SIZE 100
  • 维护性:修改常量值只需修改一处定义,提高代码可维护性

二、 全局与局部变量的本质区别

全局变量与局部变量的区别,表面上是声明/定义的位置不同(函数内/外),但其本质是存储位置的不同,这直接导致了它们作用域生命周期的天差地别。


三、 数据的存储位置

程序运行时,数据主要存储在以下几个内存区域:

  1. 栈区 (Stack)
  • 存储内容:局部变量、函数参数、函数调用地址等。
  • 特点:由系统自动分配和释放,效率高,但空间有限。
  • 行为:函数执行时,局部变量在栈上创建;函数结束时,它们被自动销毁。
  1. 堆区 (Heap)
  • 存储内容:通过动态内存分配函数(malloccalloc, realloc)申请的空间。
  • 特点:空间巨大,分配和释放需由程序员手动控制(使用 free)。
  • 行为:如果只申请不释放,会导致内存泄漏。
  1. 静态区/数据段 (Static Storage/Data Segment)
  • 存储内容:全局变量、static 静态变量、字符串常量等。
  • 特点:在程序开始时分配,程序结束时才释放。默认初始化为0。

四、 作用域 vs. 生命周期

这是两个极易混淆但至关重要的概念:

  • 作用域 (Scope):指的是变量在代码中的可访问范围。它是一个空间上的概念。
  • 问题:我在第50行写的代码,能访问这个变量吗?
  • 生命周期 (Lifetime):指的是变量在程序运行时的存在时间。它是一个时间上的概念。
  • 问题:函数调用结束后,这个变量占用的内存还在吗?

重要关系

  • 生命周期 覆盖 作用域。一个变量只要在它的生命周期内,并且在它的作用域中,就可以被访问。
  • 一个变量离开了作用域(比如函数返回),并不意味着它的生命周期一定结束(例如 static局部变量)。

学习感悟:讲到这,大多数人肯定感觉很懵,但请先别急,静下心来听完后面的内容,你就豁然开朗了。学习就是这样——“山重水复疑无路,柳暗花明又一村”。


五、 关键字 (KeyWord) 与数据类型 (DataType)

关键字是C语言预先定义的、具有特殊含义的单词,我们不能用它们来命名变量或函数(如 int, if, return)。

数据类型是一种特殊的、用于声明变量和常量的关键字。它决定了:

  1. 数据占用的内存大小(如 int 通常占4字节)。
  2. 数据的解释方式(同样的二进制数,intfloat 解释出来值不同)。
  3. 数据可执行的操作(如 取模运算 "%" 只能用于整型)。

类比:数学中的数分为“常量”、“变量”,又可细分为整数、小数等。C语言的数据类型就是为计算机世界的“数”进行更精细的分类,如整型(int)、字符型(char)、浮点型(float, double)。

注意:不同类型之间可以相互赋值,但可能会发生隐式类型转换,导致精度丢失或值改变(例如,将 float 赋给 int,小数部分会被截断)。


六、 标识符 (Identifier) 与命名规则

标识符就是给变量、函数、常量等起的名字,是我们在编程中的“命名”。

命名规则(必须遵守)

  1. 只能由字母(A-Z, a-z)、数字(0-9)、下划线(_)组成。
  2. 第一个字符必须是字母或下划线,不能是数字。
  3. 不能与C语言的关键字重名。
  4. 区分大小写(ageAge 是两个不同的变量)。

命名规范(良好习惯)

  • 见名知意:int student_age; VS. int a; (差)。
  • 常用风格:
  • 蛇形命名法:student_name (C语言常用)
  • 小驼峰命名法:StudentName
  • 常量通常全大写:#define MAX_SIZE 100

七、 字符与ASCII编码

为了理解字符型(char),必须引入ASCII编码的概念。

  • 本质:计算机中,所有数据都以数字形式存储。字符也不例外。
  • ASCII码规定了一个整数与一个字符的对应关系(例如,整数 65 代表大写字母 'A'
  • 因此,字符型可以看作一种特殊的整型,它可以参与整数运算。

扩展知识

  • 转义字符:以反斜杠\开头,表示特殊字符
    • \n:换行符
    • \t:制表符
    • \\:反斜杠本身
    • \'\":单引号、双引号
    • \0:空字符(字符串结束标志)


八、 sizeofstrlen

  • sizeof
  • 它是一个运算符编译时就确定结果。
  • 功能:计算变量或数据类型在内存中所占的字节数。
  • sizeof(array) 计算整个数组的大小。
  • strlen
  • 它是一个库函数#include <string.h>运行时才计算。
  • 功能:计算字符串的长度,即从起始地址到第一个 '\0'(字符串结束符)之前的字符个数。
  • strlen(string) 不包含结束符 '\0'

关键区别

代码语言:javascript
复制
char str[100] = "Hello";
printf("%zu", sizeof(str)); // 输出 100,计算的是数组的总容量
printf("%zu", strlen(str)); // 输出 5,计算的是字符串的实际长度

九、 常量与变量的定义

1. 常量的定义及初始化
  • 使用 #define 宏定义
代码语言:javascript
复制
#define PI 3.14159   // 注意:末尾没有分号!
#define MAX_N 100
#define GREETING "Hello, World!"
  • 在编译前,预处理器会将代码中所有 PI 直接替换为 3.14159
  • 使用 const 修饰变量
代码语言:javascript
复制
const double pi = 3.14159;
const int max_n = 100;
  • 定义了一个“只读变量”,其值在运行时不能被修改。
2. 变量的定义及初始化
  • 定义:为变量分配内存空间。
代码语言:javascript
复制
int age;        // 定义了一个整型变量age(初值是随机的)
double salary;
  • 初始化:在定义的同时赋予一个初始值。
代码语言:javascript
复制
int count = 0;   // 定义并初始化
char grade = 'A';
  • 赋值操作符 =:表示将等号右边表达式的值存入等号左边变量所标识的内存空间中。
代码语言:javascript
复制
count = 10;      // 将10这个值放入count对应的内存中
grade = 'B';     // 将'B'的ASCII码值放入grade对应的内存中

注意" = " 是赋值,不是数学中的“等于”。数学中的等于是 " == "


十、 格式化输入/输出

C语言通过标准库函数 scanfprintf 进行输入输出,它们通过格式控制字符串来指定数据的类型和格式。

1. 输出函数 printf
代码语言:javascript
复制
printf("格式控制字符串", 输出项列表);
  • 常用格式控制符
  • %d:以十进制输出 int
  • %c:输出 char
  • %f:输出 float/double
  • %lf:输出 double (推荐)
  • %s:输出字符串
  • %p:输出指针地址
  • %zu:输出 sizeof 的返回值类型 (size_t)
  • 示例
代码语言:javascript
复制
int a = 10;
char c = 'X';
double d = 3.14;
printf("a=%d, c=%c, d=%.2f\n", a, c, d);
// 输出:a=10, c=X, d=3.14
2. 输入函数 scanf

scanf是一个不太安全的输入函数,因为它在写入时不会检查该

代码语言:javascript
复制
scanf("格式控制字符串", 变量地址列表);
  • 关键:必须提供变量的地址(使用取地址运算符 &)。
  • 常用格式控制符同上。
  • 示例
代码语言:javascript
复制
int age;
double height;
printf("请输入年龄和身高:");
scanf("%d %lf", &age, &height); // 注意:height是double,用%lf
printf("年龄:%d, 身高:%.2f\n", age, height);
  • 注意scanf 读取字符串时,变量是字符数组名(本身即地址),无需 &
代码语言:javascript
复制
char name[20];
scanf("%s", name); // 正确,name已是地址
// scanf("%s", &name); // 错误,&name写法多余且类型不匹配
补充内容:利用%m.n修饰占位符

在C语言的格式化输入/输出中,%m.n 是极为重要的格式修饰符,它允许我们精确控制输入/输出的格式

基本语法结构

代码语言:javascript
复制
%[flags][width][.precision]specifier

其中:

  • flags:标志字符(如-, +, 0, #等)
  • width:指定最小字段宽度
  • .precision:指定精度(对于不同类型有不同含义)
  • specifier:类型说明符(如d, f, s等)

一、字段宽度 (width) - 控制输出的最小宽度

1. 基本用法
代码语言:javascript
复制
int num = 123;
printf("%5d", num);   // 输出 "  123"(右对齐,宽度5)
printf("%-5d", num);  // 输出 "123  "(左对齐,宽度5)
printf("%05d", num);  // 输出 "00123"(用0填充)
2. 动态指定宽度
代码语言:javascript
复制
int width = 8;
printf("%*d", width, num); // 相当于 %8d

二、精度 (.precision) - 控制输出的精度

1. 浮点数精度控制
代码语言:javascript
复制
double pi = 3.1415926535;
printf("%.2f", pi);    // 输出 "3.14"(保留2位小数)
printf("%8.3f", pi);   // 输出 "   3.142"(宽度8,保留3位小数)
printf("%.0f", pi);    // 输出 "3"(不保留小数)
2. 字符串精度控制
代码语言:javascript
复制
char str[] = "HelloWorld";
printf("%.5s", str);   // 输出 "Hello"(只输出前5个字符)
printf("%10.5s", str); // 输出 "     Hello"(宽度10,只输出5字符)
3. 整数精度控制(最小数字位数)
代码语言:javascript
复制
int num = 42;
printf("%.5d", num);   // 输出 "00042"(至少5位,用0填充)
printf("%5.3d", num);  // 输出 "  042"(宽度5,至少3位)

三、scanf 中的格式控制

1. 基本输入控制
代码语言:javascript
复制
int age;
float height;
char name[50];

// 基本输入
scanf("%d", &age);           // 读取整数
scanf("%f", &height);        // 读取浮点数
scanf("%s", name);           // 读取字符串(不包含空格)

// 同时读取多个值
scanf("%d %f %s", &age, &height, name);
2. 宽度限制 - 防止缓冲区溢出
代码语言:javascript
复制
char city[20];
// 限制最多读取19个字符(留一个位置给'\0')
scanf("%19s", city);

// 对于带有空格的字符串输入
char full_name[50];
scanf(" %49[^\n]", full_name); // 读取一行,最多49个字符
3. 扫描集 (scanset) - 精确控制输入内容
代码语言:javascript
复制
char vowels[10];
// 只接收元音字母
scanf("%[aeiouAEIOU]", vowels);

// 排除某些字符
char no_digits[50];
scanf("%[^0-9]", no_digits); // 读取直到遇到数字

// 结合宽度限制
char limited[10];
scanf("%9[^\\n]", limited); // 最多读取9个非换行符
4. 跳过特定输入
代码语言:javascript
复制
int day, month, year;
// 输入格式: DD-MM-YYYY
scanf("%d-%d-%d", &day, &month, &year);

// 跳过不想要的输入
int important_value;
scanf("%*s %*s %d", &important_value); // 跳过前两个字符串,只读取第三个

五、特殊技巧和注意事项

1. printf 标志组合使用
代码语言:javascript
复制
int num = 123;
printf("%-+10d", num);  // 输出 "+123      "(左对齐,显示正负号)
printf("%#010x", num);  // 输出 "0x0000007b"(显示0x前缀,用0填充)
2. scanf 与 printf 的差异
  • printf 中的 .precision 在 scanf 中不起作用
  • scanf 中的 width 表示最大读取宽度,而不是最小显示宽度
  • scanf 对于字符串输入会自动添加终止符 \0

十一、 自定义数据类型

结构体 (struct)

结构体允许将多个不同类型的数据组合成一个单一的类型。

代码语言:javascript
复制
// 定义结构体类型
struct Student {
    int id;
    char name[50];
    float score;
};

// 声明结构体变量
struct Student s1;
struct Student s2 = {1001, "张三", 95.5};

// 访问结构体成员
s1.id = 1002;
strcpy(s1.name, "李四");
s1.score = 88.5;

// 结构体指针
struct Student *ptr = &s1;
printf("学号:%d\n", ptr->id); // 使用->访问成员
类型重定义 (typedef)

使用 typedef 为现有类型创建别名,简化复杂类型的声明。

代码语言:javascript
复制
// 为基本类型创建别名
typedef long long ll;
typedef long double ld;

// 为结构体创建别名
typedef struct {
    int x;
    int y;
} Point;

// 使用别名
ll count = 10;
Point p1 = {0, 0};

十二、 强制类型转换

强制类型转换允许显式地将一种数据类型转换为另一种类型。

基本语法结构
代码语言:javascript
复制
(目标类型)表达式
使用案例
代码语言:javascript
复制
int a = 10, b = 3;
double result;

// 整数除法
result = a / b;           // 3.0(整数除法)
result = (double)a / b;   // 3.333...(强制转换后为浮点除法)

// 指针类型转换
int x = 100;
void *ptr = &x;
int *int_ptr = (int*)ptr; // 将void指针转换为int指针

// 字符与整数转换
char c = 'A';
int code = (int)c;        // 65(ASCII码)
注意事项

1.精度丢失:大类型转小类型可能导致数据丢失

代码语言:javascript
复制
double d = 3.99;
int i = (int)d;        // i = 3(小数部分被截断)

2.符号问题:有符号与无符号类型转换需谨慎

代码语言:javascript
复制
int i = -1;
unsigned int u = (unsigned int)i; // 很大的正数

3.指针转换:不同类型的指针转换可能导致未定义行为


内容总结:本节涵盖了C语言中数据的基础概念,从存储本质到具体使用,是理解程序如何运作的基石。后续内容将基于这些概念展开。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-09-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、 常量的意义
  • 二、 全局与局部变量的本质区别
  • 三、 数据的存储位置
  • 四、 作用域 vs. 生命周期
  • 五、 关键字 (KeyWord) 与数据类型 (DataType)
  • 六、 标识符 (Identifier) 与命名规则
  • 七、 字符与ASCII编码
  • 八、 sizeof 与 strlen
  • 九、 常量与变量的定义
    • 1. 常量的定义及初始化
    • 2. 变量的定义及初始化
  • 十、 格式化输入/输出
    • 1. 输出函数 printf
    • 2. 输入函数 scanf
      • 补充内容:利用%m.n修饰占位符
  • 基本语法结构
  • 一、字段宽度 (width) - 控制输出的最小宽度
    • 1. 基本用法
    • 2. 动态指定宽度
  • 二、精度 (.precision) - 控制输出的精度
    • 1. 浮点数精度控制
    • 2. 字符串精度控制
    • 3. 整数精度控制(最小数字位数)
  • 三、scanf 中的格式控制
    • 1. 基本输入控制
    • 2. 宽度限制 - 防止缓冲区溢出
    • 3. 扫描集 (scanset) - 精确控制输入内容
    • 4. 跳过特定输入
  • 五、特殊技巧和注意事项
    • 1. printf 标志组合使用
    • 2. scanf 与 printf 的差异
  • 十一、 自定义数据类型
    • 结构体 (struct)
    • 类型重定义 (typedef)
  • 十二、 强制类型转换
    • 基本语法结构
    • 使用案例
    • 注意事项
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档