【C语言深入探索】:指针高级应用与极致技巧(二)

目录

一、指针与数组 

1.1. 数组指针

1.2. 指向多维数组的指针

1.2.1. 指向多维数组元素的指针

1.2.2. 指向多维数组行的指针

1.3. 动态分配多维数组

1.4. 小结

二、指针与字符串

2.1. 字符串表示

2.2. 字符串处理函数

2.3. 代码示例

2.4. 注意事项

三、指针与文件操作

3.1. 文件指针

3.2. 文件读写操作

3.3. 代码示例

3.4. 注意事项

四、指针的安全性

4.1. 避免空指针解引用

4.2. 避免内存泄漏

五、总结

5.1. 指针的算术运算

5.2. 指针与结构体

5.3. 动态内存分配(malloc/free)

5.4. 函数指针

5.5. 指向指针的指针

5.6. 指针与数组

5.7. 指针与字符串

5.8. 指针与文件操作

5.9. 指针的安全性


接【C语言深入探索】:指针高级应用与极致技巧(一)_c语言指针高级技巧-CSDN博客继续学习。

一、指针与数组 

在C语言中,指针和数组是两个非常基础且强大的概念。理解它们之间的关系,尤其是如何操作多维数组的指针,对于深入掌握C语言至关重要。

1.1. 数组指针

首先,我们要明白数组名实际上是一个指向数组首元素的指针常量。当我们说“指针可以指向数组的首元素”时,意味着我们可以定义一个指针,让它指向数组的第一个元素,然后通过指针运算来遍历数组的其他元素。

示例

#include <stdio.h>  int main() {  int arr[] = {1, 2, 3, 4, 5};  int *ptr = arr; // ptr 指向数组的首元素  // 通过指针遍历数组  for (int i = 0; i < 5; i++) {  printf("%d ", *(ptr + i));  }  printf("\n");  return 0;  
}

ptr 是一个指向 int 类型的指针,它指向数组 arr 的首元素。通过 *(ptr + i),可以访问数组中的每一个元素。 

运行结果:

1.2. 指向多维数组的指针

多维数组,如二维数组,可以看作是由多个一维数组(行)组成的数组。当我们谈论指向多维数组的指针时,实际上有两种主要情况:指向多维数组元素的指针指向多维数组行的指针

1.2.1. 指向多维数组元素的指针

这种指针直接指向多维数组中的一个元素,例如二维数组中的一个 int 元素。

示例

#include <stdio.h>  int main() {  int arr[3][4] = {  {1, 2, 3, 4},  {5, 6, 7, 8},  {9, 10, 11, 12}  };  int *ptr = &arr[0][0]; // ptr 指向二维数组的第一个元素  // 通过指针遍历二维数组  for (int i = 0; i < 3; i++) {  for (int j = 0; j < 4; j++) {  printf("%d ", *(ptr + i * 4 + j));  }  printf("\n");  }  return 0;  
}

ptr 是一个指向 int 类型的指针,它指向二维数组 arr 的第一个元素。通过 *(ptr + i * 4 + j),可以访问数组中的每一个元素。注意这里的 4 是因为每行有4个元素。

运行结果:

 

1.2.2. 指向多维数组行的指针

这种指针指向多维数组中的一行(一个一维数组),例如二维数组中的一行。

示例

#include <stdio.h>  int main() {  int arr[3][4] = {  {1, 2, 3, 4},  {5, 6, 7, 8},  {9, 10, 11, 12}  };  int (*ptr)[4] = arr; // ptr 指向二维数组的第一行  // 通过指针遍历二维数组  for (int i = 0; i < 3; i++) {  for (int j = 0; j < 4; j++) {  printf("%d ", ptr[i][j]);  }  printf("\n");  }  return 0;  
}

ptr 是一个指向包含4个 int 元素的数组的指针。它指向二维数组 arr 的第一行。通过 ptr[i][j],可以直接访问二维数组中的元素。 

1.3. 动态分配多维数组

使用动态内存分配函数(如malloc)可以创建多维数组。

示例代码

#include <stdio.h>  
#include <stdlib.h>  int main() {  int rows = 3, cols = 4;  // 动态分配二维数组  int **arr = (int **)malloc(rows * sizeof(int *));  for (int i = 0; i < rows; i++) {  arr[i] = (int *)malloc(cols * sizeof(int));  }  // 初始化二维数组  int counter = 1;  for (int i = 0; i < rows; i++) {  for (int j = 0; j < cols; j++) {  arr[i][j] = counter++;  }  }  // 遍历二维数组  for (int i = 0; i < rows; i++) {  for (int j = 0; j < cols; j++) {  printf("%d ", arr[i][j]);  }  printf("\n");  }  // 释放动态分配的内存  for (int i = 0; i < rows; i++) {  free(arr[i]);  }  free(arr);  return 0;  
}

运行结果: 

首先使用malloc为二维数组的每一行分配了一个指针数组,然后为每个指针分配了一个整数数组。最后,我们遍历并打印了二维数组的元素,并释放了动态分配的内存。

理解多维数组的指针表示和动态分配多维数组是掌握C语言高级特性的关键。通过这些技术,我们可以创建和操作复杂的数据结构,以满足不同的编程需求。 

1.4. 小结

  • 数组指针:指向数组首元素的指针,可以通过指针运算遍历数组。
  • 指向多维数组元素的指针:直接指向多维数组中的一个元素,需要计算偏移量来访问所有元素。
  • 指向多维数组行的指针:指向多维数组中的一行(一个一维数组),可以方便地按行访问多维数组。

二、指针与字符串

字符串是一个特殊的字符数组,它以空字符(null character)'\0' 作为结束标志。这种表示方法使得C语言的字符串函数能够方便地遍历和处理字符串,因为它们依赖于这个结束标志来确定字符串的结束位置。

2.1. 字符串表示

字符串通常以字符数组的形式声明和初始化。例如:

char str[] = "Hello, World!";

str 是一个字符数组,它包含了字符串 "Hello, World!" 以及一个隐式的结束字符 '\0'

2.2. 字符串处理函数

C语言标准库提供了一系列字符串处理函数,这些函数通过指针来操作字符串。以下是一些常用的字符串处理函数及其简要说明:

strcpy(char *dest, const char *src): 将字符串 src 复制到字符串 dest 中。
strlen(const char *str): 返回字符串 str 的长度(不包括结束字符 '\0')。
strcat(char *dest, const char *src): 将字符串 src 追加到字符串 dest 的末尾。
strcmp(const char *str1, const char *str2): 比较字符串 str1 和 str2。如果 str1 等于 str2,则返回0;如果 str1 小于 str2,则返回一个负数;如果 str1 大于 str2,则返回一个正数。

2.3. 代码示例

以下是一个包含上述字符串处理函数使用的示例代码: 

#include <stdio.h>  
#include <string.h>  int main() {  char str1[50] = "Hello, ";  char str2[] = "World!";  char str3[100];  // 使用 strcpy 复制字符串  strcpy(str3, str1);  printf("After strcpy: str3 = %s\n", str3);  // 使用 strcat 追加字符串  strcat(str3, str2);  printf("After strcat: str3 = %s\n", str3);  // 使用 strlen 获取字符串长度  int len = strlen(str3);  printf("Length of str3: %d\n", len);  // 使用 strcmp 比较字符串  int cmp = strcmp(str3, "Hello, World!");  if (cmp == 0) {  printf("str3 is equal to \"Hello, World!\"\n");  } else if (cmp < 0) {  printf("str3 is less than \"Hello, World!\"\n");  } else {  printf("str3 is greater than \"Hello, World!\"\n");  }  return 0;  
}

运行结果:

2.4. 注意事项

  • 在使用 strcpystrcat 等函数时,确保目标数组有足够的空间来存储结果字符串,包括结束字符 '\0'
  • strcmp 函数比较的是字符串的字典顺序(基于ASCII码值)。
  • C语言中的字符串处理函数通常不会检查数组边界,因此程序员需要负责确保不会发生数组越界。

三、指针与文件操作

在C语言中,文件操作是通过标准I/O库提供的函数来实现的,这些函数使用FILE类型的指针来代表打开的文件。FILE是一个结构体类型,它包含了文件操作所需的所有信息。通过文件指针,我们可以执行文件的读写操作。

3.1. 文件指针

在C语言中,FILE是一个在<stdio.h>头文件中定义的结构体类型。当我们打开一个文件时,fopen函数会返回一个指向FILE结构体的指针,这个指针就是文件指针。如果打开文件失败,fopen会返回NULL

3.2. 文件读写操作

C语言提供了多种文件读写函数,以下是一些常用的:

fread(void *ptr, size_t size, size_t nmemb, FILE *stream): 从文件流stream中读取nmemb个元素,每个元素的大小为size字节,并将它们存储在ptr指向的缓冲区中。
fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream): 将ptr指向的缓冲区中的nmemb个元素写入到文件流stream中,每个元素的大小为size字节。
fprintf(FILE *stream, const char *format, ...): 根据format指定的格式,将格式化的输出写入到文件流stream中。
fscanf(FILE *stream, const char *format, ...): 从文件流stream中读取数据,并根据format指定的格式将它们存储到对应的变量中。

3.3. 代码示例

以下是一个包含文件读写操作的示例代码:

#include <stdio.h>  
#include <stdlib.h>  int main() {  FILE *file;  char buffer[100];  int data = 12345;  // 打开文件用于写入(如果文件不存在则创建)  file = fopen("example.txt", "w");  if (file == NULL) {  perror("Failed to open file for writing");  return EXIT_FAILURE;  }  // 使用fprintf写入数据到文件  fprintf(file, "This is a test.\n");  fprintf(file, "Integer data: %d\n", data);  // 关闭文件  fclose(file);  // 打开同一个文件用于读取  file = fopen("example.txt", "r");  if (file == NULL) {  perror("Failed to open file for reading");  return EXIT_FAILURE;  }  // 使用fscanf读取整数数据(注意:这里读取整数之前需要先读取前面的文本)  // 通常情况下,我们会先读取一行文本到缓冲区,然后根据需要解析它  while (fgets(buffer, sizeof(buffer), file) != NULL) {  printf("%s", buffer); // 打印读取到的行  // 这里简单起见,我们不直接从fgets的结果中解析整数  // 但在实际应用中,可能需要使用sscanf或其他方法来解析缓冲区中的数据  }  // 注意:在这个例子中,我们没有直接使用fscanf来读取整数,因为fscanf需要精确匹配格式  // 如果文件内容不是严格按照我们预期的格式组织的,fscanf可能会失败或读取错误的数据  // 关闭文件  fclose(file);  return EXIT_SUCCESS;  
}

运行结果:

3.4. 注意事项

  • 在打开文件后,一定要检查fopen的返回值,以确保文件成功打开。
  • 在完成文件操作后,使用fclose关闭文件,以释放资源并确保数据正确写入到磁盘中。
  • 当使用freadfwrite进行二进制文件操作时,确保了解文件的格式和数据的布局。
  • 当使用fprintffscanf进行文本文件操作时,注意格式字符串和变量类型的匹配,以避免未定义的行为。
  • 文件操作可能会失败,例如由于权限问题、磁盘空间不足或文件路径不存在等原因。因此,总是检查文件操作的返回值是一个好习惯。

四、指针的安全性

指针的使用虽然强大,但也伴随着一定的风险。为了编写健壮、可靠的代码,必须注意指针的安全性,特别是要避免空指针解引用和内存泄漏。

4.1. 避免空指针解引用

空指针解引用是指试图访问一个值为NULL(空)的指针所指向的内存区域,这通常会导致程序崩溃。因此,在使用指针之前,必须检查其是否为空。

示例代码

#include <stdio.h>  
#include <stdlib.h>  int main() {  int *ptr = NULL; // 初始化指针为空  // 检查指针是否为空  if (ptr == NULL) {  printf("Pointer is NULL, avoiding dereference.\n");  } else {  // 如果不为空,则解引用(但在这个例子中,这会导致未定义行为,因为ptr是NULL)  // printf("%d\n", *ptr); // 危险操作,不要取消注释!  }  // 正确的做法:在分配内存后再解引用  ptr = (int *)malloc(sizeof(int)); // 动态分配内存  if (ptr == NULL) {  // 内存分配失败,处理错误  fprintf(stderr, "Memory allocation failed.\n");  return 1; // 退出程序,返回非零值表示错误  }  *ptr = 42; // 现在可以安全地解引用指针  printf("%d\n", *ptr);  // 释放动态分配的内存  free(ptr);  return 0;  
}

首先初始化了一个指针ptr为NULL,并检查它是否为空。然后,动态分配了内存,并在分配成功后解引用了指针。最后,释放了动态分配的内存。 

运行结果:

4.2. 避免内存泄漏

内存泄漏是指程序在动态分配内存后未能正确释放,导致这些内存无法被重用,最终可能导致系统内存耗尽。

示例代码(续): 

#include <stdio.h>  
#include <stdlib.h>  void processData(int *data) {  // 假设这里对data进行了一些处理  // ...  // 处理完毕后,不释放data(因为这不是此函数的职责)  // 但重要的是要确保在适当的时候释放它,以避免内存泄漏  
}  int main() {  int *data = (int *)malloc(sizeof(int) * 100); // 动态分配内存用于存储100个整数  if (data == NULL) {  fprintf(stderr, "Memory allocation failed.\n");  return 1;  }  // 使用数据  // ...  processData(data); // 传递数据给另一个函数进行处理  // 在main函数的末尾释放内存  free(data); // 避免内存泄漏  return 0;  
}

虽然processData函数可以使用这些数据,但它不应该负责释放这些数据,因为这可能会导致重复释放或提前释放的错误。相反,应该在main函数的末尾(或确保在不再需要这些数据时)释放内存,以避免内存泄漏。

通过遵循这些最佳实践,我们可以编写更安全、更可靠的C语言代码,减少程序崩溃和内存泄漏的风险。 

五、总结

指针在C语言中扮演着至关重要的角色,其高级应用涵盖了多个方面。

5.1. 指针的算术运算

  • 运算类型:指针可以进行递增(++)、递减(--)、加法(+)和减法(-)等算术运算。
  • 运算实质:这些运算实际上是在对指针所指向的内存地址进行加减操作。
  • 数组元素指针运算:对于指向数组元素的指针,递增或递减操作会使其分别指向数组的下一个或上一个元素。
  • 类型匹配:指针的算术运算只在指向相同类型的数据时才有意义,因为不同类型的数据可能占用不同大小的内存空间。

5.2. 指针与结构体

  • 结构体定义:结构体是一种复合数据类型,允许将多个不同类型的数据项组合成一个单一的类型。
  • 指针与结构体结合:指针可以指向结构体的实例或结构体内的成员,通过指针可以访问和修改结构体的内容。
  • 成员访问运算符:通过指针访问结构体的成员需要使用"->"运算符,这在处理动态分配的结构体数组时特别有用。

5.3. 动态内存分配(malloc/free)

  • 分配函数:malloc函数用于在运行时根据需要动态分配内存,并返回一个指向分配的内存块的指针。
  • 分配失败处理:如果malloc函数分配内存失败,会返回NULL指针,此时程序需要进行相应的错误处理。
  • 内存释放:分配的内存块在使用完毕后应通过free函数释放,以避免内存泄漏。
  • 内存初始化:malloc分配的内存不会自动初始化,其内容是未定义的,如果需要应手动初始化分配的内存。

5.4. 函数指针

  • 函数指针定义:函数指针是指向函数的指针,它存储了函数的地址,可以通过函数指针调用函数。
  • 函数指针应用:函数指针在回调函数、事件处理函数、以及实现函数表或接口等方面有广泛应用。
  • 函数指针类型:函数指针的类型必须与它所指向的函数的返回类型和参数类型相匹配。

5.5. 指向指针的指针

  • 二级指针:指向指针的指针(也称为二级指针)是指向另一个指针变量的指针。它允许程序员在程序中操作指针的地址,这在某些高级编程技巧中非常有用。

5.6. 指针与数组

  • 数组指针:指针可以指向数组的首元素,通过指针可以遍历数组的元素。
  • 指向多维数组的指针:多维数组可以看作是由多个一维数组组成的数组,指针也可以指向多维数组的元素或行。

5.7. 指针与字符串

  • 字符串表示:在C语言中,字符串通常以字符数组的形式表示,并以空字符'\0'作为结束标志。
  • 字符串处理函数:C语言提供了许多字符串处理函数,如strcpy、strlen、strcat等,它们通过指针来操作字符串。

5.8. 指针与文件操作

  • 文件指针:在C语言中进行文件操作时,通常使用FILE类型的指针来代表打开的文件。
  • 文件读写操作:通过文件指针可以进行文件的读写操作,如fread、fwrite、fprintf、fscanf等。

5.9. 指针的安全性

  • 空指针解引用:空指针解引用会导致程序崩溃,因此在操作指针之前需要检查其是否为空。
  • 野指针:野指针是指未初始化或已被释放的指针,使用野指针会导致不可预测的行为,因此应避免产生野指针。

综上所述,指针的高级应用为C语言编程提供了强大的功能和灵活性,但同时也需要程序员具备较高的编程素养和安全意识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/69007.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于开源AI智能名片2 + 1链动模式S2B2C商城小程序源码在抖音招商加盟中的应用与创新

摘要&#xff1a;本文深入探讨了在短视频蓬勃发展的时代背景下&#xff0c;招商加盟领域借助抖音平台所具备的独特优势。同时&#xff0c;全面剖析开源AI智能名片2 1链动模式S2B2C商城小程序源码这一创新工具&#xff0c;详细阐述其如何与抖音招商加盟深度融合&#xff0c;助力…

pthread_cond_broadcast的概念和使用案例

pthread_cond_broadcast 是 POSIX 线程&#xff08;Pthreads&#xff09;库中用于条件变量&#xff08;Condition Variable&#xff09;操作的函数&#xff0c;定义在 <pthread.h> 头文件中。它的核心作用是唤醒所有等待在某个条件变量上的线程&#xff0c;通常用于多线程…

爬虫学习笔记之Robots协议相关整理

定义 Robots协议也称作爬虫协议、机器人协议&#xff0c;全名为网络爬虫排除标准&#xff0c;用来告诉爬虫和搜索引擎哪些页面可以爬取、哪些不可以。它通常是一个叫做robots.txt的文本文件&#xff0c;一般放在网站的根目录下。 robots.txt文件的样例 对有所爬虫均生效&#…

Unity游戏(Assault空对地打击)开发(4) 碰撞体和刚体的添加

前言 飞机和世界的大小关系不太对&#xff0c;我稍微缩小了一下飞机。 详细步骤 选中所有地形对象&#xff0c;如果没有圈起的部分&#xff0c;点击Add Component搜索添加。 接着选中Player对象&#xff0c;添加这两个组件&#xff0c;最好&#xff08;仅对于本项目开发&#x…

【Linux】从硬件到软件了解进程

个人主页~ 从硬件到软件了解进程 一、冯诺依曼体系结构二、操作系统三、操作系统进程管理1、概念2、PCB和task_struct3、查看进程4、通过系统调用fork创建进程&#xff08;1&#xff09;简述&#xff08;2&#xff09;系统调用生成子进程的过程〇提出问题①fork函数②父子进程关…

C语言教学第三课:运算符与表达式

一、课程导入 同学们&#xff0c;上节课我们学习了变量和数据类型&#xff0c;这些是C语言的基础。今天&#xff0c;我们将继续深入学习C语言中的运算符与表达式。运算符是C语言中用于执行各种操作的符号&#xff0c;而表达式则是由变量、常量和运算符组成的有意义的组合。通过…

Maven全解析:从基础到精通的实战指南

概念&#xff1a; Maven 是跨平台的项目管理工具。主要服务基于 Java 平台的构建&#xff0c;依赖管理和项目信息管理项目构建&#xff1a;高度自动化&#xff0c;跨平台&#xff0c;可重用的组件&#xff0c;标准化的流程 依赖管理&#xff1a; 对第三方依赖包的管理&#xf…

MATLAB实现单层竞争神经网络数据分类

一.单层竞争神经网络介绍 单层竞争神经网络&#xff08;Single-Layer Competitive Neural Network&#xff09;是一种基于竞争学习的神经网络模型&#xff0c;主要用于数据分类和模式识别。其核心思想是通过神经元之间的竞争机制&#xff0c;使得网络能够自动学习输入数据的特…

Weevely代码分析

亲测php5和php8都无效&#xff0c;只有php7有效 ailx10 1949 次咨询 4.9 网络安全优秀回答者 互联网行业 安全攻防员 去咨询 上一次做weevely实验可以追溯到2020年&#xff0c;当时还是weevely3.7&#xff0c;现在的是weevely4 生成php网页木马依然差不多…… php菜刀we…

【AI大模型】DeepSeek API大模型接口实现

目录 一、DeepSeek发展历程 2023 年&#xff1a;创立与核心技术突破 2024 年&#xff1a;开源生态与行业落地 2025 年&#xff1a;多模态与全球化布局 性能对齐 OpenAI-o1 正式版​ 二、API接口调用 1.DeepSeek-V3模型调用 2.DeepSeek-R1模型调用 三、本地化部署接口调…

具身智能-强化学习-强化学习基础-马尔可夫

文章目录 参考强化学习基础强化学习特点reward函数两种强化学习两种策略&#xff1a;探索&#xff08;Exploration&#xff09; vs. 利用&#xff08;Exploitation&#xff09;gym库的使用 马尔可夫马尔可夫过程马尔可夫奖励过程&#xff08;Markov Reward Process, MRP&#x…

半导体器件与物理篇5 mosfet及相关器件

认识mos二极管 MOS二极管是研究半导体表面特性最有用的器件之一。MOS二极管可作为存储电容器&#xff0c;并且是电荷耦合器件(CCD)的基本结构单元。 MOS二极管结构的重要参数包括&#xff1a;氧化层厚度d&#xff1b;施加于金属平板上的电压V&#xff08;正偏压时V为正&#x…

pandas习题 071:字典元素列表构造 DataFrame

(编码题)以下有一个列表嵌套字典 data,列表中的每个字典 fields 中的列表为每行数据的值,另有一个 col 为列名,利用这两个数据构造一个 DataFrame。 data = [{fields: [2024-10-07T21:22:01, USER-A, 21, 0,

037 DFS回溯

1.回溯模板求排列 2.回溯模板求子集 # 当前位于点x&#xff0c;步长为length def dfs(x,length):passvis[x]length #接下来走下一个点 #判断下一个点是否走过if vis[a[x]]!0:#此时存在环global ansansmax(ans,length-vis[a[x]]1)else:dfs(a[x],length1)nint(input()) a[0]list(…

#systemverilog# Verilog与SystemVerilog发展历程及关系

1. Verilog的发展历史 1984年:Gateway Design Automation公司开发了Verilog,最初作为专有语言,用于逻辑仿真和数字电路设计。 1990年:Cadence收购Gateway,Verilog逐步开放,成为行业标准。 1995年(IEEE 1364-1995):首个IEEE标准,即Verilog-1995,定义基础语法和仿真语…

Kafka流式计算架构

引言 Kafka 凭借其卓越的架构设计&#xff0c;具备极为高效的流式计算能力&#xff0c;在海量数据环境下&#xff0c;依然能够以惊人的速度实现消息的高性能消费&#xff0c;轻松应对高并发、低延迟的严苛业务需求。无论是实时数据处理、复杂事件分析&#xff0c;还是大规模数…

RK3568使用QT搭建TCP服务器和客户端

文章目录 一、让RK3568开发板先连接上wifi二、客户端代码1. `widget.h` 文件2. `widget.cpp` 文件**详细讲解**1. **`Widget` 类构造函数 (`Widget::Widget`)**2. **UI 布局 (`setupUI`)**3. **连接按钮的槽函数 (`onConnectClicked`)**4. **发送消息按钮的槽函数 (`onSendMess…

解决 LeetCode 922 题:按奇偶排序数组 II

解决 LeetCode 922 题&#xff1a;按奇偶排序数组 II 题目描述 给定一个非负整数数组 nums&#xff0c;其中一半整数是奇数&#xff0c;一半整数是偶数。要求对数组进行排序&#xff0c;以便当 nums[i] 为奇数时&#xff0c;i 也是奇数&#xff1b;当 nums[i] 为偶数时&#…

redis教程

Redis 教程 Redis 是一个开源的内存数据结构存储系统&#xff0c;用作数据库、缓存和消息代理。以下是一些基础知识和常用操作。 一、简介 Redis 支持多种数据结构&#xff0c;如字符串、哈希、列表、集合、有序集合等。它具有高性能、高可用性和数据持久化的特性。 二、安…

力扣988. 从叶结点开始的最小字符串

Problem: 988. 从叶结点开始的最小字符串 文章目录 题目描述思路复杂度Code 题目描述 思路 遍历思想(利用二叉树的先序遍历) 在先序遍历的过程中&#xff0c;用一个变量path拼接记录下其组成的字符串&#xff0c;当遇到根节点时再将其反转并比较大小&#xff08;字典顺序大小&…