C语言——指针

本文介绍了指针的基本概念,包括指针的定义、指针变量、类型匹配,以及如何通过指针进行数据交换、数组操作、函数传递和高级指针技巧,如指针数组和二级指针的使用。

1、什么是指针:

         指针就是地址,地址就是指针。(门牌号)


2、指针变量:存放变量地址的变量。


3、指针类型匹配:指针变量指向的是和它类型一致的变量的地址。


练习:

【1】封装一个函数实现两个数交换(函数传参用指针实现):01_pointer1.c

/*
 *         封装一个函数实现两个数交换(函数传参用指针实现):
 */
#include <stdio.h>

void swap(int* data1,int* data2)
   {
         int tmp;

	 tmp = *data1;
	 *data1 = *data2;
	 *data2 = tmp;
   }

int main()
  {
      int data1 = 10;
      int data2 = 5;

      printf("交换前: data1= %d  data2= %d\n",data1,data2);
      swap(&data1,&data2);
      printf("交换后:data1= %d  data2= %d\n",data1,data2);
	  return 0;
  }

【2】输入三个数a,b,c,要求不管怎么输入,在输出时,a,b,c就是由大到小的顺序输出,用函数封装实现。(传参使用指针): 02_pointer2.c

/*
 *        输入三个数a,b,c,要求不管怎么输入,在输出时,a,b,c就是由大到小的顺序输出,用函数封装实现。(传参使用指针)
 */

#include <stdio.h>

void number_comparisorison(int* p_data)
   {
       int i,j;
       int tmp = 0;

       for(i=0;i<3;i++)
         {
	   for(j=0;j<3-i-1;j++)
	     {
		if(*(p_data + j) < *(p_data + j+1))
		 {
		     tmp = *(p_data + j);
		     *(p_data + j) = *(p_data + j+1);
		     *(p_data + j+1) = tmp;   
		 }
	     }
	 }
   }



int main()
  {
       int arr[3];
       int i;

       for(i=0;i<3;i++)
         {
	      scanf("%d",&arr[i]);
	 }
       number_comparisorison(arr);
       for(i=0;i<3;i++)
         {
             printf("%d\t",arr[i]);
         }
       printf("\n");

	  return 0;
  }

4、定义一个指针变量指向数组

指针变量指向数组的首地址:a[0]

示例:

int  arr[3];         //创建一个数组

int* p_data;      //创建一个指针

/******指针变量指向数组的方式*****/

【1】p_data  =  &arr[0];        //&arr[0]是数组的首元素地址

【2】p_data  =  arr;              //arr是数组名,数组名是数组的首地址,是一个指针 


5、通过指针偏移遍历数组:03_pointer3.c

/*
 *         指针偏移遍历数组
 */
#include <stdio.h>


int main()
  {
     int i;
     int arr[3] = {1,2,3};
     int* p_data = arr;

     /*指针变量数据的偏移*/
     for(i=0;i<3;i++)
       {
	      printf("%d\t",*(p_data+i));
       }
     printf("\n");


     /*指针变量地址的偏移*/
     for(i=0;i<3;i++)
       {
	      printf("%p\n",p_data+i);
       }
	 return 0;
  }

指针偏移遍历方法二:(此方法由注意事项)

p_data = arr;        //下面的指针每遍历一轮就需要重新指定数组的头

for(i=0;i<3;i++)

  {

         printf("%d",*(p_data++));

  }


 6、指针和数组名的关系(面试需要)

【1】指针当作数组名的下表法访问:04_pointer4.c

【2】数组名当指针用:   04_pointer4.c

/*
 *           指针和数组名的关系
 */

#include <stdio.h>

int main()
  {  
    int i;
    int arr[3] = {1,2,3};

    int* p_data = arr;

    /*****指针当作数组名的下表法访问*****/
    for(i=0;i<3;i++)
      {
         printf("%d\n",p_data[i]);         //此时p_data[1] 和 arr[1]等价
      }


    /**********数组名当指针用***********/
    for(i=0;i<3;i++)
      {
         printf("%d\n",*(arr+i));          //此时*(arr+1) 和 *(p_data+1)等价
      }


      return 0;
  }

【3】printf("%d",*(arr++));       //*(arr++)是不允许的        这里的arr是指针常量

     注:1】指针常量:指针常量指向的对象是可以修改的,但指针本身是不可以修改地址的。

            2】指针变量:是存储地址的变量。它可以存储对象或函数的地址。

【4】sizeof(指针)  和   sizeof(数组)

    1】printf("%d\n",sizeof(arr));            //占12个字节        数组中有3个元素   x    int类型 4Byte    =  12 Byte

    2】printf("%d\n",sizeof(p_data));     //占8个字节           在64位系统中所有的指针变量都是8个字节    


练习:  将数组中的n个元素按逆序输出(用函数实现功能)05_pointer5.c

/*
 *          练习:将数组中的n个元素按逆序输出(用函数实现功能)
 */

#include <stdio.h>


void Reverse_output(int* p_data,int len)
   {
      int i = 0;
      for(i=len-1;i>=0;i--)
        {
           printf("%d\t",*(p_data+i));
	} 
   }

int main()
  {
      int arr[5];
      int i;
      
      int len = sizeof(arr)/sizeof(arr[0]);     //计算数组的长度

      printf("请输入数组中的元素\n");
      for(i=0;i<len;i++)
        {
            scanf("%d",&arr[i]);
	}
      
      Reverse_output(arr,len);

      return 0;
  }

二维数组:二维数组的每一项都是一个数组。

7、二维数组的地址:06_pointer6.c

【1】一维数组中的每一项 " a[0] " 是数组的值

【2】二维数组中每一项 " a[0] " 是数组的地址

例:

int arr[2][3];

arr[1]:是一个数组名,数组中包含了3个元素。

 arr:是数组名,是整个二维数组的首地址

 arr[0][0] = arr[0]

/*
 *         二维数组的地址问题:
 */

#include <stdio.h>


int main()
{   
    int arr[2][3]; 

    printf("二维数组的地址:%p\n",arr);
    printf("元素arr[0]:%p\n",arr[0]);
    printf("元素arr[1]:%p\n",arr[1]);
    printf("元素arr[0][0]:%p\n",&arr[0][0]);
    printf("元素arr[0][1]:%p\n",&arr[0][1]);

      return 0;
}

【3】二位数组的首地址 :  int  arr[2][3];

(1)arr              :      二维数组的数组名

(2)arr[0]          :      二维数组的首元素

(3)&arr[0][0]   :       二维数组中首元素的首地址      

             arr[0]      等价于      &arr[0][0]

数组表示首地址:[1]数组名

                             [2]数组首元素的地址

【4】二维数组偏移问题:           把数组名当指针用

int arr[2][3];

(1)arr                         :数组名

(2)arr[0]                     :  数组首元素

    *(arr+1) 

  

(3)arr[0]+1                 :  arr[0]+1   :表示地址偏移是个指针

    *(arr+0)+1

(4)*(arr[0]+1)             :  表示arr[0][1] 的值

    *(*(arr+0)+1)


 8、数组指针 :数组指针就是指向数组的指针变量。它存储数组的地址,通过这个地址可以访问整个数组。

注: 

 :数组指针等同于二维数组名

 :定义一个指针指向一个数组 

【1】如何定义一个数组指针

类型     (*数组名)[大小];

int        (*arr)[10];             //二维数组中一项中有几个元素,[ ] 中就填写几。

例:

int  arr[2][3];              //定义一个二维数组

int  (*p_arr)[3];          //定义一个数组指针

【2】如何使用数组指针:数组指针每次偏移指向的都是一个数组  07_pointer7.c

/*
 *         如何定义一个数组指针并使用
 *         数组指针等同与数组名
 */

#include <stdio.h>


int main()
  {
	int i;
	int j;
	int arr[2][3] = {
		               {1,2,3},
			           {4,5,6}
	                };

	int (*p_arr)[3];

	p_arr = arr;

        /**********通过指针数组遍历二维数组********/
        for(i=0;i<2;i++)
	  {
	      for(j=0;j<3;j++)
	        {
		     printf("%d\t",*(*(p_arr+i)+j));
		}
	      printf("\n");      //打印完一项换行
	  }
	printf("done!\n");
  }

练习:输出二维数组任意行、列的数  (函数实现)     08_pointer8.c

/*
 *       数组指针:
 *       题目:输出二维数组任意行、列的数(函数实现)
*/

#include <stdio.h>

/***********输出任意行列的值***********/
void output_lineAndlie(int (*p_arr)[4],int line,int lie)
  {
        printf("第%d行第%d的值是:%d\n",line+1,lie+1,*(*(p_arr+line)+lie));    
  }


int main()
  {
     int line;     //行
     int lie;      //列
		   //
     int arr[3][4] = {
	                    {1,2,3,4},          //line 1
			            {5,6,7,8},          //line 2
			            {9,10,11,12}        //line 3
                     };

     printf("请输入行:");
     scanf("%d",&line);
     printf("请输入列:");
     scanf("%d",&lie);

     output_lineAndlie(arr,line,lie);
	return 0;
  }

9、函数指针

【1】函数指针的定义:如果在程序中定义了一个函数,在编译时,编译系统为函数代码分配一段存储空间,这段存储空间的起始地址(又称入口地址)

         称为这个函数的指针。 

注:函数名就是地址(函数的起始地址)

注:函数指针是指向函数的变量

注:可以根据程序运行的不同情况,调用不同的函数

【2】定义函数指针变量

   类型   (*变量名)(形参);

   int      (*func)(int data);

【2】通过函数指针调用函数  

       void  func(int data)                      //创建一个函数

          {

          }

       void (*p_func)(int data);             //定义函数指针变量

       p_func  =  func;                         //函数指针指向函数

       (*p_func)(data);                         //调用函数

 【2】附代码:通过函数指针调用函数     09_pointer9.c

/*
 *        通过函数指针调用函数
 */

#include <stdio.h>


/******创建一个函数*****/
void func(int data) 
   {
       printf("函数指针测试:");
       printf("data = %d\n",data);
   }

int main()
  {
      int data = 10;
      void (*p_func)(int data);       //创建一个函数指针
      p_func = func;                  //函数指针指向函数
      (*p_func)(data);                //调用函数
         return 0;
  }

练习 : 有两个整数a和b,由用户输入1,2或3。如输入1,程序就给出a和b中大者,输入2,就给出a和b中小者,输入3,则求出a与b之和。10_pointer10.c

/*
 *        练习 : 有两个整数a和b,由用户输入1,2或3。如输入1,程序就给出a和b中大者,输入2,就给出a和b中小者,输入3,则求出a与b之和。
 */
#include  <stdio.h>

/*****最大值*****/
int outBigNum(int num1,int num2)
  {
      if(num1 > num2)
       {
	    printf("最大值为num1,值为 %d\n",num1);
       }
      else
         {
	     printf("最大值为num2,值为 %d\n",num2);
	 }
	  return 0;
  }

/*****最小值*****/
int outSmallNum(int num1,int num2)
  {
	if(num1 < num2)
	 {
	      printf("最小值为num1,值为 %d\n",num1);
	 }
	else
	  {
		  printf("最小值为num2,值为 %d\n",num2);
	  }

	return 0;
  }

/******求和******/
int sumNum(int num1,int num2)
  {
        int sum = 0;
	sum = num1 + num2;
	printf("两数字之和为:%d\n",sum);
  }

int main()
  {
	  int InData;        //用户输出
	  int num1 = 10;
	  int num2 = 20;


	  int (*p_func)(int num1,int num2);     //创建一个函数指针

	  printf("提示:\n 输入1求最大值\n 输入2求最小值\n 输入3求和\n");
	  scanf("%d",&InData);
	  switch(InData)
	      {
		   case 1:{
			      p_func = outBigNum;       //函数指针指向函数(函数名是地址 )
			      (*p_func)(num1,num2);     //调用函数(函数指针)   
			  };break;
		 
		   case 2:{
			      p_func = outSmallNum;
			      (*p_func)(num1,num2);
			  };break;
		   case 3:{
			      p_func = sumNum;
			      (*p_func)(num1,num2);
			  };break;	
	      }
  }

10、指针数组:一个数组,若其元素均为指针类型数据 ,称为指针数组。

【1】定义一个指针数组

  类型   数组名[数组长度] ;

  int*  p[5];       //数组里面的每一项都是一个指针变量

特殊用法:int (*parr[5])(int  data);        //函数指针数组          //指针数组的每一项指向一个函数 

函数指针初始化 :int (8parr[3])(int  data) = {func1,func2,func3};

 【1】附代码:11_pointer11.c

/*
 *       指针数组示例
 *       指针数组就是一个,每一项都是指针的数组
 */

#include <stdio.h>
#include <stdlib.h>
int main()
  {
      int i;
      int data1 = 10;
      int data2 = 20;
      int data3 = 30;
      int data4 = 40;

      int* arr[4] = {&data1,&data2,&data3,&data4};       //指针数组 :数组中每一项都是指针。
      
      for(i=0;i<4;i++)
        {
            printf("%d\n",*arr[i]);        //输出指针数组的每一项
	}
      
      
	  return 0;
  }

11、指针函数 :返回值的类型是指针类型


12、二级指针: int** p;

【1】多级指针存放的是指针变量的地址

【2】定义二级指针:int**  p;

【3】二级指针示意:

                  int    ⬅     int*    ⬅       int** 

【4】二级指针用来存储一级指针的地址 

              数据类型**   指针变量名   =   & 一级指针变量名;

 【5】二级指针图示;

代码验证:12_pointer12.c

#include <stdio.h>
/*
     二级指针示意:
        int  ←  int*  ←  int**
*/
int  main()
        {
			int data = 100;
			int *pointer;
			int **pointer2;
			pointer  = &data;
			pointer2 = &pointer;
			puts("地址:");
		        printf("data的地址是:%p\n",&data);			
			printf("pointer的地址是:%p\n",&pointer);
			printf("pointer2的地址是:%p\n",pointer2);
			
			puts("值:");
			printf("*pointer的值是:%d\n",*pointer);
			printf("*pointer2的值是:%p\n",*pointer2);
			printf("**pointer2的值是:%d\n",**pointer2);
			puts("done!");
		    
                       return 0;
        }

【5】总结:

          在二级指针中,int**  p;

          p        是一个地址(二级指针首地址)

          *p      是一个地址

          **p     是一个具体的值


注: 一些平时不会注意的操作:

int *   p_data    ,    p_str;

p_data    是一个指针变量

p_str       是一个整型变量

附:本文中所有代码

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值