指针是什么
》》每一个内存单元只能同时存储一个数据, 如何保证内存单元同时只能存储一个数据, 可以使用编号的方式实现内存单元标记, 此编号就是指针.
》》指针是一个变量, 指针是存放着一个数据的内存地址而不是数据本身的值, 其是查找数据的另一种方式
相关运算符
[&] 在变量中取地址
[*] 在地址中取变量
测试小程序:
- #include<stdio.h>
- void main() {
- int i = 10;// 定义一个变量, 并赋初始值为 10
- int *p = &i;// 定义一个指针变量, 并赋初始值为 i 的地址
- *p = 199;
- printf("%d=%d", *p,i);// 输出 199=199
- printf("---%d---", p);// 得到变量 i 的地址
- }
指针变量的类型
》》指针类型: int *,float*,long*,double*,char * 等等
》》指针变量的类型需要与存储的数据类型相同
》》确定类型可以方便指针变量确定存储数据的大小, 为数据寻找到结束符, 如 int 类型占四个字节, char 占一个字节. 也方便指针使用加 1 或减 1 操作, 如 int 加减 1 会跳动 4 个字节, char 加减 1 会跳动两个字节.
指针的赋值
int i=10; int *p=&i;
int *pp;
pp=p;
指针运算符:
*p++
等同于 p++;*p; 或者 *(p++), 运算优先级为从右到左.
指针变量作为函数参数
- #include<stdio.h>
- //int *a1=&b1;
- void fun(int *a1, int* a2) {
- *a1 = 100;
- int ii = 99;
- a2 = ⅈ// 让指针重新指向另外一个地址
- printf("得到的数据:%d,%d", *a1, *a2);// 输出 100,99
- }
- void main() {
- int b1 = 1, b2 = 2;
- fun(&b1, &b2);
- printf("调用函数后:%d,%d", b1, b2);// 输出 100,2
- }
输出 b2 的结果并不是相同的值, 是因为执行调用函数改变了实参指针变量的值, 并不是改变了实参指针变量所指变量的值
一维数组指针变量
数组名 (如 arr) 代表元素的首地址, 数组第一个元素的地址也是这个数组的首地址(如 & arr[0]).
数组指针中使用加减 1 将跳到下一个或者上一个数组元素地址, 与使用 &arr[n+1] 基本相同.
如果整数数组名为 arr, 运行 int *p=arr, 则 *(p+3),p[3],*(arr+3),arr[3]效果均是取出数组 arr 的第三个元素, 在编译时 arr[3]实际上是 *(arr+3)处理的.
- #include<stdio.h>
- void main() {
- int arr[] = { 5,4,3,2,0 };
- int *p = arr;
- int *pp = &arr[0];
- printf("%d", *(p+3));// 输出 2
- }
函数数组参数
- #include<stdio.h>
- // 等价于 void fun(char a1[]) {
- void fun(char *a1) {
- *(a1 + 2) = 'c';// 改变第二个值的内容
- }
- void main() {
- char b1[] = { "123456789" };
- fun(b1);
- printf("调用函数后:%s", b1);// 输出: 12c456789
- }
二维数组指针变量
- #include<stdio.h>
- void main() {
- int a1[][3] = { {10,11,12},{100,110,120} };
- int a[][3] = { 10,11,12,100,110,120 };
- printf("地址:%d==%d==%d==%d", a[0], &a[0][0],*(a+0),a+0);// 输出地址
- printf("%d===%d==%d", a[0][1], *(*(a + 0)+1),*(a[0]+1));// 得到值
- }
指针引用字符串
字符串常量[char *ch = "dong xiao dong";] 表示其指向地址的内容不可变, 但指向的地址是可变的;
字符串变量[char ch[] = "dong xiao dong";] 其指向地址的内容可变.
- #include<stdio.h>
- void main() {
- //char *ch = "dong xiao dong"; // 字符串常量, 不可变
- char ch[] = "dong xiao dong"; // 字符数组, 可变
- ch[2] = '2';// 字符串常量运行这条将报错
- printf("%s\n", ch);
- }
可变格式的输出函数:
- #include<stdio.h>
- void main() {
- char *ch = "dong xiao %d\n";
- printf(ch, 10);
- ch = "xiaoxiao%d\n";
- printf(ch, 10);
- char chh[] = "dongdong %d\n";
- printf(ch, 100);
- }
指向函数的指针
[int(*p)(int, int);// 定义一个函数指针变量 p] , 第一个 int 表示返回值类型, 第二个 int 和第三个 int 表示函数的参数类型. 注意 * p 两侧的括号不能省略, 表示 p 先与 * 结合, 是指针变量, 然后再于后面的 () 结合,()表示是函数, 即该指针变量不是指向一般的变量, 而是指向函数. 如果写成 "int * p(int,int);", 由于 () 优先级高于 *, 它相当于 "int *(p(int,int))", 就成了声明一个 p 函数, 并且这个函数的返回值是指向整型变量的指针.
返回值为 int
- #include<stdio.h>
- void main() {
- int minto(int a, int b);// 函数声明
- int(*p)(int, int);// 定义一个函数指针变量 p
- p = minto;// 函数指针指向函数 minto 首地址
- int cc = (*p)(11, 55);// 调用函数
- printf("Min===%d", cc);
- }
- int minto(int a, int b) {
- if(a> b) return b;
- else return a;
- }
无返回值:
- #include<stdio.h>
- void main() {
- void fun(int a);// 函数声明
- void (*p)(int);// 定义一个函数指针变量 p
- p = fun;// 函数指针指向函数 fun 首地址
- (*p)(11);// 调用函数
- }
- void fun(int a) {
- printf("%d\n", a);
- }
指向函数指针作为函数的参数
- #include<stdio.h>
- void main() {
- int fun(int(*addpp)(int, int), int x, int y);// 函数声明
- int add(int i, int j);
- int ii=fun(add, 11, 12);// 传递函数名和参数即可
- printf("输出相加的值为:%d", ii);
- }
- //int (*addpp)(int,int);addpp=add;
- int fun(int (*addpp)(int,int),int x,int y){
- int cc = (*addpp)(x, y);
- return cc;
- }
- int add(int i, int j) {
- return i + j;
- }
返回指针的函数
- #include<stdio.h>
- void main() {
- int* add(int i, int j);
- int *p = add(10, 4);
- printf("输出相加的值为:%d", *p);
- }
- int* add(int i, int j) {
- int aa = i + j;
- return &aa;// 返回地址
- }
指针数组
一个数组其全部元素都存放着指针, 就是指针数组[int * p[5];]
- #include<stdio.h>
- void main() {
- // 指针数组
- char * p[] = { "dong1","xiao2","dong3","dong4" };
- printf("%s\n", p[2]);
- }
进阶版
- #include<stdio.h>
- void main() {
- // 指针数组(字符串)
- char * p[] = { "dong1","xiao2","dong3","dong4" };
- char **pp;
- pp = p;
- printf("%s\n", *(pp+1));// 转换一次就可以拿到对应字符串的首地址通过 %s 打印
- // 指针数组(整数)
- int a[5]= {10,11,12,13 };
- int * ip[] = { &a[0],&a[1],&a[2],&a[3],&a[4]};
- int **ppp = ip;
- printf("%d\n", *(*ppp+1));// 转换第一次得到存储的指针, 再次转换得到值
- }
错误示范
- 1,
- int *p=10; // 等同于: int *p; p=10;
分析: 非法操作, 内存地址不能用户自定义. 10 相当于一个内存地址, 该内存地址的值不确定且也不明确该地址是否可以直接访问, 正确的应该是使用[& 变量名] 得到内存地址.
- 2,
- int f = 12.3;
- int *p;
- *p = &f; // 错误 1
- int ff = &f; // 错误 2
分析: 指针 (地址) 必须赋值给指针变量
来源: https://www.cnblogs.com/dongxiaodong/p/10743246.html