0808指针(3)

提示:以下内容都是针对指针练习展开的,相当于是拿指针练手,增加对指针的理解。有小伙伴不理解,勿看!

指针 操作 二维数组 

提示:二维数组 
1.c语言中并不存在,真正的二维数组。
2.二维数组本质 是一维数组的一维数组 
3.二维数组 也 符合数组的特点 //连续性,有序性,单一性 

问题:
1.怎么针对二维数组确定需要定义什么类型的指针?
例如:

int a [2][3]; 

&a[0]
    //a[0]  --- int[3]
    //&a[0] --- int[3] * 
    //c语言中 不支持 int[3] *  
    //正确写法 int(*)[3]

int(*p)[3] = a; //p指向二维数组 a 
                //p的基类型 int[3]

*p <=> a[0] // 相当于是内部这个一维数组的数组名 
       (*p)[0] 
       *(*p+0) //**p

*(*(p+1)+1) <=> a[1][1]
*(*(p+i)+j) <=> a[i][j] //里面的*号是对a[i]取地址,而a[i]等价为*(a+i),在机器语言中其实[]就代表
                           *(),而*(p+i)+1;代表a[i][1],也就是说i的值确定了,+1代表在a[i] 
                           [],i确定下,对二维数组最里面的a[j]访问,(这里指是a[i][j]的地址)。    
  


   
   
注意:  
   二维数组的操作
   从二维数组的本质 进行的 
   二维数组的本质 :一维数组的 一维数组
   直接的访问操作 也是 一维一维的展开  


练习:
1. 求出整形数组a[N][N]主对角线最大值和辅对角线最小值
 int *Input(int (*a)[n],int n)
 {
     int(*p)[n]=a;
     int i=0;                             
     int j=0;
     for(i=0;i<n;i++)
     {
         for(j=0;j<n;j++)
         {
             scanf("%d",&*(*(p+i)+j));
         }
     }
 
 }
 int Maxzhu(int (*a) [n],int n)//这里int (*a) [n],代表a的首地址,即a[0].
 {
     int(*p)[n]=a;
     int i=1;
     int j=1;
     int max=**p;
     while(i==j&&j<n&&i<n)
     {
             if(*(*(p+i)+j)>max)
             {
                 max=*(*(p+i)+j);
             }
             i++;
             j++;
     }
     return max;
 }
 int Minfu(int (*a) [n],int n)
 {
     int(*p)[n]=a;
     int i=1;
     int j=1;
     int min=*(*(p)+n-1);
     while(i<n)
    {
            if(*(*(p+i)+n-i-1)<min)
            {
                min=*(*(p+i)+n-1-i);
            }
            i++;        
    }
    return min;
}


int main()
{
    int i=0,n;
    printf("In put n: ");
    scanf("%d",&n);
    int a[n][n];
    Input(a,n);//调用输入函数,将值输进去。
    printf("Max= %d\n",Maxzhu(a,n));//主对角线最大值
    printf("Min= %d\n",Minfu(a,n));//副对角线最大值
    return 0;
}

    实现一个函数,找出二维数组中能被3整除的数 
    
void Zhenchu(int (*a)[5],int n)
{
    int (*p)[5]=a;
    int i=0;
    int j=0;
    for(i=0;i<n;i++)
    {
        for(j=0;j<n;j++)                       
        {
            if(*(*(p+i)+j)%3==0)
            {
                printf("%d\n ",*(*(p+i)+j));
            }
        
        }
    }
}


int main(void)
{
    int n;
    int a[5][5]={1,2,3,4,5,6,7,8,9,15,41};
    Zhenchu(a,5);
    return 0;
}


    
指针 操作 二维字符型数组

操作二维字符型数组其实和操作二维数组是差不多的。唯一有区别的是字符串有结束标志'\0';

char s[][10] = {"hello","world","china"};
char (*p)[10] = s; //p指向二维数组s 

//*(*(p+i)+j) 

练习:
    输入三个字符串 ,排序输出 
    
int Strcmp(const char *s1,const char *s2)//自己写的函数,比较字符串大小
{
    int ret = 0;
    while (*s1 == *s2 && *s1 != '\0' && *s2 != '\0')
    {
        ++s1;
        ++s2;
    }
    ret = *s1 - *s2;
    return ret;

}

char *Strcpy(char *dest,const char *src)//把src的值复制到dest。
{
    char *ret = dest;
    while (*src != '\0')
    {
        *dest = *src;
        dest++;
        src++;
    }
    *dest = '\0';
    return ret;
}

void Erwei(char (*a)[20],int n)
{
    char (*p)[20]=a;
    int i=0;
    int j=0;
    for(i=0;i<n-1;i++)
    {
        for(j=i+1;j<3;j++)                              
        {
            if(Strcmp(*(p+i),*(p+j))>0)
            {
                char b[20];           
                Strcpy(b,(*p+i));
                strcpy(*(p+i),*(p+j));
                strcpy(*(p+j),b);
            }

        }
    }

}

int main(void)
{
    int n;
    char a[][20]={"hello","word","abc"};
    Erwei(a,3);
    for(int i=0;i<3;i++)
    puts(a[i]);
    return 0;
}


指针的数组:

概念

指针数组是数组,用来存放指针的。

比如:

    int arr[10]={0};	//整型数组,数组用来存放整型(int)
    char ch[5]={0};		//字符数组, 数组用来存放字符(char)
    int* parr[4];		//指针数组,数组用来存放整型指针(int*)
    char* pch[5];		//指针数组,数组用来存放字符指针(char*)

用法:

char s[3][10]={"hello","nihao","word"};

char s[10] = "hello";//存放字符串数据 
char *p = "hello";
	

char s[10]; //s的数据类型 char[10]
char[10] s1[3]; //二维数组 //此时的二维数组的元素 是一个一维字符型数组 
                //定义一个存放 字符串 的一维数组 


char *p = "hello"; //p的类型 char *  
                   //char *的指针变量p 相当于代表一个字符串 

				   
char *p1 = "hello";
char *p2 = "world";
char *p3 = "china";

char* pstr[3]= {"hello","world","china"}; //数组 --- 数组中存放是 各个字符串的地址
      //地址 ---存放这地址数据的数组 --- 指针的数组 ---指针数组 
	  
char **q = pstr; //q 二级指针 

练习:
    找出字符串中最大值 
    
char *Maxstr(char **p,int n)
{
    char *max=*p;
    for(int i=1;i<n;i++)
    {
        if(strcmp(p[i],max)>0)
        {
            strcpy(max,p[i]);
        }
    }
    return max;
}
int main(void)
{
    int n;
    char s[][20]={"hello","word","abc"};
    char *p[]={s[0],s[1],s[2]};

    puts(Maxstr(p,3));
  
    return 0;
}

练习:
    在以上的代码中进行排序 
void  Maop(char **p,int n)
 {
     char *max;
     for(int i=0;i<n-1;i++)
     {
         for(int j=0;j<n-i-1;j++)
        {
            if(strcmp(*(p+j),*(p+j+1))>0)
            {
                max=*(p+j);
               *(p+j)=*(p+j+1);
                *(p+j+1)=max;
            }                               
        }
     }
 }

总结

(1)int(*p)[10]

p先和*结合,说明p是一个指针变量,然后指向的是一个大小为10个整型的数组。

所以p是一个指针,指向一个数组,叫数组指针。

(2)注意

[]的优先级高于*,所以必须加上()来保证p先和*结合。



函数指针:

概念

函数指针 的本质是一个指针,该指针的地址指向了一个函数,所以它是指向函数的指针。
我们知道,函数的定义是存在于代码段,因此,每个函数在代码段中,也有着自己的入口地址,函数指针就是指向代码段中函数入口地址的指针。

通过指针 的方式 来调用函数 

那我们先了解函数名代表什么?
 

函数名 --- 代表函数的入口地址 

int add(int a,int b) // 函数  
                     // 函数名 - 代表函数的入口地址 
                     // 函数名对应的数据类型 
                     // int (int a,int b) //函数类型 
                     // 代表一类函数
                     // 返回值为int型
                     // 带有两个int型的形参变量 

声明形式

基类型  (*函数名)(基类型,基类型)
int (*p) (int,int) 


                    
说明:
 1.可以定义一个函数类型的指针变量 
   来保存函数的入口地址 
 2.有了这个指针变量 
   通过指针变量 进行函数调用 
   
 思考:为什么要使用函数指针?
       那么,有不少人就觉得,本来很简单的函数调用,搞那么复杂干什么?其实在这样比较简单的代码实现中不容易看出来,当项目比较大,代码变得复杂了以后,函数指针就体现出了其优越性。
举个例子,如果我们要实现数组的排序,我们知道,常用的数组排序方法有很多种,比如快排,插入排序,冒泡排序,选择排序等,如果不管内部实现,你会发现,除了函数名不一样之外,返回值,包括函数入参都是相同的,这时候如果要调用不同的排序方法,就可以使用指针函数来实现,我们只需要修改函数指针初始化的地方,而不需要去修改每个调用的地方(特别是当调用特别频繁的时候)。

举例:

#include <stdio.h>

int add(int a,int b)
{
	return a + b;
}

int sub(int a,int b)
{
	return a - b;
}
int mul(int a,int b)
{
	return a * b;
}
int div(int a,int b)
{
	return a / b;
}

//以上是实现两个数的加减乘除


void processData(int a,int b,int(*p)(int,int))//在这里我们直接用函数指针直接调用函数就可以实 
                                               现输出不同函数。
{
	printf("result: %d\n",p(a,b));
}

int main(int argc, const char *argv[])
{

	processData(1,2,add);
	processData(1,2,sub);
	processData(1,2,mul);
	processData(1,2,div);
	
	return 0;
}

回调函数


函数指针的一个非常典型的应用就是回调函数。
什么是回调函数?
回调函数就是一个通过指针函数调用的函数。其将函数指针作为一个参数,传递给另一个函数。
回调函数并不是由实现方直接调用,而是在特定的事件或条件发生时由另外一方来调用的。

举例:

#include<stdio.h>
#include<stdlib.h>

//函数功能:实现累加求和
int func_sum(int n)
{
        int sum = 0;
        if (n < 0)
        {
                printf("n must be > 0\n");
                exit(-1);
        }
        for (int i = 0; i < n; i++)
        {
                sum += i;
        }
        return sum;
}

//这个函数是回调函数,其中第二个参数为一个函数指针,通过该函数指针来调用求和函数,并把结果返回给主调函数
int callback(int n, int (*p)(int))
{
        return p(n);
}

int main(void)
{
        int n = 0;
        printf("please input number:");
        scanf("%d", &n);
        printf("the sum from 0 to %d is %d\n", n, callback(n, func_sum));       //此处直接调用回调函数,而不是直接调用func_sum函数
        return 0;
}

总结:
1.指针 
  指针概念 
  指针的定义  //基类型 * 变量名 
  指针的初始化 和 赋值 
             //野指针 NULL,没有赋值
  
  核心用途 
          被调修改主调 
          使用方法:
          1.要修改谁,把谁的地址传过去 
          2.被调函数中,一定要有对应的 *p运算 
          3.传过去的实参地址,一定要对应一块有效的内存空间 
-------------------------------------------------------------
2.指针 + 数组 
  指针 操作 一维整型数组 
  指针 操作 一维字符型数组 
  
  核心思路:
     1.定义一个什么类型的指针变量  
                            //参考第2点 
     2.获得那个位置的地址  //数组的特点 
                           //数组首元素的地址 &a[0]   //就是数组名 


   指针操作数组元素的过程:
   

 指针运算 
     
     p+1 //代表p+1的地址,在P上移动基类型大小的字节
     *p  //代表对P进行取值


--------------------------- ------------------------------------------
指针 + 二维数组 
 1.二维数组本质 ---一维数组  
 2.数组的特点 //连续空间
 3.指针类型的定义 //int(*p)[ ];
 4.指针访问数组元素的 过程  
   *(*(p+i) + j)


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值