指针----C语言下篇--62-87节(看目录学习-指针)

178 阅读10分钟

指针

😈

什么是指针

指针=地址

坦白讲,这个地方我看了不知道多少遍,反反复复方阿胶囊

"*"是取地址所存放的值的运算符

"&"是取值的地址的运算符

指针变量wei什么要求类型

#include<stdio.h>
int main()
{
    int a = 0X1234;
    int *p = &a;
    char *c = &a;
    printf("p = %p\n",p);
    printf("c = %p\n",c);
    
    printf("a = %x\n",*p);//取值运算符会根据变量类型访问不同大小空间
    printf("a = %x\n",*c);//所以会出现访问不全的问题(访问不到)
    
    printf("++p = %p\n",++p);//先让值自增一然后打印    整型数加了四个字
    printf("++c = %p\n",++c);//字符型只加了一个字节

}
image.png image.png

使用指针场景一示例1

用指针交换两个数

封装一个交换两个数的函数,这边我们写两个代码 一个对的一个错的

错误示范

#include <stdio.h>
void huan(int a, int b)//用来承接的是变量
{                        //改变的是局部变量
    int tmp;
    tmp = a;
    a = b;
    b = tmp;
}
int main()
{
    int a = 88;
    int b = 77;
    huan(a,b);//传递的是值   详单与复制过去给形参
    printf("a = %d,b = %d",a ,b);
    
}

image.png 那么为什么他没有交换呢

是因为我们的值传递的本质值copy 并不是直接对实参进行修改

正确示范

#include <stdio.h>
void huan(int *pa, int *pb)//用来存放的是指针
{                         //交换两个数的地址
    int tmp;
    tmp = *pa;
    *pa = *pb;
    *pb = tmp;
}
int main()
{
    int a = 88;
    int b = 77;
    huan(&a,&b);//传递的是地址
    printf("a = %d,b = %d",a ,b);
    
}

image.png

这里我们就实现了两个数的交换,我们将存放两个数的的“地址”进行传递,并在函数中交换

使用指针场景一示例2

指针指向固定区域,这边我们的示例代码 就是指定固定区域

上代码:

#include<stdio.h>
int main()
{
    int a = 3;
    printf("%p\n",&a);                 //我们先打印出他的地址     是000000000061FE14
   volatile unsigned int *p = (volatile unsigned int *)0x000000000061FE33;//(volatile)防止编译器自动优化 (unsigned)无符号的
   printf("%p",p);//这里的p的地址是我根据a的地址修改的    就是我指向的地址
}

这边多在单片机 领域会用到 image.png

指针小检测

image.png

#include<stdio.h>
void jiaohuan(int *pa,int *pb, int *pc)
{
		int tmp;
		
		if(*pa<*pb){   //最大值给a
			tmp = *pa;
			*pa = *pb;
			*pb = tmp;
			
		}
		if(*pa<*pc){    //最大值给a
			tmp = *pa;
			*pa = *pc;
			*pc = tmp;
		}
		if(*pb<*pc){   //第二大的值给b
			tmp = *pb;
			*pb = *pc;
			*pc = tmp;	
		}	
	
}
int main()
{
    int a,b,c;
   scanf("%d%d%d",&a,&b,&c);
   jiaohuan(&a,&b,&c);
   
   printf("%d>%d>%d",a,b,c);
}

这里跟着写一遍加深一下记忆

数组指针(一维数组)

常规操作 ,先上废话

数组指针是指向数组的指针。在C语言中,数组名本身就是指向数组第一个元素的指针,因此可以使用数组名或者数组指针来访问数组中的元素。在函数中,可以使用数组指针来传递数组参数

废话说完上代码:

#include <stdio.h>
int main()
{
      int a[4] = {434,45,2,55};
      int *p;//定义一个指针
      p = a;//将数组名传递给指针p
      printf("%d\n",*p);
      printf("%d\n",*a);
}

好好看

指针偏移遍历数组

#include <stdio.h>
int main()
{
      int a[4] = {434,45,2,55};
      int *p;
      int i;
      p = a;//将数组名传递给指针p
      for(i = 0;i < 4; i++){
          printf("%d    ",*(p+i));
      }
}

image.png

这里有一个小小的坑位,我在写注释里了

#include <stdio.h>
int main()
{
    int a[4] = {434,45,2,55};
     int *p;
     int i;
     p = a;//将数组名传递给指针p
     for(i = 0;i < 4; i++){
         printf("%d    ",*(p+i));
     }
     p = a;//这边用完之后一定要复位   如果这一行代码没有     那就会出错    
      for(i = 0;i < 4; i++){//这里我再一次访问数组
         printf("%d    ",*(p+i));
     }
}

指针和数组的见怪不怪的写法

#include <stdio.h>
int main()
{


    int a[3] = {5,2,56};
    int *p;
    p = a;
    int i;
    
    printf("sizeof a is %d\n",sizeof(a));//3x4=12(个字节)数组中有三个元素   每个元素占四个字节
    printf("sizeof p is %d\n",sizeof(p));//8个字节
    printf("sizeof pointer is %d\n",sizeof(char *));//8个字节
    printf("sizeof pointer is %d\n",sizeof(int *));//8个字节
    printf("sizeof int is %d\n",sizeof(int));//4个字节
    
    for(i = 0; i < 3;i++){
        printf("%d  ",*(p+i));
    }
    puts("\n");
     for(i = 0; i < 3;i++){
        printf("%d   ",*(a+i));
    }
    puts("\n");
     for(i = 0; i < 3;i++){
        printf("%d   ",p[i]);
    }
}

也许有漏洞,交给你们啦

由上可看出,只要是指针类型的都是占用8个字节。
他们之间有些也是可以混着用的(这句话有争议---我说的),你们要理解可以用,在那用,怎么用,这是关键,好好思考

特性数组名指针
类型常量指针变量
内存空间固定,编译时就已经分配好了动态分配
赋值操作不可赋值可以改变指向的地址
sizeof操作符返回整个数组所占用的内存空间大小返回指针本身所占用的内存空间大小
函数参数传递作为参数时自动退化为指向数组第一个元素的指针可以直接传递指针或指针的地址
表达式运算可以参与表达式运算需要使用解引用运算符*访问所指向的值

有特殊标记的,就要注意看,数组名不可++

函数、指针、数组结合

#include <stdio.h>
void initArr(int *parr,int size)
{
    int i;
    for(i = 0;i<size;i++){
        scanf("%d",parr);
		parr++;
    }
}
void printArr(int *parr,int size)
{
    int i;
    for(i = 0;i < size;i++){
        printf("%d  ",*parr);
		parr++;
    }
}
int main()
{
    int arr[5];
    int size = sizeof(arr)/sizeof(arr[0]);
    initArr(arr,size);
    printArr(arr,size);
	return 0;
}

这个我不多说 作为对前面我所讲得一个小考核,前面的看懂了 这个也就懂了

练习题

image.png

#include <stdio.h>
void initArr(int *parr,int size)
{
    int i;
    for(i = 0;i<size;i++){
        scanf("%d",parr);
		parr++;
    }
}
void printArr(int *parr,int size)
{
    int i;
    for(i = 0;i < size;i++){
        printf("%d  ",*parr);
		parr++;
    }
	puts("\n");
}
void fanZhuanArr(int *parr,int size)//反转数组里的内容
{
	 int i;
	 int j; 
	 int tmp;
	 
    for(i = 0;i < size/2;i++){
            j = size - 1 - i;
            tmp = *(parr+i);
	    *(parr+i) = *(parr+j);
	    *(parr+j) = tmp;
    }
}
int main()
{
    int arr[5];
    int size = sizeof(arr)/sizeof(arr[0]);
    initArr(arr,size);
    printArr(arr,size);
	fanZhuanArr(arr,size);
	printArr(arr,size);
	return 0;
}

image.png

二维数组的地址

这个我讲的容易把你们带到沟里去---但是我会

这个你们去找我的老师吧 他讲的Very good——————上官社长
在抖音可以找得到,是猿学社里非常牛掰的老师之一

af60db1d56fc2113e8bc9fcd80295e8.jpg

这边就写一个写上几行代码 参考一下

上代码:

#include<stdio.h>

int main()

{
    int i,j;
    int a[3][4] = {{11,22,33,44},{55,66,77,88},{99,110,112,114}};
    for(i = 0;i < 3;i++){
        for(j = 0;j < 4;j++){
            printf("地址:0x%p的值为%d\n",&a[i][j],a[i][j]);
            printf("地址:0x%p的值为%d\n",a[i]+j,*a[i]+j);
            printf("地址:0x%p的值为%d\n",*(a+i)+j,*(*(a+i)+j));
            printf("兄弟们   smallsnake    是最帅的  !!!!!!\n");
        }
    }
}

留下部分看看 挺长的

image.png

留下个宝藏

a48887e31f5bdb7b909c23355ace9e3.jpg

数组指针(二维数组)🤞

数组指针是指向数组的指针。在C语言中,数组名本身就是指向数组第一个元素的指针,因此可以使用数组名或者数组指针来访问数组中的元素。在函数中,可以使用数组指针来传递数组参数 。 int (*p)[m], m为二维数组的列
只有数组指针才是真正的等同于二维数组名

兄弟们 看代码

#include<stdio.h>
int main()
{
    int i,j;
    int a[3][4] = {{11,22,33,44},{55,66,77,88},{99,110,112,114}};
    int (*p)[4];
     p = a;
    printf("p = %p\n",p);
     printf("p++ = %p\n",++p);
    p = a;                   //知道这里为什么要在写一次吗???????????????
    for(i = 0;i < 3;i++){
        for(j = 0;j < 4;j++){
                    printf("值为%d\n",*(*(p+i)+j));
        }
    }
}

做一个题目

用户任意输入行和列,输出二维数组任意行列的数

#include<stdio.h>
void init_hang_lie(int *ph,int *pl)🤞
{
    puts("请输入行和列:");
    scanf("%d%d",ph,pl);
}
int getseek_look(int (*pa)[4],int hang,int lie)🤞
{
    
    int data = *(*(pa+hang)+lie);
    //return pa[hang][lie];//这个也是可以的
    
    return data;    
}
int main()
{
    int a[3][4] = {{11,22,33,44},{55,66,77,88},{99,110,112,114}};
    int (*p)[4];
    int hang;
    int lie;
    p = a;
    int data1;
 //提示用户输入行列值
 init_hang_lie(&hang,&lie);🤞
 //抓出那个数
 data1 = getseek_look(p,hang,lie);🤞
 //打印这个数
 printf("第%d行,第%d列的数是:%d",hang,lie,data1);
 return 0;
}

别的就不多说了,兄弟们,这几个地方我刚才写的时候又卡住了,有“🤞”标注的地方都是我出问题的地方,很奇葩的问题,不说了🙈说多了都是泪!

函数指针

先上废话:

函数指针是一个指向函数的指针变量,它可以存储函数的地址,并且可以通过该指针变量来调用该函数。函数指针可以用于实现回调函数、动态绑定、多态等高级编程技术,是C语言中非常重要和常用的概念。int (*p)()
"int"类型 | “(*p)”名字 | “()”根据类型传递<里面可以是空的,主要强调是类型,形参可以不写,但是如果有类型要写>

上代码:

#include<stdio.h>
int waha_init(int a)//函数1
{
    return ++a;
}
void print_wa()//函数二
{
    printf("哇!you are beautiful\n");
}
int main()//主函数
{
    int (*waha)();//定义函数指针
    int (*wa)();//定义一个函数指针
    wa = print_wa;//指向函数
    waha = waha_init;
    (*wa)();//间接调用
    printf("look at me   %d",(*waha)(4));
}

这下清晰明了了吧!!!!!!!!!!!😎

冲击你的脑瓜子

其实这个题不算难
两个代码的注释要看

84f7842de1890b9344a6ada9e1b8d86.jpg 我是把他复杂化了,但其实是废了,不对 是会了😎 将其他的知识能融汇进来 说明你懂了

#include<stdio.h>

int max(int *a,int *b)
{
  return *a>*b?*a:*b;
}
int min(int *a,int *b)
{
  return *a<*b?*a:*b;
}
int num(int *a,int *b)
{
  return *a+*b;
}
int main()
{
    int i;
    int a = 6;
    int b = 7;
    int (*Max)();
    //int (*Max)(int ,int )   //这种写法是常用的 ,强调的是类型
    int (*Min)();   //这种也不会报错
    int (*Num)();
        Max = max;
        Min = min;
        Num = num;
        printf("1找出大的,2找出小的,3加一起,你想干啥\n");
        scanf("%d",&i);
        switch(i){
            case 1: 
            printf("哈哈   来啦:%d",(*Max)(&a,&b));
            break;
            case 2: 
            printf("哈哈   来啦:%d",(*Min)(&a,&b));
            break;
            case 3: 
            printf("哈哈   来啦:%d",(*Num)(&a,&b));
            break;
        }    //方法有很多在
}

这个是通过回调函数完成的

#include<stdio.h>
int get_summarizing(int a,int b,int (*pfunc)(int ,int ))//这里哦,出现的写法都是对的各种写法
{
    int ret;
    ret = (*pfunc)(a,b);
    return ret;
}
int max(int *a,int *b)
{
  return *a>*b?*a:*b;
}
int min(int *a,int *b)
{
  return *a<*b?*a:*b;
}
int num(int *a,int *b)
{
  return *a+*b;
}
int main()
{
    int i;
    int a = 6;
    int b = 7;
    int ret;
    int (*pfunc)(int,int);
    int (*Min)();//不写也可以在某些地方,但是不提倡,但是不报错可以用
    int (*Max)(int,int);
    int (*Num)(int a,int b);//都是对的
        Max = max;
        Min = min;
        Num = num;
        printf("1找出大的,2找出小的,3加一起,你想干啥\n");
        scanf("%d",&i);
        switch(i){
            case 1: 
            printf("哈哈   来啦:%d\n",(*Max)(&a,&b));
            pfunc = max;
            break;
            case 2: 
            printf("哈哈   来啦:%d\n",(*Min)(&a,&b));
            pfunc = min;
            break;
            case 3: 
            printf("哈哈   来啦:%d\n",(*Num)(&a,&b));
            pfunc = Num;
              break;
        }
   
ret = get_summarizing(&a,&b,pfunc);
    printf("这个是通过回调函数实现的,结果是%d",ret);
           return 0;
}

🎶煲子们,走起

指针数组

废话走起

指针数组就是一个数组,数组中的每个元素都是指针类型。指针数组中的每个元素都可以指向不同类型的数据。指针数组的访问方式与普通数组类似,可以使用下标操作符[]来访问数组中的元素。指针数组常用于实现复杂的数据结构和算法

小试牛刀

#include<stdio.h>

int main()
{
	int a = 20;
	int b = 10;
	int c = 88;
	int i;
	
	int *p[3] = {&a,&b,&c};
	
		for(i = 0;i<4;i++){
		printf("%d ",*p[i]);
		puts("\n");
	}
	
}

挥刀斩鸡(函数的指针数组)

#include<stdio.h>

int max(int a,int b)//找最大值
{
  return a>b?a:b;
}
int min(int a,int b)//找最小值
{
  return a<b?a:b;
}
int num(int a,int b)//求和
{
  return a+b;
}
int main()
{
    int i;
    int a = 6;
    int b = 7;
    int ret;
    int (*pfunc[3])(int,int) = {max,min,num};//函数的指针数组
    //都是对的
      for(i = 0;i < 3;i++){
		  ret = (*pfunc[i])(a,b);//运算符优先级的问题  所以把*Pfunc[i]加了()
		  printf("%d\n",ret);
	  }
                   return 0;
}

指针函数

废话上

指针函数就是返回指针的函数,它返回的指针指向内存中的某个地址,这个地址存储了某个数据对象的值。使用指针函数时需要注意返回的指针必须指向有效的内存地址

通常会返回指向上分配的内存地址的指针。//这句话其实有点拗口,我理解的不多

int *p;//定义一个指针变量

int* p;//定义一个变量,这个变量是int型的指针类型
两个说法,作用差别不大

啾咪啾咪🤞

e127abe623f10631d781b71dfbc706c.png

实践来啦

a7bb421b6e108ae49191ac5c2f64e42.png

练习

#include <stdio.h>
int* student(int i,int (*pa)[5])
{
    int *p;
	p = (int *)(i + pa);//这屋里进行一个强转,不然会出现报错
	
    return p;
              
}
int main()
{
	int a[3][5]= {{99,100,15,97,98},
                {93,78,66,88,89},
                {12,13,11,101,100}};
    int i;
    int *p;
    puts("请输入0-2的学号:\n");
    scanf("%d",&i);
    p = student(i,a);
    for(i = 0;i<5;i++){
        printf("%d  ",*p++);
    }
}

作业

这个留给你们,也留给我,我复习拿来练手。这里就不写示例代码了

二级指针

老生常谈

二级指针是指向指针的指针,可以用于传递指针的地址,在函数调用中非常有用。需要注意使用时可能会导致内存泄漏和悬挂指针等问题,需要小心使用,并确保指向的内存地址有效,及时释放内存。

概念性的东西是搞起来就是的头疼,重在理解,理解了,就不疼了

#include <stdio.h>
int main()
{
    int data = 992;
    int **p2;
    int *p;
    p = &data;
    p2 = &p;//重点
    printf("data的地址是%p,p存储的地址是%p\n",&data,p);
	puts("\n");
    printf("data的值是%d,      p的地址是%p\n",data,&p);
	puts("\n");
    printf("p2保存的地址是%p,p2的地址是%p\n",p2,*p2);
	 puts("\n");
    printf("访问p2的值是%d\n",**p2);

}//这里我写的时候又翻车了,    

image.png

实战

#include <stdio.h>
void student(int i,int (*pa)[5], int **p2)
{
       //父数组偏移i,传给二级指针
	*p2 = (int *)(pa + i);//这里进行一个强转,不然会出现报错     
}
int main()
{
	int a[3][5]= {{99,100,15,97,98},
                {93,78,66,88,89},
                {12,13,11,101,100}};
    int i;
    int *p;
    puts("请输入0-2的学号:\n");
    scanf("%d",&i);
    student(i,a,&p);
    for(i = 0;i<5;i++){
        printf("%d  ",*p++);
    }
}

一遍肯定是不理解的,没有关系的,我能理解,大家不要慌😃哈哈

🤞二级指针和二维数组的必坑指南

兄弟们 我累了,第86节,我写不下去了,最后这一点想看的你们去找一下吧,在图片里

af60db1d56fc2113e8bc9fcd80295e8.jpg

指针完结

指针搞了4天,确实有点久了,但没办法,查漏补缺,主打一个细节,搞起,继续。