嵌入式八股文篇——P1 关键字篇

嵌入式八股文篇--P1 关键字篇

目录

[嵌入式八股文篇--P1 关键字篇](#嵌入式八股文篇--P1 关键字篇)

[1. Continue](#1. Continue)

[2. Break](#2. Break)

[3. Return](#3. Return)

[4. Goto](#4. Goto)

[5. Volatile(编译优化阶段)](#5. Volatile(编译优化阶段))

[6.Struct(结构体) (C和C++区别,求结构体大小,使用的注意事项)](#6.Struct(结构体) (C和C++区别,求结构体大小,使用的注意事项))

7.class和struct的区别?

8.Union(联合体)

8.1.联合体union和结构体struct的区别:

8.2.联合体一般可以用来判断大小端问题:

8.3.大小端转换问题:

8.4.计算占用空间大小问题:

9.Enum

10.Typedef

[11.Const (C中的变量:局部,函数形成,返回值,指针,typedef的区别,数组大小定义,case C++:常函数,常对象)](#11.Const (C中的变量:局部,函数形成,返回值,指针,typedef的区别,数组大小定义,case C++:常函数,常对象))

12.Extern(链接阶段)

13.Register

14.Auto

15.Static (c语言:变量、函数 C++:类中变量、类中静态成员函数)

[16.Swicth case](#16.Swicth case)

[17.Do while](#17.Do while)

18.Sizeof

[19.New/malloc delete/free(指明大小,返回值,初始化)](#19.New/malloc delete/free(指明大小,返回值,初始化))

20.左值和右值是什么?

[21. 什么是短路求值](#21. 什么是短路求值)

22.++a和a++区别

23.局部变量能不能和全局变量重名?

[24. gets和scanf函数的区别(空格,输入类型,返回值)](#24. gets和scanf函数的区别(空格,输入类型,返回值))

[25. C语言编译过程中,volatile关键字和extern关键字分别在哪个阶段起作用?](#25. C语言编译过程中,volatile关键字和extern关键字分别在哪个阶段起作用?)

[26. Printf()函数的返回值](#26. Printf()函数的返回值)

27.C语言中不能用来表示整常数的进制是二进制

[28.char *str1 = "hello"和char str2[] = "hello"](#28.char *str1 = “hello”和char str2[] = “hello”)


1. Continue

continue 仅用于循环语句,作用是跳过本次循环剩余语句,直接进入下一次循环条件判断(不终止整个循环),核心是 "局部跳过当前轮,循环整体仍继续"。

总结:跳本轮回判(跳过本次循环,进入下一轮判断)

2. Break

break 仅用于循环(for/while/do-while)或 switch 语句,作用是强制跳出最近包含它的那一层结构:在循环中,终止当前循环的所有后续迭代;在 switch-case 中,终止当前 case 的执行并跳出整个 switch。若结构嵌套(如 for 循环内有 switch),break 仅影响直接包含它的内层结构,不影响外层。需特别注意:switch 中若缺少 break,会从匹配的 case 开始 "穿透执行" 所有后续分支(包括 default),直到遇到 break 或 switch 结束。

与 continue 对比:break 是 "终止本层结构",continue 是 "跳过本次循环"。

总结:破层终止(破坏当前层级结构并终止其执行)

3. Return

return 是函数体专用的关键字,作用是立即终止当前函数的所有执行(包括函数内的循环、分支等),退出函数并返回至调用处;若函数为非 void 类型,需携带匹配类型的返回值传递给调用者,void 类型则可直接用 return; 实现提前退出。

总结:退函返值(退出函数并返回值)

4. Goto

goto 是用于当前函数内的无条件跳转语句,可直接跳转到预定义的标签(格式为标签名:)处执行,无需遵循正常代码顺序。主要用途是跳出多层循环或集中处理错误,但滥用会导致逻辑混乱,且不能跨函数跳转。

总结:函数内跳标签(慎用于多层循环跳出)

5. Volatile (编译优化阶段)

volatile 作用于编译优化阶段,用于修饰可能被当前代码外因素(如中断、多线程、硬件寄存器)修改的变量,强制编译器每次使用变量时都从内存重新读取,而非使用寄存器缓存的旧值,避免数据失效。

总结:强读内存禁优化

6.Struct(结构体) (C和C++区别,求结构体大小,使用的注意事项)

struct(结构体)在 C 与 C++ 中差异显著:C 语言结构体仅能包含数据成员,不可有函数、不支持继承,使用时需加struct或通过typedef取别名,成员默认 public 且不可初始化,空结构体大小为 0;C++ 结构体可包含函数、支持继承,可直接用结构体名定义变量,支持权限控制(public/private 等),允许成员初始化,空结构体大小为 1。计算结构体大小时需遵循字节对齐规则(总大小为最大成员类型字节数的整数倍,成员偏移量为自身类型字节数的整数倍)。

总结:C 简 C++ 强,大小看对齐

7.class和struct的区别?

class 与 struct 的核心区别集中在权限与功能场景:从访问权限看,class 成员默认 private(仅类内可访问),struct 默认 public(外部可直接访问);从继承权限看,class 默认 private 继承(子类无法直接访问父类成员),struct 默认 public 继承(子类可直接访问父类 public 成员);从功能场景看,class 更侧重封装 "对象实现"(隐藏内部逻辑),struct 更侧重定义 "数据结构"(暴露数据),且 class 可用于定义模板,struct 不支持此功能。

总结:权默异(class 私 struct 公),功能别(class 能模板 struct 不能)

8.Union(联合体)

8.1.联合体union和结构体struct的区别:

union(联合体)与 struct(结构体)的核心区别在于内存分配方式:联合体的所有成员共享同一块内存空间,修改任一成员会直接接影响其他成员;而结构体的成员各自占独立独立内存,总空间是各成员内存的叠加(需考虑字节对齐),成员间数据互不干扰。

总结:联共内(成员共享内存),结叠存(成员内存叠加)

8.2.联合体一般可以用来判断大小端问题:

联合体是判断大小端的常用工具:利用其成员共享内存的特性,通过多字节数据在内存中的存储顺序区分 ------ 大端字节序中高字节存低地址、低字节存高地址;小端字节序中低字节存低地址、高字节存高地址。

示例中,联合体myshort tchar b[2]共享内存,当t=0X0102时:若b[0]=0x01b[1]=0x02,为大端;若b[0]=0x02b[1]=0x01,则为小端。

总结:联共内存判端序(高存低为大,低存低为小)

8.3.大小端转换问题:

大小端转换主要通过位运算(与运算 + 位移运算) 实现,核心思路是将数据各字节的存储位置按需求互换。以 32 位数据为例,需将原本 0-7 位(最低字节)移到 24-31 位(最高字节)、8-15 位移到 16-23 位、16-23 位移到 8-15 位、24-31 位(最高字节)移到 0-7 位。

如代码所示,先通过&运算提取各字节(如value & 0x000000ff提取 0-7 位),再用<</>>将其移到目标位置,最后用|运算合并各字节,完成 32 位数据的大小端转换。

复制代码
//32位大小端交换
int swap(int value)
{
value=((value & 0x000000ff)<<24)|
((value & 0x0000ff00)<<8)|
((value & 0x00ff0000)>>8)|
((value & 0xff000000)>>24);
return value;
}

8.4.计算占用空间大小问题:

对于不同位的操作系统,个别数据类型数据大小不一样,

Long 和unsigned long在32位中是4个字节

在64位中是8个字节

计算联合体(union)和结构体(struct)的占用空间需遵循字节对齐规则,核心要点如下:

  1. 基础规则
    • 总大小必须是成员中最大类型字节数的整数倍
    • 每个成员的偏移量(距起始地址)必须是自身类型字节数的整数倍
  1. 联合体计算 :因所有成员共享内存,大小需同时满足:①能容纳最大成员(含数组总大小);②是最大成员类型字节数的整数倍。例如union {double i; int k[5];}中,int[5]占 20 字节,double为 8 字节,故总大小为 24(8 的 3 倍,且≥20)。
  2. 结构体计算 :成员内存叠加,需注意:①嵌套联合体时,其起始偏移量需符合自身最大成员类型的对齐要求;②最终总大小是结构体中最大类型(含嵌套类型)字节数的整数倍。例如含int(4 字节)、24 字节联合体(最大成员 8 字节)、double(8 字节)的结构体,总大小为 40(8 的 5 倍)。

总结:对齐看最大,联取容大值,结叠算偏移

9.Enum

enum(枚举)是用于定义离散常量集合的类型,内部常量默认从 0 开始依次自增(可手动指定初始值打破自增序列),为离散值提供语义化名称,增强代码可读性。例如enum Week {Mon, Tue, Wed};中,Mon=0、Tue=1、Wed=2。

总结:枚举常量自增(默认从 0 起,可手动指定)

10.Typedef

typedef 是编译期关键字,用于给已有类型起别名,具有类型检查功能,可简化数组、指针、结构体等复杂类型的使用,且在其作用域内有效,不能在函数内定义;与 #define(预处理指令,仅做字符串替换,无类型检查)的核心区别在于:定义指针时,typedef 能保证所有变量均为指针类型(如 typedef int* myptr; myptr a,b;ab 都是指针),而 #define 可能导致部分变量类型不符合预期(如 #define myptr int*; myptr a,b;b 是 int 类型)。

总结:类型别名(编译检查,指针定义无歧义)

11.Const (C中的变量:局部,函数形成,返回值,指针,typedef的区别,数组大小定义,case C++:常函数,常对象)

const 是用于定义 "只读实体" 的关键字,在 C 和 C++ 中功能各有侧重:在 C 中,可修饰变量(表值不可改)、函数参数(表函数内不可改参数)、函数返回值(表返回内容不可改),修饰指针时分 "常量指针"(内容不可改)、"指针常量"(地址不可改)、"完全只读指针"(地址和内容均不可改);需注意 C 中 const 变量非编译期常量,不能用于定义数组大小或 switch case 常量,推荐用 #define 定义此类常量。在 C++ 中,除兼容 C 的功能外,还可修饰 "常函数"(类成员函数,仅读类成员不修改)和 "常对象"(仅调用常函数)。存储上,局部 const 变量存栈(C 中可间接修改),已初始化的全局 const 变量存只读数据段(不可修改)。

总结:定义只读实体(C 限变量指针,C++ 加常函数对象)

12.Extern(链接阶段)

extern 是作用于链接阶段的关键字,核心用于跨文件引用实体:一是声明外部变量(告知编译器变量在其他文件已定义并分配内存,本文件仅使用,不可初始化,且全局变量不能定义在头文件,避免多文件包含报 "multiple define" 错误);二是声明外部函数(告知编译器函数在其他文件定义,本文件可调用);此外,extern "C" 专门用于 C++ 中按 C 语言规则编译代码,解决 C++ 名称修饰导致的跨语言调用链接失败问题。

总结:链接声明外部(变量函数跨文件,C++ 用 "C" 调 C)

13.Register

register 是向编译器发起的 "建议性声明",希望将局部整数类型变量存储到 CPU 寄存器中(利用寄存器高速访问特性提升效率),但编译器可根据寄存器资源情况决定是否采纳;需注意,register 不可修饰浮点数、数组等类型,也不能对被修饰变量执行取地址操作(&)。

总结:建议存寄存器(限局部整数,禁取地址)

14.Auto

auto 是局部变量的默认存储类型(通常可省略),表示 "自动存储期"------ 变量存储在栈中,函数执行结束后会自动销毁,仅在定义它的局部作用域内有效,无法修饰全局变量或静态变量。

总结:局部默认存栈(自动销毁,限局部域)

15.Static (c语言:变量、函数 C++:类中变量、类中静态成员函数)

static 关键字在 C 和 C++ 中功能丰富,核心是限定作用域与延长生命周期:

C 语言中

  1. 静态变量
    • 静态局部变量:仅在函数内可见,生命周期与程序一致(函数退出不销毁),仅初始化一次(保留上次值),存储在数据段 /.bss 段。
    • 静态全局变量:仅在本文件内可见(其他文件无法通过extern访问),生命周期与程序一致,避免全局命名冲突。
  1. 静态函数:仅在本源文件内可调用,其他文件可定义同名函数,实现 "文件私有"。

C++ 扩展(类中)

  1. 静态成员变量:所有对象共享同一块内存,不占类空间,需在类外单独定义(类内仅声明,不可在构造函数中初始化)。
  2. 静态成员函数 :属于类而非对象,无this指针,仅能访问静态成员,不能访问非静态成员(面试高频考点)。

总结:静存久,域受限;类静共,无 this

16.Swicth case

switch case 是多分支条件判断结构,核心规则有三:①表达式结果必须是整数 / 字符类型(不可为浮点数或字符串);②case 后必须是常量(不可为变量或字符串,字符因本质是整数可使用);③若无 break,会从匹配 case 开始 "穿透执行" 所有后续分支(直至 break 或结构结束)。

总结:整表常量判,break 防穿透

17.Do while

do while 是一种循环结构,核心逻辑是 "先执行循环体,再判断条件"------ 无论条件是否成立,循环体至少会执行一次,仅当条件为假时才退出循环,适用于需先执行再判断的场景(如输入验证)。

总结:先执行再判(循环体至少一次)

18.Sizeof

sizeof 是编译期关键字,核心用于计算变量 / 类型的内存占用大小,关键特性与差异如下:

  1. strlen 区别:sizeof 算内存大小(含字符串 \0)、编译期计算、是关键字;strlen 算字符串有效长度(不含 \0)、运行期计算、是函数。
  2. 特殊计算:32 位机下指针大小恒为 4 字节;引用大小与对应类型一致;数组大小 = 类型字节数 × 元素数(如 int[5] 为 20 字节);sizeof(a++) 不执行表达式(a 值不变)。
  3. 特殊值:sizeof("\0") 为 2(含两个 \0),sizeof('\0') 为 4(字符按 int 存储),sizeof(void) 出错或为 1;自定义宏 mysizeof 可通过地址差模拟其功能。

总结:编译算内存(含 \0,不执行表达式,指针 32 位恒 4)

19.New/malloc delete/free (指明大小,返回值,初始化)

new/deletemalloc/free 均用于动态内存管理,但核心差异显著:

  • 性质new/delete 是 C++ 运算符,malloc/free 是 C 标准库函数。
  • 功能new 申请内存后自动调用构造函数初始化,delete 先调用析构函数再释放内存;malloc 仅申请内存(需显式指定大小),free 仅释放内存,均不处理构造 / 析构。
  • 使用new 返回对应类型指针(无需强转),malloc 返回 void*(需显式强转)。

总结:new 带构造免强转,malloc 仅申请需大小

20.左值和右值是什么?

左值和右值是 C/C++ 中用于区分表达式或变量 "可被操作特性" 的概念,核心差异在于是否可被修改、能否放在赋值运算符左侧

  • 左值 :本质是 "有明确内存地址、可被修改" 的实体,能出现在赋值运算符左侧(也可出现在右侧)。比如普通变量(int a)、数组元素(arr[0])等,其值可通过赋值改变;但需注意,数组名是 "常量左值",虽有内存地址,却不可被修改(如str++str = new char[5]均报错)。
  • 右值 :本质是 "临时结果、无持久内存地址、不可被修改" 的实体,仅能出现在赋值运算符右侧。比如字面量(10"abc")、表达式结果(a + b)、后置自增(a++,因其返回的是自增前的临时值)等,无法作为赋值对象(如i++ = 5报错)。

核心规则:左值可作右值,右值不能作左值;特殊左值(如数组名)虽有地址,但不可修改。

总结:左值可改放左边,右值只读放右边(数组名是特殊左值,不可改)

21. 什么是短路求值

短路求值是逻辑运算符(|| 逻辑或、&& 逻辑与)的核心特性:在判断表达式结果时,若通过前面的部分已能确定最终结果,就不再执行后续部分,直接返回结果,以此提升效率。具体规则与示例如下:

1. 逻辑或( ||****):一真则真,遇真即停

只要左侧表达式为 "真",就无需判断右侧表达式,直接返回 "真";仅当左侧为 "假" 时,才执行右侧表达式进一步判断。

  • 示例 a>0 || b++>2:左侧 a>02>0)为真,直接确定整体为真,右侧 **b++**未执行 ,故 b 仍为 3。
  • a<0 || b++>2:左侧 a<02<0)为假,需执行右侧 b++b 从 3 变为 4,最终整体为真。

2. 逻辑与( &&****):一假则假,遇假即停

只要左侧表达式为 "假",就无需判断右侧表达式,直接返回 "假";仅当左侧为 "真" 时,才执行右侧表达式进一步判断。

  • 示例 a>0 && b++>2:左侧 a>0 为真,需执行右侧 b++b 从 4 变为 5,最终整体为真。
  • a<0 && b++>2:左侧 a<0 为假,直接确定整体为假,右侧 **b++**未执行b 仍为 5。

总结:|| 遇真停,&& 遇假停(后续表达式不执行)

22.++a和a++区别

++a(前置自增)与 a++(后置自增)的核心区别在于自增操作的执行时机、返回值类型及效率,具体差异如下:

1. 执行时机与返回值:核心差异

两者最终都会让 a 的值 + 1,但 "何时 + 1" 和 "返回什么值参与后续运算" 完全不同:

  • a++(后置自增):先取值,后自增 步骤:①先将 a 当前的值存入临时变量 (返回的是自增前的 "旧值");②再对 a 本身执行 + 1 操作;③后续运算使用的是临时变量中的 "旧值"。例:int a=1; int b=a++; → 先将 a=1 存入临时变量给 b(故 b=1),再让 a 自增为 2。
  • ++a(前置自增):先自增,后取值 步骤:①先对 a 本身执行 + 1 操作;②直接返回 a引用 (无需临时变量,返回的是自增后的 "新值");③后续运算使用的是 a 自增后的 "新值"。例:int a=1; int b=++a; → 先让 a 自增为 2,再将 a=2 直接给 b(故 b=2)。

2. 效率差异:前置自增更高

  • a++ 需额外开辟临时变量存储自增前的旧值,运算结束后还要释放临时空间,存在额外开销。
  • ++a 直接操作原变量并返回引用,无需临时变量,效率更高。(尤其在循环(如 for 循环)或高频调用场景中,++a 的效率优势更明显。)

3. 复杂运算示例:结合返回值特性分析

所有运算均基于 "返回值" 进行,需明确两者返回的是 "旧值" 还是 "新值引用":例:int i=1; printf("%d\n", ++i / i--);

  • 第一步:++i 先执行 → i 自增为 2,返回 i 的引用(此时引用指向 i=2)。
  • 第二步:i-- 执行 → 先将 i=2 存入临时变量(返回旧值 2),再让 i 自减为 1(此时 ++i 的引用指向 i=1)。
  • 第三步:运算 ++i 的返回值(1) / i-- 的返回值(2) → 1/2=0(整数除法),最终输出 0。

总结:a++ 先值后增(需临时变量,效率低),++a 先增后值(无临时变量,效率高)

23.局部变量能不能和全局变量重名?

局部变量与全局变量可以重名,但会触发 "局部变量屏蔽全局变量" 的规则 ------ 在局部变量的作用域内(如函数、代码块),代码默认操作的是局部变量,全局变量会被 "隐藏",无法直接访问。

若需在局部作用域中使用被屏蔽的全局变量,可通过 extern 关键字声明该变量为 "外部全局变量",明确指定使用全局版本。

示例如下:

复制代码
#include <stdio.h>
int a = 1; // 全局变量a

void test() {
    int a = 2; // 局部变量a(与全局变量重名)
    printf("局部变量a:%d\n", a); // 默认操作局部变量,输出2
    
    // 用extern声明,显式使用全局变量
    {
        extern int a; 
        printf("全局变量a:%d\n", a); // 输出1
    }
}

int main() {
    test();
    return 0;
}

总结:可重名,局部屏蔽全局;用 extern 显式访全局

24. gets和scanf函数的区别(空格,输入类型,返回值)

getsscanf 均为输入函数,但在处理方式、适用场景和返回值上差异显著,核心区别如下:

  1. 空格处理
    • gets完整读取一行输入(包括空格) ,直到遇到换行符(\n)才停止,且会自动丢弃换行符。
    • scanf 遇空格、制表符或换行符时默认视为输入分隔符 ,会停止当前变量的输入(除非用格式控制符如 %[^\n] 特殊处理)。
  1. 输入类型
    • gets 仅用于读取字符串(char*),功能单一。
    • scanf 是格式化输入函数,可通过格式符(%d%f%s 等)读取整数、浮点数、字符串等多种基础类型。
  1. 返回值
    • gets 返回 char* 指针:成功时返回输入字符串的地址,失败(如读入错误)时返回 NULL
    • scanf 返回 int 整数:表示成功赋值的变量个数,遇到文件结尾时返回 EOF(通常为 -1)。

示例对比:

复制代码
char str1[20], str2[20];
gets(str1);       // 输入 "hello world",str1 会存储完整字符串(含空格)
scanf("%s", str2); // 输入 "hello world",str2 仅存储 "hello"(遇空格停止)

总结:gets 读整行含空格(仅字符串),scanf 遇空格停(多类型),返回值类型不同

25. C语言编译过程中,volatile关键字和extern关键字分别在哪个阶段起作用?

在 C 语言编译过程中,volatileextern 关键字的作用阶段不同:

  • volatile:作用于编译阶段。它告诉编译器,被修饰的变量可能被意外修改(如硬件中断、多线程等),禁止编译器对该变量进行优化(如缓存变量值到寄存器、省略重复读取等),确保每次访问都直接从内存中读取最新值。
  • extern:作用于链接阶段。它用于声明外部变量或函数,告知编译器 "该实体在其他文件中定义",在链接时由链接器根据声明找到对应的定义并完成地址关联,实现跨文件引用。

总结:volatile 防编译优化(编译期),extern 助跨文件链接(链接期)

26. Printf()函数的返回值

printf() 函数的返回值是成功输出的字符总数 (包括数字、字母、空格、换行符 \n 等所有输出的字符),若输出失败则返回负数。

具体示例解析:

  1. printf("%d\n", 241);输出内容为 "241\n",包含 3 个数字字符 + 1 个换行符 \n,共 4 个字符,故返回值为 4。
  2. printf("%d\n", printf("%d", 241));
    • 内层 printf("%d", 241) 输出 "241"(3 个字符),返回值为 3。
    • 外层 printf 输出内层返回的 3 加换行符 \n,即 "3\n"(2 个字符),但整体输出结果为 "2413\n",外层函数返回值为 2。
    • 最终屏幕显示 "2413"(换行被包含在输出中)。
  1. printf("%d\n", printf("%d\n", 241));
    • 内层 printf("%d\n", 241) 输出 "241\n"(4 个字符),返回值为 4。
    • 外层 printf 输出 4 加换行符,即 "4\n",整体输出为 "241\n4\n",外层返回值为 2。
    • 最终屏幕显示 "241" 换行后再显示 "4"

总结:返回输出字符总数(含所有符号和控制字符)

27.C语言中不能用来表示整常数的进制是二进制

在 C 语言中,整常数的表示仅支持十进制、八进制、十六进制 三种进制,不支持二进制直接表示,具体规则如下:

  1. 十进制 :默认形式,由数字 0-9 组成,不能以 0 开头(除非数值本身是 0)。例:123-450
  2. 八进制 :以数字 0 开头,后续由 0-7 组成。例:012(对应十进制的 10)、077(对应十进制的 63)。
  3. 十六进制 :以 0x0X 开头,后续由 0-9a-fA-F 组成。例:0x1A(对应十进制的 26)、0XFF(对应十进制的 255)。

若需使用二进制数值,需通过其他进制间接转换 (如将二进制 1101 转为十进制 13、八进制 015 或十六进制 0xD 后使用),或借助 C99 及后续标准中的 %b 格式符(部分编译器支持,非标准),但无法直接以二进制形式定义整常数。

总结:C 语言整常数无二进制表示,仅支持十进制、八进制、十六进制

28.char *str1 = "hello"和char str2[] = "hello"

char *str1 = "hello"char str2[] = "hello" 是 C 语言中字符串两种常见定义方式,核心区别体现在存储位置、可修改性及变量性质上,具体差异如下:

1. 存储位置与内存性质

  • char str2[] = "hello"****(字符数组) :字符串 "hello" 被存储在栈区 (局部数组)或数据段 (全局数组),数组会分配独立内存空间(长度为 6,含终止符 \0),内容是字符串的副本。
  • char str1 = "hello"***(字符指针) :字符串 "hello" 被存储在只读数据段 (常量区),指针 str1 仅在栈区存储该常量字符串的首地址,本身不存储字符串内容。

2. 可修改性

  • 字符数组 str2
    • 数组名是常量指针 (地址不可变),不能执行 str2++ 等修改地址的操作。
    • 但数组元素(内存内容)可修改,如 str2[0] = 'W' 是合法的(修改栈 / 数据段的副本)。
  • 字符指针 str1
    • 指针本身是变量 ,可修改指向的地址,如 str1 = "world" 是合法的(指向新的常量字符串)。
    • 但指向的内容(只读数据段的常量)不可修改,如 *str1 = 'w' 会触发段错误(写入只读内存)。

3. 本质区别总结

|--------|---------------------------|--------------------------|
| 特性 | char str2[] = "hello" | *char str1 = "hello" |
| 变量性质 | 数组(分配独立内存存储内容) | 指针(仅存储常量字符串地址) |
| 地址可改性 | 不可改(数组名是常量指针) | 可改(指针可指向新地址) |
| 内容可改性 | 可改(修改数组内的副本) | 不可改(指向只读常量区) |
| 存储区域 | 栈区 / 数据段(可写) | 指针在栈区,内容在只读数据段 |

简言之:数组存副本(内容可改,地址不可改),指针存地址(地址可改,内容不可改)

29. 局部变量和全局变量同名的时候如何使用全局变量

当局部变量与全局变量同名时,若要在局部作用域中使用全局变量,最直接的方式是通过 extern****关键字显式声明,明确指定引用全局版本。具体用法如下:

复制代码
#include <stdio.h>

int a = 10; // 全局变量

int main() {
    int a = 20; // 局部变量(与全局变量同名)
    
    // 默认使用局部变量
    printf("局部变量 a: %d\n", a); // 输出 20
    
    // 使用 extern 声明,显式引用全局变量
    {
        extern int a; // 声明此处使用全局变量 a
        printf("全局变量 a: %d\n", a); // 输出 10
    }
    
    return 0;
}

原理extern int a; 告诉编译器 "此处的 a 是外部全局变量",从而绕过局部变量的屏蔽,直接访问全局版本。声明需放在局部作用域内(如代码块 {} 中),避免影响其他部分对局部变量的使用。

此外,也可通过 函数封装全局变量 的方式间接访问(适用于复杂场景):

复制代码
int a = 10; // 全局变量

int get_global_a() {
    return a; // 函数内部无同名局部变量,直接返回全局 a
}

int main() {
    int a = 20; // 局部变量
    printf("全局变量 a: %d\n", get_global_a()); // 输出 10(通过函数获取全局值)
    return 0;
}

总结:局部屏蔽全局时,用 extern****显式声明或函数封装可访问全局变量

相关推荐
workflower2 小时前
将图片中的图形转换为可编辑的 PPT 图形
java·开发语言·tomcat·powerpoint·个人开发·结对编程
TDengine (老段)2 小时前
TDengine 时序函数 DERIVATIVE 用户手册
大数据·数据库·sql·物联网·时序数据库·iot·tdengine
TDengine (老段)3 小时前
TDengine 时序函数 STATEDURATION 用户手册
大数据·数据库·sql·物联网·时序数据库·iot·tdengine
ftpeak3 小时前
《WebAssembly指南》第九章:WebAssembly 导入全局字符串常量
开发语言·rust·wasm
卡戎-caryon3 小时前
【Java SE】06. 数组
java·开发语言
Rain_is_bad3 小时前
初识c语言————数学库函数
c语言·开发语言·算法
lsx2024063 小时前
Eclipse 快捷键
开发语言
聪明的笨猪猪4 小时前
Java SE “泛型 + 注解 + 反射”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
磨十三4 小时前
C++ 类型转换全面解析:从 C 风格到 C++ 风格
java·c语言·c++