☰
C语言学习笔记十二 —— 指针补充(多指针 · 野指针 · void* · 排序查找指针版 · const · 字符串)
2026/10/1 21:32:49 网站建设 项目流程

一、指针补充

1. 定义多个指针变量

int*p;// 定义一个指针变量 pint*p,*q,*r;// 一次定义多个指针变量// * 是起修饰作用:修饰变量名,表示该变量是指针类型变量,而不是普通变量inta,b,c,*p,*q;// 普通变量和指针变量可以混合定义

注意:定义时*是修饰(用来说明是指针变量),不是在取值!

2. 野指针

野指针:指针指向不明确。

  • a. 指针变量未初始化——变量中可能是随机值 → 指针指向不明确(野指针)。
int*p;// 野指针!p 里是随机值,不知道指向哪里

3. NULL —— 空地址(0号地址)

为了避免野指针,定义指针时先赋 NULL:

int*p=NULL;// 表示 p 的指向是明确的(空地址 0号地址)
  • NULL 就是 0 号地址(空地址);
  • 判断指针是否有效:if (p == NULL) { ... }。

4. void* —— 万能指针

void// 空类型void*// 空类型指针 —— 万能指针(可以接收任意类型的地址)
inta=10;void*p=&a;// void* 可以指向任意类型

5. & 与 * 互为逆运算

inta=10;int*p=&a;&*p// 等价于 &(*p) == p// & 与 * 互为逆运算:先解引用再取地址,等于 p 本身

二、排序(指针版思路)

1. 选择排序

思想:给合适的位置选择合适的数。

// 迭代的方式实现// begin —— 起始位置(指针)// end —— 结束位置(指针)for()// 用地址代表元素的位置,条件 begin < end{for(p=begin+1;p<=end;){if()// p 位置上的值和 begin 位置上的值比较{swap();// 交换}}}
voidselectArray(int*begin,int*end){int*p=NULL;for(begin;begin<=end;++begin){for(p=begin+1;p<=end;++p){if(*p<*begin){intt=*p;*p=*begin;*begin=t;}}}}

2. 冒泡排序

思想:相邻两个元素两两相比,小的放前,大的放后。

for()// 控制趟数 —— 每一趟结束冒出一个数(最大值冒到最后){for(?)// 一趟的比较过程(从开头到结束位置){if()// 相邻比较{swap();// 交换}}}
voidmp(int*begin,int*end){int*p=NULL;int*b=begin;int*e=end;for(begin;begin<e;++begin,--end){for(p=b;p<end;++p){if(*(p+1)<*p){intt=*(p+1);*(p+1)=*p;*p=t;}}}}

3. 插入排序

思想:从无序区拿数据,插入到有序区。步骤:① 拿数 ② 找位置 ③ 插入。

for()// 通过指针拿数(begin 起始位置){// 1. t 拿数// 2. int *q 准备要插入的位置while(q>begin&&*(q-1)>t)// 前面的数比 t 大就往后挪{}*q=t;// 插入到正确位置}
voidcr(int*begin,int*end){int*p=begin;int*q=NULL;for(p=begin;p<=end;++p){intt=*p;q=p;while(q>begin&&*(q-1)>t){*q=*(q-1);--q;}*q=t;}}

三、查找:二分查找(指针版)

begin end// 0 1 2 3 4 5 6// b e// 1 2 3 4 5 6 8mid=begin+(end-begin)/2;// 中间位置if(*mid>n)// 要找的比中间小 → 去前半段{end=mid-1;}elseif(*mid<n)// 要找的比中间大 → 去后半段{begin=mid+1;}else// 找到了{}

返回值:

  • mid(int*)—— 找到了,返回位置指针;
  • NULL—— 空指针,没找到。

int*binaryFind(int*begin,int*end,intn){int*mid=NULL;int*ret=NULL;while(begin<=end){int*mid=begin+(end-begin)/2;if(*mid>n){end=mid-1;}elseif(*mid<n){begin=mid+1;}else{ret=mid;break;}}returnret;}

四、快速排序

用到的知识:① 指针 ② 递归 ③ 迭代

思想:分而治之——选一个基准值,把比它小的放左边、比它大的放右边,然后对左右两部分递归。

voidquickSort(int*begin,int*end){int*p=begin;int*q=end;//1.找基准值首元素int*k=begin;if(begin>=end)//7.递归结束的条件,当begin与end错开或者相遇{return;}while(begin<end)//5.{//2.从右往左找到第一个比基准值小的while(begin<end&&*end>=*k){--end;}//3.从左往右找第一个比基准值大while(begin<end&&*begin<=*k){++begin;}//4.找到以后交换这两个值(2和3的)swap(begin,end);//5.重复2~4,直到begin与end相遇}//6.将相遇位置上的值与基准值交换swap(begin,k);//7.递归下去quickSort(p,end-1);//小的一部分quickSort(begin+1,q);//大的一部分}

五、小结

  1. 指针操作整型一维数组;
  2. 指针很灵活:
    • 指针可以代表位置;
    • 指针也可以实现间接访问。

六、指针操作字符型一维数组

字符串本身也是按照字符型一维数组的方式存储到计算机中——字符串是一种特殊的字符型一维数组。

chars[]="hello";// 操作字符串

指针操作 s 中的数据,只需要获得首元素地址:

s[0]// char 类型&s[0]// char *char*p=&s[0];// p 指向首元素=s;// 数组名就是首元素地址,等价写法

七、const 修饰符

const:表示将所修饰的变量限定为只读。

修饰原则:就近原则——离谁近,就限定谁。

inta;// 普通变量,可读可写constinta;// a 此时只读,不能修改constchar*p;// 限定通过 *p 方式访问基类型为只读(*p 不能修改基类型)charconst*p;// 同上,等价写法char*constp;// 限定 p 本身为只读(p 不能被修改,不能换指向)constchar*constp;// p 不能被修改,*p 也不能被修改

const 在函数参数中的应用

intputs(constchar*s);// const char *s —— 设计函数的一种方式

puts 函数:功能是把 s 中的字符串输出。

建议:如果函数只是做读操作,参数建议写成 const 形式:

  • 好处:避免出问题,出问题也能及早发现;
  • 提高参数的适用性。

能传什么给const char *参数:

char*// 指针数组名// 如 s"hello"// 字符串常量constchar*// 常量指针

八、表示字符串的两种方式

chars[]="hello";// 使用栈空间上的字符串(可修改)char*s="hello";// 使用字符串常量区中的字符串(不可修改)constchar*s="hello";// 更准确的写法:明确告知是只读的字符串常量

九、strcpy 的 const 版本

char*strcpy(char*dest,char*src);// 普通写法char*strcpy(char*dest,constchar*src);// 改进:src 只读不修改

原因:strcpy 只"读" src 的内容,不改 src,所以 src 用const char *更安全。


补充总结

  1. int *p,*q,*r;中*是修饰作用;
  2. 野指针 = 指针指向不明确(未初始化);NULL用来避免野指针;
  3. void *万能指针;
  4. &与*互为逆运算:&*p == p;
  5. 三种排序(选择/冒泡/插入)、二分查找都可以用指针(begin/end/mid)实现;
  6. 快速排序 = 指针 + 递归 + 分而治之;
  7. const 就近原则;只读函数参数用const char *;
  8. 字符串两种表示:栈空间(可改)vs 字符串常量区(只读)。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询