再学习《C程序设计语言》
作为有 C 语言基础的学习者,我整理《C 程序设计语言 第二版》(2004 年版本)这本旧书时倒没费太多功夫。不过得说句实话,这本书里的内容和现在的 C 语言差异不小。要是你刚入门,我真心不建议只啃这本书单打独斗,多去逛逛开源社区,看看大佬们写的开源项目,在实战里摸索,收获肯定比光看书多得多! 导言类型、运算符与表达式控制流函数与程序结构指针与数组结构输入与输出导言:类型、运算符与表达式:控制流:函数与程序结构:指针与数组:结构:输入与输出: 通读此书后,我深刻意识到,书中函数实现的思想内核才是真正的精华所在,这些精妙的思维方式远比单纯的知识罗列更具价值。书中设置的习题也颇具匠心,对编程学习有浓厚兴趣的同学,若能深入钻研,定能收获颇丰。 此次阅读既是学习新程,也是对旧知的梳理与巩固。浏览过程中,许多熟悉的概念重焕清晰,还挖掘出不少被忽略的细节,让知识体系更加完善。虽暂时仅完成主体内容复习,但这只是新起点。后续我会合理规划时间,认真解答课后习题,通过练习让书中思想落地生根,将理论转化为实践能力,稳步前行在编程之路上。
Leecode 0004. Median of Two Sorted Arrays
4. Median of Two Sorted Arrays题目There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)). You may assume nums1 and nums2 cannot be both empty. Example 1: nums1 = [1, 3] nums2 = [2] The median is 2.0 Example 2: nums1 = [1, 2] nums2 = [3, 4] The median is (2 + 3)/2 = 2.5 题目大意给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m +...
Leecode 0007. Reverse Integer
7. Reverse Integer题目Given a 32-bit signed integer, reverse digits of an integer. Example 1: Input: 123 Output: 321 Example 2: Input: -123 Output: -321 Example 3: Input: 120 Output: 21 **Note:**Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−2^31, 2^31 − 1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows. 题目大意给出一个 32 位的有符号整数,需要将这个整数中每位上的数字进行反转。注意:假设我们的环境只能存储得下 32...
Leecode 0005. Longest Palindromic Substring
5. Longest Palindromic Substring题目Given a string s, return the longest palindromic substring in s. Example 1: 1234Input: s = "babad"Output: "bab"Note: "aba" is also a valid answer. Example 2: 123Input: s = "cbbd"Output: "bb" Example 3: 123Input: s = "a"Output: "a" Example 4: 123Input: s = "ac"Output: "a" Constraints: 1 <= s.length <= 1000 s consist of only digits and English letters...
C语言实现二叉搜索树(BST):从增删改查到三种遍历的完整解析
引言二叉搜索树(Binary Search Tree, BST)是一种经典的动态数据结构,因其高效的查找、插入和删除操作(平均时间复杂度O(logn)),广泛应用于数据库索引、缓存系统、排序算法等领域。本文将基于C语言实现一个完整的BST,详细解析其核心原理、关键操作及三种遍历方式,并通过测试用例验证功能正确性。 一、BST基础概念:定义与核心性质1.1 BST的定义二叉搜索树(BST)是一种特殊的二叉树,满足以下性质: 左子树性质:对于任意节点,其左子树中所有节点的键值均小于该节点的键值。 右子树性质:对于任意节点,其右子树中所有节点的键值均大于或等于该节点的键值(注:部分定义要求严格大于,本文采用“大于等于”以支持重复值处理)。 递归结构:左子树和右子树本身也是BST。 1.2...
用C语言文件流实现轻量级图书管理系统:从0到1的实战解析
引言在C语言的学习过程中,文件操作是一个绕不开的核心技能。无论是保存用户数据、记录日志,还是实现小型系统,“如何将数据持久化到本地”都是必须解决的问题。今天,基于之前写的轻量级图书管理系统,通过文件流复现,带你深入理解C语言文件流的核心概念(如文件指针、文本/二进制模式、文件读写逻辑),并展示如何用文件流替代内存存储,解决小型系统的实际需求。 一、为什么选择文件流?——对比内存存储的局限性在开发小型系统时,我们可能会先用数组或链表在内存中存储数据。但内存存储存在两个致命问题: 临时性:程序退出后,内存数据会被操作系统回收,无法长期保存。 容量限制:内存大小有限(如32位系统约4GB),无法处理大规模数据。 而文件流(File...
动态哈希表:从0到1解析C语言动态数组+链表冲突解决方案
引言哈希表(Hash Map)是一种高效的数据结构,通过哈希函数将键映射到数组索引,实现O(1)时间复杂度的插入、查询和删除操作。但传统静态哈希表(固定容量数组)存在空间浪费(数据少时数组空置)和冲突频发(数据多时哈希碰撞概率激增)的痛点。本文将基于C语言,手把手实现一个动态哈希表,通过「动态数组+链表」的组合方案解决这些问题,并深入解析核心设计与实现细节。 一、设计背景:为什么选择「动态数组+链表」?1.1 传统静态哈希表的痛点传统哈希表通常使用固定大小的数组存储键值对,通过哈希函数计算索引。但这种设计存在两大缺陷: 空间浪费:若初始容量过大,数据稀疏时大量数组空间闲置;若初始容量过小,数据增多时频繁扩容(需重新哈希所有数据),效率低下。 冲突频发:当数据量超过数组容量时,哈希碰撞概率激增,链表法(拉链法)虽能解决冲突,但链表过长会导致查询时间退化为O(n)。 1.2...
C语言文件流:从字符到二进制的三种高效实现
引言在C语言中,文件操作是处理数据存储与传输的核心能力。无论是文本文件还是二进制文件(如图片、视频),复制操作都是最常见的需求。但不同场景下,选择不同的复制方式会直接影响程序的性能与数据完整性。本文将结合三种经典复制实现(字符复制、按行复制、二进制复制),深入解析文件流的核心机制,并给出实战优化建议。 一、文件流基础:文本模式vs二进制模式1.1 文件打开模式的选择C语言中,fopen函数的第二个参数(模式)决定了文件的读写方式。最常用的模式有: 文本模式("r"/"w"/"a"):以字符形式读写,自动处理换行符转换(如Windows的\r 转Unix的 )。 二进制模式("rb"/"wb"/"ab"):以字节形式直接读写,不进行任何转换。 1.2...
Leecode 0003. Longest Substring Without Repeating Characters
3. Longest Substring Without Repeating Characters题目Given a string, find the length of the longest substring without repeating characters. Example 1: 123Input: "abcabcbb"Output: 3 Explanation: The answer is "abc", with the length of 3. Example 2: 123Input: "bbbbb"Output: 1Explanation: The answer is "b", with the length of 1. Example 3: 1234Input: "pwwkew"Output: 3Explanation: The answer is "wke", with the length of 3. ...
Leecode 0001.two sum
1. Two Sum题目Given an array of integers, return indices of the two numbers such that they add up to a specific target. You may assume that each input would have exactly one solution, and you may not use the same element twice. Example: 1234Given nums = [2, 7, 11, 15], target = 9,Because nums[0] + nums[1] = 2 + 7 = 9,return [0, 1]. 题目大意在数组中找到两个数,它们的和等于给定的目标值 target,并返回这两个数在数组中的下标。要求每个元素只能使用一次,且保证有且仅有一个解。 解题思路方法一:双层循环(暴力枚举)思路 通过双重循环遍历数组中的每一对元素,检查它们的和是否等于目标值 target。外层循环控制第一个元素的索引...
Leecode 0002. Add Two Numbers
2. Add Two Numbers题目You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list. You may assume the two numbers do not contain any leading zeros, except the number 0 itself. Example 1: 123Input: l1 = [2,4,3], l2 = [5,6,4]Output: [7,0,8]Explanation: 342 + 465 = 807. Example 2: 12Input: l1 = [0], l2 = [0]Output: [0] Example...
从0到1实现C语言哈希表:底层原理与实战解析
引言在C语言的标准库中,没有像C++ unordered_map或Java HashMap这样现成的哈希表容器。当我们需要在C中实现高效的键值对存储时,手动实现一个哈希表是绕不开的选择。本文将以我近期实现的轻量级哈希表为例,从数据结构设计、核心逻辑解析到内存管理,带您深入理解哈希表的底层原理,并结合实际测试用例验证其正确性。 一、为什么需要自己实现哈希表?在开始代码解析前,先聊聊为什么选择手动实现哈希表: 场景适配:标准库未提供通用哈希表(C++的unordered_map依赖模板,无法直接用于纯C项目)。 性能可控:手动实现可以针对具体场景优化(如自定义哈希函数、内存分配策略)。 学习价值:理解哈希表的核心原理(哈希冲突、负载因子、动态扩容),是进阶C语言开发的必经之路。 本文的哈希表实现定位为轻量级字符串键值对存储,适用于配置管理、缓存系统等需要快速查找的场景。 二、数据结构设计:从抽象到具体2.1...
从基础到进阶:常见排序算法的C语言实现与深度解析
引言排序算法是计算机科学中最基础且重要的算法之一,广泛应用于数据库查询、日志处理、数据统计等场景。理解不同排序算法的核心思想、时间复杂度及适用场景,不仅能帮助我们写出更高效的代码,还能在实际工程中根据需求选择最优方案。 本文将以C语言实现为切入点,深入解析插入排序、希尔排序、归并排序、快速排序(双向优化)、堆排序五大经典算法,结合代码逐行分析其底层逻辑,并通过测试用例验证正确性。文末附完整可运行源码。 一、插入排序:从“摸牌”到有序1.1 算法思想插入排序的核心思想是将未排序元素逐个插入到已排序序列的正确位置,类似于整理扑克牌的过程:初始时左手为空(已排序序列),每次从桌面(未排序序列)取一张牌,插入左手已有牌中的正确位置。 1.2 代码实现与解析插入排序代码如下(已修正注释格式): 123456789101112131415void insertion_sort(int arr[], int len) { for (int i = 1; i < len; i++) { // 从第2个元素开始(索引1) if...
C语言单链表操作详解(含二级指针深度解析)
一、简介本文档详细解析一段C语言单链表操作的代码,涵盖头插法插入节点、尾插法插入节点、修改头节点值和打印链表四大核心功能。重点讲解二级指针在链表操作中的作用,帮助理解动态内存管理与指针操作的核心逻辑。 二、前置知识:二级指针的本质2.1 什么是二级指针? 一级指针(Node *head):存储某个节点的内存地址(指向节点)。 二级指针(Node **head):存储一级指针的内存地址(指向“指向节点的指针”)。 2.2 为什么链表操作需要二级指针?在C语言中,函数参数传递是值传递。若链表头指针(head)通过一级指针传递,函数内部对head的修改(如让它指向新节点)只会影响函数的局部副本,外部头指针不会改变。 示例对比: 错误写法(一级指针): 12345void insert_head(Node *head, ElementType new_val) { Node *new_node = calloc(1, sizeof(Node)); new_node->next = head; head = new_node; //...
C语言数组与指针深度解析
引言:为什么需要理解数组与指针的差异?在C语言中,数组和指针是最基础且容易混淆的概念。尤其是*p[](指针数组)和(*p)[](数组的数组)的语法差异,涉及类型优先级、内存布局和操作方式的本质区别。本文通过具体代码示例,结合fruits1(二维数组)和fruits2(指针数组)的对比,深入解析两者的核心差异,并探讨实际开发中的应用场景。 核心概念:*p[]与(*p)[]的类型优先级C语言中,运算符优先级决定了表达式的解析顺序。其中,[](下标运算符)的优先级高于*(解引用运算符)。因此: *p[]会被解析为*(p[]),即数组的指针(指针数组):数组的每个元素是指针; (*p)[]会被解析为(*p)[],即数组的数组(二维数组):数组的每个元素是另一个数组。 用户代码中的fruits1和fruits2正是这两种类型的典型代表: 12char fruits1[][10] = { "apple", "banana", "cherry" }; // 二维数组(数组的数组)char...
C语言实现汉诺塔问题:从递归逻辑到代码解析
引言:为什么需要学习汉诺塔?汉诺塔(Hanoi Tower)是计算机科学中最经典的递归问题之一,由法国数学家爱德华·卢卡斯于1883年提出。它不仅是理解递归思想的绝佳案例,更是培养算法思维的基础。本文将通过C语言实现汉诺塔问题的递归解法,详细解析其核心逻辑,并探讨如何通过代码验证和优化提升程序的健壮性。 问题背景:汉诺塔的规则与目标汉诺塔问题描述如下: 假设有3根柱子(起始塔A、辅助塔B、目标塔C),初始时A塔上有n个盘子,按大小顺序从上到下叠放(大盘子在下,小盘子在上)。目标是将所有盘子从A塔移动到C塔,移动过程中需遵守以下规则: 每次只能移动一个盘子; 大盘子不能直接放在小盘子上(即任何时刻,小盘子必须在大盘子之上)。 最少移动步数:对于n个盘子,最少需要2^n - 1步(数学归纳法可证)。 代码核心:递归解法的逻辑拆解代码通过递归函数move实现了汉诺塔的移动步骤输出,并计算了最少步数。以下是代码的核心部分: 1234567891011121314151617181920212223242526272829#define...
C语言命令行参数处理
引言:为什么需要处理命令行参数?在开发命令行工具时,我们经常需要通过参数传递输入数据或配置选项。例如,一个计算器工具可能需要接收两个数值作为输入,一个文本处理工具可能需要指定输入文件路径。C语言中,main函数的argc和argv参数是处理命令行输入的核心接口。本文将通过一个具体案例,详细解析如何从命令行参数中读取数据、进行数值计算,并输出结果。 核心功能:命令行参数的读取与处理用户提供的代码实现了以下核心功能: 读取命令行参数数量(argc)并打印; 遍历所有命令行参数(argv)并打印每个参数的内容; 从指定参数中解析数值(整数num1和浮点数num2); 计算两数之和并格式化输出结果; 使用第四个参数作为结果的描述字符串。 代码逐行解析:从参数获取到结果输出1. main函数参数:argc与argvC语言中,main函数的标准形式为int main(int argc, char *argv[]),其中: argc(Argument Count):命令行参数的数量(包含程序名本身); argv(Argument...
Vector动态数组复现
引言:为什么需要动态数组?在C语言中,静态数组的大小在编译时确定,无法根据运行时需求动态调整。当数据量不确定或需要频繁插入/删除元素时,静态数组会暴露出明显缺陷:要么浪费内存(声明过大),要么溢出(声明过小)。动态数组(Vector)通过堆内存分配和自动扩容机制,完美解决了这一问题。它支持灵活的元素插入、删除,且内存使用更高效,是实现栈、队列等高级数据结构的基础。 核心结构:Vector的设计哲学结构体定义:封装底层细节代码中的Vector结构体通过三个字段封装了动态数组的核心状态: 12345typedef struct { ElemType *table; // 指向堆空间的数组(存储实际元素) int size; // 当前元素个数(逻辑长度) int capacity; // 数组的最大容量(物理长度)}...
C语言位运算
引言:为什么需要掌握位运算?在计算机底层,所有的数据都以二进制形式存储和处理。位运算(Bitwise Operations)作为直接操作二进制位的工具,是高性能计算、嵌入式开发、算法优化的核心技能。今天我们将通过一个实际案例,深入理解**与(&)、或(|)、异或(^)、取反(~)、移位(<<、>>)**等位运算的应用场景,并实现一组实用的位操作函数。 位运算基础:二进制视角下的数字要掌握位运算,首先需要理解二进制数的表示规则: 最低有效位(LSB):二进制数的最右边一位(2⁰位),决定数的奇偶性; 高位:从右往左依次为2¹、2²...2ⁿ位,每一位代表2的幂次; 补码表示:负数在内存中以补码形式存储(原码取反+1),这是位运算处理负数的关键。 实战函数解析:逐个击破位运算问题1. 判断奇数:最低位的「1」密码问题描述:判断一个整数是否为奇数。...
主题修改记录
二零二五年 二月一日 Hexo 主题封面大改造:从失效链接到宫崎骏风 AI 图这篇主题修改的文章好多年不打开了(其实大部分博客都不怎么重新修正,反正是写给自己的),年久失修,许多封面图片链接失效,只剩破碎图标。为重塑博客风采,假借藏书之家,拜谢AI大人,统一更换封面(全用本地图片改起来还好,但终归让人头秃) 二零二二年 六月十一日 Hexo...