From 50a8b60bc536bc9a9a00ccbd54efa9c48b6bae4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E5=A4=A7=E4=BB=99?= <1900919313@qq.com> Date: Thu, 8 Aug 2024 17:21:30 +0800 Subject: [PATCH] c --- docs/notes/01_c-basic/01_xdx/index.md | 30 ++++++ docs/notes/01_c-basic/06_xdx/index.md | 129 ++++++++++++++++---------- 2 files changed, 110 insertions(+), 49 deletions(-) diff --git a/docs/notes/01_c-basic/01_xdx/index.md b/docs/notes/01_c-basic/01_xdx/index.md index 761bd1f..674eaa6 100644 --- a/docs/notes/01_c-basic/01_xdx/index.md +++ b/docs/notes/01_c-basic/01_xdx/index.md @@ -2110,3 +2110,33 @@ cp perf /usr/bin/ ![](./assets/196.png) ![](./assets/197.png) + +## 9.7 C 语言的学习技巧 + +* 对于大部分的初学者, 学习 C 语言的目的可能是为了成为一名合格的程序员,开发出优秀的软件。但是,在学习了 C 语言的基本语法后,却发现只能在`控制台`(`黑底白字`)上玩玩,没有漂亮的用户界面以及优化、人性化的交互。于是,开始学习数据结构、算法、数据库、操作系统,越陷越深,越来越迷茫,不知道学习 C 语言能做什么,认为学习编程很难,开始怀疑自己,直到放弃!!! +* 其实,C 语言本身就是一门非常简单的语言,提供的实用功能不多,大部分的时候需要`借助`操作系统、第三方库以及以及一些硬件才能发挥它的威力!!! + +> [!IMPORTANT] +> +> * ① 学习 C 语言仅仅是让你踏上程序员之路的第一步而已,只学习 C 语言也做不了什么。 +> * ② 系统、扎实的学习 C 语言可以让你了解底层硬件、一些简单的数据结构和算法,并培养计算机思维。 + +* C 语言是一门通用性的语言,并没有针对某个领域进行优化,在实际项目中,C 语言主要用于较底层的开发,例如: + * Windows、Linux、Unix 等操作系统的内核 90% 以上都使用 C 语言开发。 + * 开发硬件驱动,让硬件和操作系统连接起来,这样用户才能更有效的使用硬件。 + * 单片机和嵌入式属于软硬件的结合,是使用 C 语言最多的地方。 + * 开发系统组件或服务,用于支撑上层应用。 + * …… +* 既然 C 语言的应用很多,为什么感觉学习它还是做不了什么?答案就是`生态`。 + +> [!IMPORTANT] +> +> 现代化的高级编程语言的流行程度,除了和编程语言的设计是否优秀有关,最主要的原因就是`生态`。 +> +> * ① 很多编程语言都自带`标准库`(语言本身提供的,开箱即用),如:Java、Go 等。 +> * ② 很多编程语言都有自己的`包管理器`(用于管理第三方库)解决方案,如:Java 中的 Maven、Gradle、Go 中的 go modules ,JavaScript 的 npm 等。 +> +> 遗憾的是,C 语言的`标准库`非常简单,如:输入输出、文件操作、日期时间、字符串处理、内存管理等。C 语言的`第三方库`也非常稀少,更别提缺少自己的包管理器。 +> +> 不过,现在 C 语言社区也开始诞生了一些包管理器,如:Conan 和 vcpkg ;也有自己的项目构建工具,如:cmake 、xmake 等。 + diff --git a/docs/notes/01_c-basic/06_xdx/index.md b/docs/notes/01_c-basic/06_xdx/index.md index 45d768d..cbf93e6 100644 --- a/docs/notes/01_c-basic/06_xdx/index.md +++ b/docs/notes/01_c-basic/06_xdx/index.md @@ -300,74 +300,105 @@ int main() { > > 下文中提及的`指针`都是`指针变量`,不再阐述!!! +## 3.3 指针变量的定义 -## 3.2 普通变量和指针变量的区别 -在 CLion 中使用 GDB 调试时,可以通过反编译代码来查看指针变量和普通变量的区别。下面是具体的步骤: -### 设置 GDB 调试器 -1. 打开 CLion,并加载你的项目。 -2. 确保你使用的是带有 GDB 支持的工具链(如 GCC 工具链)。 -3. 在 CLion 的设置中,确保调试器设置为 GDB。 -### 编译你的代码 -确保在编译你的代码时使用了调试信息生成选项(如 `-g`)。你可以在 CMakeLists.txt 文件中添加以下行: +## 3.4 指针的作用 -```cmake -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") +* 查询数据。 +* 存储数据。 +* 参数传递。 +* 内存管理。 + + + + + + + +在 Java 中,引用数据类型的向上类型转换(upcasting)和向下类型转换(downcasting)是面向对象编程中常见的操作。这些转换是 Java 继承体系和多态性的重要部分。我们先分别介绍向上类型转换和向下类型转换,然后讨论它们在 C 语言中指针的类似操作。 + +### 向上类型转换(Upcasting) + +向上类型转换是将一个子类对象引用转换为父类对象引用。由于子类继承了父类的所有方法和属性,子类对象也包含父类对象的所有部分,因此这种转换是安全且隐式的。 + +**例子:** +```java +class Animal { + void makeSound() { + System.out.println("Animal sound"); + } +} + +class Dog extends Animal { + void makeSound() { + System.out.println("Bark"); + } +} + +public class Main { + public static void main(String[] args) { + Dog dog = new Dog(); + Animal animal = dog; // Upcasting, 隐式转换 + animal.makeSound(); // 输出:Bark + } +} ``` +在这个例子中,`Dog` 类型的对象 `dog` 被转换为 `Animal` 类型。尽管 `animal` 引用的实际对象是 `Dog`,但在编译时,`animal` 被视为 `Animal` 类型。 -### 开始调试 -1. 设置断点:在代码中你想要查看变量的地方设置一个断点。 -2. 启动调试:点击调试按钮启动调试会话。 +### 向下类型转换(Downcasting) -### 查看变量 -当调试器在断点处暂停时,你可以在调试控制台中使用 GDB 命令来查看变量。以下是一些常用的 GDB 命令: +向下类型转换是将一个父类对象引用转换为子类对象引用。由于父类对象不一定具有子类的所有方法和属性,因此这种转换需要显式进行,并且在运行时进行类型检查(使用 `instanceof` 关键字来确保安全)。 -- `print variable_name`:打印变量的值。 -- `info locals`:打印当前作用域中的所有局部变量。 -- `whatis variable_name`:显示变量的类型。 +**例子:** +```java +public class Main { + public static void main(String[] args) { + Animal animal = new Dog(); // Upcasting + if (animal instanceof Dog) { + Dog dog = (Dog) animal; // Downcasting, 显式转换 + dog.makeSound(); // 输出:Bark + } + } +} +``` +在这个例子中,`animal` 引用的对象实际是 `Dog` 类型,在向下转换之前使用 `instanceof` 检查以确保安全。 -### 区分指针变量和普通变量 -指针变量和普通变量的主要区别在于它们的类型和存储的内容。指针变量存储的是地址,而普通变量存储的是实际的值。通过 GDB 命令可以很容易地看到这种区别。 +### 区别 -#### 示例 -假设有如下代码: +- **向上类型转换**:隐式的,安全的,因为子类是父类的扩展。 +- **向下类型转换**:显式的,可能不安全,需要运行时检查,因为父类不一定具有子类的特性。 -```cpp -#include +### C 语言中的指针转换 + +在 C 语言中,指针的转换类似于引用类型的转换,但由于 C 语言没有继承和多态的概念,其转换更多是基于内存布局。 + +**例子:** +```c +#include + +void printInt(void* ptr) { + printf("%d\n", *(int*)ptr); +} int main() { - int a = 10; - int *p = &a; - std::cout << "a: " << a << ", p: " << p << std::endl; + int x = 10; + void* voidPtr = &x; // Upcasting, 隐式转换 + printInt(voidPtr); // 输出:10 + + int* intPtr = (int*)voidPtr; // Downcasting, 显式转换 + printf("%d\n", *intPtr); // 输出:10 return 0; } ``` +在这个例子中,`void*` 是通用指针类型,可以指向任何类型的数据。将 `int*` 转换为 `void*` 是隐式的,而将 `void*` 转换为 `int*` 是显式的。由于 C 没有类型检查,因此这种转换需要程序员自己确保安全。 -在 CLion 中设置断点并开始调试,程序将在 `std::cout` 行暂停。此时在调试控制台中输入以下命令: - -- `print a`:输出变量 `a` 的值,应该是 `10`。 -- `print p`:输出指针变量 `p` 的值,即 `a` 的地址。 -- `print *p`:输出指针 `p` 指向的值,即 `10`。 - -通过这些命令,你可以看到指针变量 `p` 实际上存储的是一个地址,而普通变量 `a` 存储的是一个整数值。 - -#### 使用反汇编 -在某些情况下,你可能需要查看反汇编代码来更深入地理解变量的存储方式。使用以下命令可以查看当前函数的反汇编代码: - -- `disassemble`:反汇编当前函数的代码。 -- `x/4wx &a`:查看变量 `a` 的内存内容。 - -### 总结 -在 CLion 中使用 GDB 调试时,通过查看变量值和反汇编代码,可以清楚地区分指针变量和普通变量。指针变量存储地址,而普通变量存储实际的值,通过适当的 GDB 命令可以轻松辨别两者的区别。 - - - - - - +总结: +- Java 中的向上类型转换和向下类型转换是为了支持多态性和继承,向上转换是安全的,向下转换需要显式进行并且进行运行时检查。 +- C 语言中的指针转换没有多态性和继承的概念,但有类似的指针类型转换操作,程序员需要确保转换的安全性。