001_704_二分查找
int count = (left + right) / 2; // 当 left + right 的结果是奇数(除以 2 得小数)时,会直接舍弃小数部分,也就是向下取整(向零取整)
- 正数场景:
5/2 = 2(不是 2.5,也不是 3)、7/2 = 3; - 负数场景:
(-5)/2 = -2(同样截断小数,向零取整,不是 - 3)。
002_27_移除元素
for(int i = 0;i < numsSize;i++) 里的 i++ 是在循环体代码执行完毕后才会执行
for 循环的完整执行流程(核心)
for(表达式1; 表达式2; 表达式3) { 循环体 } 的执行顺序是固定的:
- 第一步 :执行
表达式1(int i = 0)------ 仅在循环开始时执行 1 次,用来初始化变量; - 第二步 :判断
表达式2(i < numsSize)------✅ 如果为真:执行循环体代码;❌ 如果为假:直接退出循环; - 第三步 :循环体执行完毕后,执行
表达式3(i++)------ 这就是 i 自增 1 的时机; - 第四步:回到第二步,重复判断表达式 2,直到为假。
想了半天只想到
cpp
int removeElement(int* nums, int numsSize, int val) {
int count = 0;
for(int i = 0;i < numsSize;i++)
{
if(nums[i] == val)
{
for(int j = i;j < numsSize - 1;j++)
{
nums[j] = nums[j+1];
}
i--;
}
else
{
count ++ ;
}
}
return count;
}
但没有想到如何能不让程序死循环--让数组大小-numsSize也 - 1 !!!
003_977_有序数组的平方
不加排序情况下思考的代码
cpp
int* sortedSquares(int* nums, int numsSize, int* returnSize) {
for(int i = 0;i < numsSize;i++)
{
nums[i] = nums[i] * nums[i];
}
return nums;
}
问题 1:直接修改原数组,不符合 "返回新数组" 的语义
题目要求返回 "新数组",但你直接在传入的nums数组上原地修改,相当于 "破坏了原数组的数据",这是 C 语言编程中非常不规范的做法(调用方可能还需要使用原数组的原始值)。
问题 2:未处理 returnSize 参数
题目中给出的 int* returnSize 是要求你通过这个指针,把新数组的长度返回给调用方(这是这类接口的标准设计),你的代码完全没给它赋值,调用方拿到的会是随机值,无法正确遍历返回的数组。
C语言创建新数组
cpp
//动态分配内存,创建新数组(避免修改原数组)
//向操作系统申请一块能存放 numsSize 个int元素的连续内存,把这块内存的起始地址存到 newNums 指针里 //相当于 "创建了一个长度为 numsSize 的空 int 数组,newNums 就是这个数组的名字"。
int* newNums = (int*)malloc(numsSize * sizeof(int));
if (newNums == NULL) { // 健壮性:检查内存分配是否成功
return NULL;
}
静态数组
cpp
// 1. 定义时直接初始化(长度可省略,编译器自动计算)
int nums[] = {1, 2, 3, 4, 5}; // 长度=5,下标0~4
// 2. 定义时指定长度+初始化(未赋值的元素默认补0)
int arr[6] = {10, 20}; // arr[0]=10, arr[1]=20, arr[2]~arr[5]=0
// 3. 字符数组(字符串)
char str[] = "hello"; // 自动补'\0',长度=6(h e l l o \0)
// 遍历数组
for (int i = 0; i < 5; i++) {
printf("nums[%d] = %d\n", i, nums[i]);
}
变长数组
int arr[n]; // 变长数组,长度由用户输入决定
动态数组
语法 :数据类型* 数组名 = (数据类型*)malloc(长度 * sizeof(数据类型));
(长度可以是变量,内存分配在堆上,用完必须free)
006_203_移除链表元素
原版
cpp
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val) {
ListNode *p = head->next;
while(p != NULL)
{
if(p->val == val)
{
q = p->next;
p->next = q->next;
}
p = p->next;
}
return head;
}
一、错误原因拆解
在 C 语言中,自定义结构体的规则是:
- 直接定义
struct ListNode { ... };后,这个类型的完整名称是struct ListNode,而非ListNode; - C++ 中可以直接用
ListNode,但 C 语言必须加struct关键字,或通过typedef简化。
你的代码第 9 行写了ListNode *p = head->next;,编译器找不到名为ListNode的类型,因此报错 "unknown type name 'ListNode'"。
二、两种修复方案(任选其一)
方案 1:直接加struct关键字(最简单,无需修改结构体定义)
在使用ListNode的地方,都加上struct
方案 2:用typedef给结构体起别名(更简洁,推荐)
提前给struct ListNode定义别名ListNode,后续可直接使用:
007_707_设计链表
cpp
typedef struct {
int val;
MyLinkedList* next;
} MyLinkedList;
一、错误原因:类型引用顺序问题
- 编译器处理顺序是「先解析结构体内部内容,再给匿名结构体起别名
MyLinkedList」; - 当解析到
MyLinkedList* next时,MyLinkedList这个别名还没生效,因此会报「unknown type name 'MyLinkedList'」错误。
简单说:"你想用的别名,在定义它之前就被用到了",这是 C 语言结构体自引用的典型坑。
二、正确的两种写法(任选其一)
方案 1:先命名结构体,再 typedef(最清晰,推荐)
先给结构体起一个 "临时名"(比如Node),内部用struct Node引用,最后 typedef 为MyLinkedList:
cpp
// 第一步:定义带名结构体,内部用struct Node自引用
struct Node {
int val;
struct Node* next; // ✅ 此时struct Node已定义,可正常引用
};
// 第二步:给struct Node起别名MyLinkedList
typedef struct Node MyLinkedList;
方案 2:typedef 和结构体命名合并(更简洁)
把结构体命名和 typedef 写在一起,内部用struct MyLinkedList引用(注意:这里的MyLinkedList是结构体名,不是别名):
cpp
// 核心:结构体名MyLinkedList和别名MyLinkedList同名(合法且常用)
typedef struct MyLinkedList {
int val;
struct MyLinkedList* next; // ✅ 先有struct MyLinkedList定义,再引用
} MyLinkedList;
三、为什么这两种写法能生效?
- 方案 1:
struct Node是完整的类型名,在结构体内部引用时已经存在,编译器能识别; - 方案 2:
struct MyLinkedList是结构体的 "正式名称",内部引用时这个名称已经被声明,后续 typedef 只是给它起了同名别名,逻辑上无冲突。