1.指针深度解析
(1)字符指针与类型转换
定义与赋值:
char c = 'A';
char *p = &c; // p指向字符变量c
printf("%c", *p); // 输出A
(2)指针运算规则
偏移计算:
int arr[5] = {0};
int *p = arr;
p += 3; // 偏移3*sizeof(int)=12字节(假设int为4字节)
运算符优先级:
int x = 10;
int *p = &x;
int y = *p++; // 等价于*(p++),先取*p,后p自增
(3)空指针与野指针
空指针定义:
int *p = NULL; // 表示指针未指向有效地址
if (p != NULL) // 安全操作
{
*p = 10;
}
禁止操作:
NULL + 1; // 编译错误
*NULL; // 运行时崩溃(段错误)
2.快速排序算法实现
(1)算法步骤
选取基准:通常选第一个元素
分区操作:从右向左找第一个小于基准的元素,从左向右找第一个大于基准的元素,交换这两个元素,重复直至左右指针相遇
递归处理:对基准左右子数组重复上述过程
(2)复杂度分析
平均时间复杂度:O(n log₂n)
最坏情况(已排序数组):O(n²)
3.地址运算规则
(1)合法操作
地址相减(同类型指针):
int arr[5] = {0};
int *p1 = &arr[0], *p2 = &arr[3];
int diff = p2 - p1; // diff=3(相差3个int元素)
比较运算:
if (p1 < p2) { ... } // 判断地址先后
(2)非法操作
地址相加:
int *p3 = p1 + p2; // 编译错误!
不同类型指针运算:
char *pc = (char*)p1;
int diff = pc - p1; // 结果无意义(类型不同)
4.练习
1)判断存储方式
int main(void)
{
int i = 10;
char *p;;
p = (char *)&i;
if(*p == 10)
{
printf("小端存储\n");
}
else
{
printf("大端存储");
}
return 0;
}
2)数组相关操作
void printArray(int *a, int len)
{
int i;
for(i = 0; i < len; ++i)
{
printf("%d\n", *(a + i));
}
}
int maxOfArray(int *a, int len)
{
int i;
int max = *a;
for(i = 0; i < len; ++i)
{
if(max < *(a + i))
{
max = *(a + i);
}
}
return max;
}
void swap(int *a, int *b)
{
int t;
t = *a;
*a = *b;
*b = t;
}
void reverseArray(int *a, int len)
{
int i;
for(i = 0; i < len / 2; ++i)
{
swap(a + i, a + len - i - 1);
}
}
void sort(int *a, int len)
{
int i, j;
for(i = 0; i < len -1; ++i)
{
for(j = i + 1; j < len; ++j)
{
if(*(a + i) > *(a + j))
{
swap(a + i, a + j);
}
}
}
}
int *binaryFind(int *a, int len, int n)
{
int begin = 0;
int end = len -1;
int mid;
while(begin <= end)
{
mid = (begin + end) / 2;
if(*(a + mid) > n)
{
end = mid - 1;
}
else if(*(a + mid) < n)
{
begin = mid + 1;
}
else
{
return a + mid;
}
}
return NULL;
}
int main(void)
{
int a[] = {1,2,3,4,5,6,11,12,9,0};
int len = sizeof(a) / sizeof(a[0]);
sort(a, len);
int n = -12;
int *p;
p = binaryFind(a, len, n);
if(p != NULL)
{
printf("%p\n", p);
}
else
{
printf("Error\n");
}
return 0;
}
3)数组高级版
void printArray(int *begin, int *end)
{
while(begin <= end)
{
printf("%d\n", *begin);
++begin;
}
}
void swap(int *a, int *b)
{
int t;
t = *a;
*a = *b;
*b = t;
}
void reverseArray(int *begin, int *end)
{
if(begin >= end)
{
return;
}
else
{
swap(begin, end);
reverseArray(begin + 1, end - 1);
}
}
4)排序算法
快速排序 (Qsort
)
void Qsort(int *begin, int *end)
{
if(begin >= end)
{
return;
}
int t = *begin;
int *q = end;
int *p = begin;
while(p < q)
{
while(p < q && *q >= t)
{
--q;
}
while(p < q && *p <= t)
{
++p;
}
swap(p, q);
}
swap(begin, p);
Qsort(begin, p - 1);
Qsort(p + 1, end);
}
选择排序 (choiceSort
)
void choiceSort(int *begin, int *end)
{
int *p;
for(; begin < end; ++begin)
{
for(p = begin + 1; p <= end; ++p)
{
if(*begin > *p)
{
swap(begin, p);
}
}
}
}
冒泡排序 (bubbleSort
)
void bubbleSort(int *begin, int *end)
{
int *p;
for(; end > begin; --end)
{
for(p = begin; p < end; ++p)
{
if(*p > *(p + 1))
{
swap(p, p + 1);
}
}
}
}
插入排序 (inserSort
)
void inserSort(int *begin, int *end)
{
int *p;
int *q;
for(p = begin + 1; p <= end; ++p)
{
int t = *p;
q = p;
while(q > begin && *(q - 1) > t)
{
*q = *(q - 1);
--q;
}
*q = t;
}
}
5)二分查找
非递归版
int *binaryFind(int *begin, int *end, int n)
{
while(begin <= end)
{
int * mid;
mid = (end - begin) / 2 + begin;
if(*mid > n)
{
end = mid - 1;
}
else if(*mid < n)
{
begin = mid + 1;
}
else
{
return mid;
}
}
return NULL;
}
递归版
int *binaryFindStrings(int *begin, int *end, int n)
{
if(begin > end)
{
return NULL;
}
int *mid = begin + (end - begin) / 2;
if(*mid == n)
{
return mid;
}
else if(*mid > n)
{
return binaryFindStrings(begin, mid - 1, n);
}
else
{
return binaryFindStrings(mid + 1, end, n);
}
}
测试用的main函数
int main(void)
{
int a[] = {1,2,3,-4,5,-6,7,8,9,0};
int len = sizeof(a) / sizeof(a[0]);
inserSort(a, a + len - 1);
int n = 9;
int *p = binaryFindStrings(a, a + len - 1, n);
if(p)
{
printf("found mid = %p\n", p);
}
else
{
puts("not found");
}
return 0;
}
5.总结
- 指针安全:避免野指针,初始化为
NULL。
类型匹配是地址运算的前提 - 快速排序核心:分治思想 + 递归实现,基准选择影响效率
- 嵌入式注意:避免深度递归导致栈溢出(可改用迭代版快速排序)。指针运算需严格对齐内存