重新回顾指针:

C语言指针笔记01 – Morning枫 – 博客园 (cnblogs.com)

&ptr  输出指针变量ptr的地址

ptr  输出指针变量ptr保存的地址(一个十六进制的地址,若输出采用%d,则输出一个整数)//字符串自身的地址就是它本身的值

*ptr  输出指针变量ptr保存的地址的值(相当于直接找到地址修改地址保存的值)


 由于指针也是个变量,所以它自己本身也可以进行算术运算:

 

 地址+1,但是定义是int的指针,int有四字节,所以指针保存的地址在内存中+4,即指向数组中下一个元素

实机演示运行一次:

 自增如此,同理可推自减。


 指针加/减运算:

已经理解自增和自减,加减也不在话下!

 

 此代码表示,指针指向数组当前位置的后面第二位元素


指针的比较:

直接上案例进行判断:

1.

 输出为:ok2和ok3

分析过程:

 ============================================

2.

 输出为:

Address of var[0] = 指向10的地址

Value of var[0] = 10

Address of var[00] = 指向100的地址

Value of var[1] = 100

 此案例进行的是地址的比较。。。


指针数组:

 

 实例:

 

 当执行完:

int i, *ptr[3];

内存中有:

 

 执行完第一个循环体后,有如下内存图变化:

 

 此时被称为指针数组

 

 接着,用指针数组来获取各个值:

 

 完整代码如下:

 1 #include <stdio.h>
 2 
 3 const int MAX = 3;
 4 
 5 int main(){
 6     int var[] = {10,100,200};
 7     int *ptr[3];
 8     for(int i = 0; i < MAX; i++){
 9         ptr[i] = &var[i];
10     }
11     for(int i = 0; i < MAX; i++){
12         printf("Value of var[%d] = %d\n", i, *ptr[i]);
13     }
14     return 0;
15 }

实例运用:

 1 #include <stdio.h>
 2 
 3 const int MAX = 4;
 4 
 5 int main(){
 6     char *books[] = {"西游记","水浒传","红楼梦","三国演义"};
 7 
 8     for(int i = 0; i < MAX; i++){
 9         printf("Value of var[%d] = %s\n", i, books[i]); //字符串本身就是地址,不用*books[]
10     }
11 }

 

&ptr  输出指针变量ptr的地址

ptr  输出指针变量ptr保存的地址(一个十六进制的地址,若输出采用%d,则输出一个整数)//字符串自身的地址就是它本身的值

*ptr  输出指针变量ptr保存的地址的值(相当于直接找到地址修改地址保存的值)


 

多重指针数组(指向指针的指针):

 

 快速入门:

 1 #include <stdio.h>
 2 
 3 int main(){
 4     int var;
 5     int *ptr;
 6     int **pptr;
 7     var = 3000;
 8     ptr = &var;     //把var变量的地址赋值给ptr
 9     pptr = &ptr;    //把ptr存放的地址赋值给pptr
10     printf("var的地址=%p var=%d\n", &var, var);
11     printf("ptr本身的地址=%p ptr存放的地址=%p ptr=%d\n", &ptr, ptr, *ptr);
12     printf("pptr本身的地址=%p pptr存放的地址=%p pptr=%d\n", &pptr, pptr, **pptr);
13     return 0;
14 }

内存图示例:

 

 更多级的指针可以从二级指针理解和去推导即可。


传递指针给函数:

 案例1(传递指针/地址给指针变量)入手:

 1 #include <stdio.h>
 2 
 3 //函数写在main前就不用声明,写在main后就需要在前面声明
 4 void test2(int *p); //函数声明,接收int *
 5 
 6 void main(){
 7     int num = 90;
 8     int *p = &num;      //把num地址赋值给p
 9     test2(&num);    //传地址
10     printf("\n main()中的num=%d", num);
11     test2(p);   //传指针
12     printf("\n main()中的num=%d", num);
13 }
14 
15 void test2(int *p){
16     *p += 1;
17 }

内存示意图:


案例2(传数组给指针变量)入手:

首先确认:

 

 指针数组传递的是地址,而不是值,因此操作过程中有且只有一个数组(理解为全局)在被操作,而不是和值一样操作值的副本(理解为局部)

 1 #include <stdio.h>
 2 
 3 //函数声明
 4 double getAverage(int *arr, int size);
 5 double getAverage2(int *arr, int size);
 6 
 7 int main(){
 8     int balance[5] = {1000,2,3,17,50};  //定义带有五个元素的int数组
 9     double avg;
10     avg = getAverage(balance, 5);  //传递以一个指向数组的指针作为参数
11     printf("Average value is: %f\n", avg);
12     return 0;
13 }
14 
15 double getAverage(int *arr, int size){  //下标遍历
16     int i, sum = 0;
17     double avg;
18     for( i = 0; i < size; i++){
19         sum += arr[i];  //数组下标运算
20         printf("\n arr存放的地址=%p", arr); //不改变arr的地址,只对下标进行修改
21     }
22     avg = (double)sum / size;
23     return avg;
24 }
25 
26 double getAverage2(int *arr, int size){ //指针遍历
27     int i, sum = 0;
28     double avg;
29     for( i = 0; i < size; i++){
30         sum += *arr;    //地址运算
31         printf("\n arr存放的地址=%p", arr);
32         arr++;  //指针的自增运算,会对arr存放的地址做修改
33         //arr[0] = arr + 0
34         //arr[1] = arr + 1个int的字节(4)
35         //arr[2] = arr + 2个int的字节(8)
36     }
37     avg = (double)sum / size;
38     return avg;
39 }

内存图:


返回指针的函数:

 

 快速入门:

 1 #include <stdio.h>
 2 #include <string.h>
 3 
 4 char *strlong(char *str1, char *str2){  //表明此函数是一个指针函数
 5     printf("\n str1的长度是:%d,str2的长度是:%d", strlen(str1), strlen(str2));
 6     if(strlen(str1) >= strlen(str2)){
 7         return str1;
 8     }else{
 9         return str2;
10     }
11 }
12 
13 int main(){
14     char str1[30], str2[30], *str;  //str是一个指针类型,指向一个字符串
15     printf("\n请输入第一个字符串:");
16     gets(str1);
17     printf("\n请输入第二个字符串:");
18     gets(str2);
19     str = strlong(str1, str2);
20     printf("\n Longer string:%s \n", str);
21     return 0;
22 }

 

返回函数指针的有关注意事项:

 

 关于第一点和第二点,需要深刻理解!!!:

 1 #include <stdio.h>
 2 
 3 int *func(){
 4     int n = 100;    //局部变量
 5     return &n;
 6 }
 7 
 8 int main(){
 9     int *p = func();    //func返回指针
10     int n;
11     n = *p;
12     printf("\n value = %d \n", n); //所以最后不一定能输出100
13     return 0;
14 }

对于函数返回销毁,它只是放弃了需要返回的函数的使用权限,但是其中内存改变的值并没有重新初始化(只要没有代码调用新的内存(例如printf会调用内存,此时可能会重新给之前返回的函数占用的内存重新赋值,从而导致返回的值被覆盖)),只要在执行其他代码前调用了返回函数的值,就有可能正常运行输出返回的值。具体看第三点。。

关于第三点,进行了static修饰后,即可正常运行上面的案例程序:

 1 #include <stdio.h>
 2 
 3 int *func(){
 4     static int n = 100;    //如果这个局部变量是static性质的,那么它将保存在内存中的静态数据区
 5     return &n;
 6 }
 7 
 8 int main(){
 9     int *p = func();    //func返回指针
10     int n;
11     n = *p;
12     printf("\n value = %d \n", n); //所以最后不一定能输出100
13     return 0;
14 }

关于static的用法:

static 关键字 – Morning枫 – 博客园 (cnblogs.com)


应用实例:

 

 

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 int *random1(){
 5     static int arr[10]; //让arr的空间在静态数据区保存
 6     for(int i = 0; i < 10; i++){
 7         arr[i] = rand();
 8     }
 9     return arr;
10 }
11 
12 void main(){
13     int *p;
14     p = random1();  //p指向在random1生成的数组的首地址(即第一个元素的地址)
15     for(int i = 0; i < 10; i++){
16         printf("\n%d",*(p+i));
17     }
18 }

函数指针:

 定义:

 

 

 实例演示:

 1 #include <stdio.h>
 2 
 3 int max(int a, int b);
 4 
 5 int main(){
 6     int x, y, maxVal;
 7     //函数指针
 8     //函数指针名字是pmax
 9     //int表示该函数指针指向的函数是返回int类型
10     //(int , int)表示该函数指针指向的函数形参是接收两个int
11     //要注意这个函数指针是有地址的
12     //在定义函数指针时,也可以写形参名(可以不与指向的函数形参名或者传递的变量名相同),如:int (*pmax)(int i, int j) = max;
13     //简单理解为:本身有地址的pmax函数指针保存了max函数的地址//
14     int (*pmax)(int, int) = max;
15     printf("Input two numbers:");
16     scanf("%d%d", &x, &y);
17     maxVal = (*pmax)(x,y);  //通过函数指针去调用参数,即*pmax-->max,当然也可以写成pmax(x,y)也是允许的
18     //类似于*pmax取到了函数max的首地址
19     //maxVal = max(x,y);
20     printf("Max value = %d\n", maxVal);
21     printf("pmax保存的地址:%p,pmax本身的地址:%p", pmax, &pmax);
22     return 0;
23 }
24 
25 int max(int a,int b){   //Max函数,接收两个int,返回值大的
26     return a>b ? a:b;
27 }

内存图:

函数指针——回调函数:

介绍:

 

 实例:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 //回调函数
 5 //int (*f)(void),f是一个函数指针,它可以接收的函数是返回int,没有形参的参数
 6 //f在这被initArray调用,充当了回调函数的角色
 7 void initArray(int *array, int arraySize, int (*f)(void)){
 8     int i;
 9     for(i = 0; i < arraySize; i++){
10         array[i] = f(); //通过函数指针调用getNextRandomValue函数,(*f)()=f()
11     }
12 }
13 
14 //获取随机值
15 int getNextRandomValue(void){
16     return rand();  //rand系统函数,会返回一个随机整数
17 }
18 
19 int main(){
20     int myarray[10], i; //定义一个数组和int
21     //说明:
22     //1.调用initArray函数
23     //2.传入了一个函数名getNextRandomValue(地址),需要使用函数指针来接收
24     initArray(myarray, 10, getNextRandomValue);
25     for ( i = 0; i < 10; i++){
26         printf("%d\n", myarray[i]);
27     }
28     printf("\n");
29     return 0;
30 }

指针使用的注意事项以及空指针:

 

 关于第二点和第三点:

 

原文地址:http://www.cnblogs.com/MorningMaple/p/16773970.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性