2.15上官c语言学习

本文详细介绍了C语言中指针的基础知识,包括指针变量的定义、使用方法、指针与数组的关系、函数指针、二级指针以及它们在数据交换、数组操作和函数返回地址中的应用。通过实例展示了指针在提高程序效率和封装功能中的重要性。
摘要由CSDN通过智能技术生成

第六章 指针

目录

第六章 指针

认识

如何定义一个指针变量 

如何使用一个指针变量

变量访问的两种方式

为什么需要指针

指针引用数组 

二维数组 

数组指针 

函数指针

指针数组

指针函数

二级指针


认识

指针=地址 

*(&a)取值运算符:把他后面跟的内存地址中的数据取出来

如何定义一个指针变量 

 int *p;——*只产生在指针变量定义或者声明的时候

如何使用一个指针变量

*的运算作用

变量访问的两种方式
  1. 直接访问——直接按变量名访问
  2. 间接访问——将变量i的地址存放在另一个变量中,然后通过变量来找到变量i的地址,从而访问i变量
int a =10;
int *p;
p=&a;
为什么需要指针

封装函数,实现两个数的交换

#include<stdio.h>
void changedata(int *pdata,int *pdata2)
{
	int tmp;
	tmp=*pdata;
	*pdata=*pdata2;
	*pdata2=tmp;
	
	
}

int main()
{
	int data=10;
	int data2=20;
	
	printf("交换前data=%d,data2=%d",data,data2);
	
	changedata(&data,&data2);
	
	printf("交换后data=%d,data2=%d",data,data2);
	
	
	
	return 0;
 }

指针指向固定区域zz

#include<stdio.h>
int main()
{
	int a =10;
	printf("address of a is 0x%p\n",&a);
	int *p=(int*)0x000000000061FE33;
	
	printf("p=0x%p\n",p);
	
	return 0;
}
指针引用数组 
  • 定义一个指针变量指向数组
int a[10]={12,432,543213,23,12,3432,123,12,43,232};
int *p;
p=&a[0];
  • 在c语言中数组名代表数组中首元素的地址,因此下面两个语句等价
p=&a[0];//p是a[0]的地址
p=a;//p的值是数组a的首元素(即a[0])的地址
  • 指针的增量和数组的关系
printf("首元素是%d\n",*p);
printf("1元素是%d\n",*(p+1));
printf("2元素是%d\n",*(p+2));
  • 通过指针引用数组元素
  1. 下标法
  2. 指针法
    1. 偏移
    2. 取内容

       见怪不怪的内容 :   

  • 指针当作数组名 ,下标法访问
    int arr[3]={1,2,3};
    int *p=arr;
    
    printf("%d",p[2]);

  • 数组名拿来加

   数组名和指针的区别

arr++不可行 指针常量不能++,指针变量可以++

8个字符表示一个地址

两种方法效率对比

系统在使用数组下标对数组成员变量进行访问时,开销较大,指针的访问效率时远远大于数组名的访问效率的。

但是只有在指针正确访问时,才成下标法更有效率。

下标法更容易理解,在可读性方面,也更加具有优势,具体怎么选择,也没有一定的说法 

练习:

函数封装数组初始化,遍历

#include<stdio.h>
void intiarray(int *parr,int size)
{
	int i;
	for(i=0;i<size;i++)
	{
		printf("请输入第%d个元素\n",i+1);
		scanf("%d",parr);
		parr++;
	}

}
void printarray(int *parr,int size)
{
	int i;
	for(i=0;i<size;i++)
	{
		printf("请第%d个元素是%d\n",i+1,*parr);
		parr++;
	}

}
int main()
{
	
	int array[5];
	int size=sizeof(array)/sizeof(array[0]);
	
	intiarray(array,size);
	printarray(array,size);
	return 0;
} 

将数组中的n个元素按逆序存放 

#include<stdio.h>
void intiarray(int *parr,int size)
{
	int i;
	for(i=0;i<size;i++)
	{
		printf("请输入第%d个元素\n",i+1);
		scanf("%d",parr);
		parr++;
	}

}
void printarray(int *parr,int size)
{
	int i;
	for(i=0;i<size;i++)
	{
		printf("请第%d个元素是%d\n",i+1,*parr);
		parr++;
	}

}
void revangearray(int *parr,int size)
{
	int i,j;
	int tmp;
	
	for(i=0;i<size/2;i++)
	{	/*
		j=size-1-i;
		tmp=parr[i]; 
		parr[i]=parr[j];
		parr[j]=tmp;
		*/
		j=size-1-i;
		tmp=*(parr+1); 
		*(parr+i)=*(parr+j);
		*(parr+j)=tmp;
	}
	
}
int main()
{
	
	int array[5];
	int size=sizeof(array)/sizeof(array[0]);
	
	intiarray(array,size);
	revangearray(array,size);
	printarray(array,size);
	return 0;
}  
二维数组 

父子数组——把二维回归到一维  

int a [3][4]举例 a[0]既是数组名也是子数组的首地址

&a[0][0]=a[0] 

a是 行的地址 a+1是整行加1到下一行

a[0]是子数组的地址 

*a  = a [0]   a[0]=*(a+1)   a[0]+1=*(a+1)+1

#include<stdio.h>
int main()
{
	int arr[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12,}};
	
	/*printf("arr是父亲地址;%p,偏移1后是%p\n",arr,arr+1);	
	printf("arr[0]是子数组地址%p,偏移1后地址是%p\n",arr[0],arr[0]+1);
	printf("arr[0]是子数组地址%p,偏移1后地址是%p\n",*(arr+0),*(arr+0)+1);
	*/
	
	int i;
	int j;
	
	for(i=0;i<3;i++)
	{
		for(j=0;j<4;j++)
		{
		printf("add:0x%p,data=%d \n",&arr[i][j],arr[i][j]);
		printf("add:0x%p,data=%d \n",arr[i]+j,*(arr[i]+j));
		printf("add:0x%p,data=%d \n",*(arr+i)+j,*(*(arr+i)+j));
		}
		
	}
	return 0; 
}

数组指针 
#include<stdio.h>
int main()
{
	int arr[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12,}};//arr++
	int i,j;
	int *p;//p++
	//p=&arr[0][0]
	//p=arr;
	//能不能定义一个指针,让指针偏移的时候也偏移相应对应大小的数组
	//数组指针,定义一个指针,指向一个数组
	int (*p2)[4];
	p2=arr;
	for(i=0;i<3;i++)
	{
		for(j=0;j<4;j++)
		{
			printf("%d\n",*(*(p2+i)+ j));
		}
	}
	return 0; 
}

数组指针才是真正等同于二维数组名

练习

#include<stdio.h>
void tipsinput(int *pm,int *pn)
{
	printf("请输入行列值\n");
	scanf("%d%d",pm,pn);
	puts("done\n");
} 
int getthedata(int (*p)[4],int hang,int lie)
{
	int data;
	data=*(*(p+hang)+lie);
	return data;
}
int main()
{
	int arr[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12,}};//arr++
	int ihang,ilie;
	int data;
	//1.输入行列值
	tipsinput(&ihang,&ilie);
	//2.找出对应行列值的那个数
	data=getthedata(arr,ihang,ilie);
	//3.打印
	printf("%d行%d列的值是%d",ihang,ilie,data);
	
	return 0;
}
函数指针
  • 定义函数地址——如果在程序中定义了一个函数,在编译时,编译系统为函数代码分配一段存储空间,这段存储空间的起始地址(又称入口地址)称为这个函数的指针

        函数名就是地址 

  • 如何定义一个函数指针变量——和普通变量一样 ——

        int a;int *p;     char c;char *p;     int getdata(int a,int b);int (*p)(int a,int b);

  •  使用函数指针——函数调用概念和变量一样——

                直接访问:变量名(函数名),间接访问:指针(函数指针)

#include<stdio.h>
void printwelcome()
{
	puts("welcome");
}
int main()
{
	
	void(*p)();//定义一个函数指针变量
	p = printwelcome;//指向函数
	printwelcome();
	(*p)();//调用
	
	return 0;
}

练习 

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

#include<stdio.h>
int getmax(int data1,int data2)
{
	return data1>data2?data1:data2;
}

int getmin(int data1,int data2)
{
	return data1<data2?data1:data2;
}

int getsum(int data1,int data2)
{
	return data1+data2;
}
int datahandler(int data1,int data2,int (*pfunc)(int data1,int data2))
{
	int ret;
	ret=(*pfunc)(data1,data2);
	return ret;
	
}
int main()
{
	int a=10;
	int b=20;
	int cmd;
	int ret;
	
	int (*pfunc)(int data1,int data2);
	printf("请输入1(取最大值),2(取最小值),3(求和)\n");
	scanf("%d",&cmd);
	switch(cmd)
	{
		case 1:
			pfunc=getmax;
		break;
		case 2:
			pfunc=getmin;
		break;
		case 3:
			pfunc=getsum;
		break;
	}
	ret=datahandler(a,b,pfunc);
	printf("result=%d\n",ret);
	
	return 0;
}
指针数组

一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都存放一个地址,相当于一个指针变量。下面定义一个指针数组:int *p[4] 

由于[]比*优先级高,因此p先与[4]结合,形成p[4]的形式,这显然是数组的形式,表示p数组有四个元素。然后在与p前面的*结合,*表示此数组是指针类型的,每个数组元素(相当于一个指针变量)都可以指向一个整型变量。

tips:不要写成int (*p)[4]——类型名 *数组名[数组长度]

注意和数组指针的区别

#include<stdio.h>
int main()
{
	int a=10;
	int b=20;
	int c=30;
	int d=40;
	
	int *p[4]={&a,&b,&c,&d};
	
	int i;
	for(i=0;i<4;i++)
	{
		printf("%d ",*(p[i]) );
	}
	
	return 0;
} 
指针函数

一个函数可以返回一个整型值、字符值、实型值等,也可以返回指针型的数据,即地址其概念与以前类似,只是返回的值的类型是指针类型而已。
例如“int * a(int x,int y);”,a 是函数名,调用它以后能得到一个 int *型(指向整型数据)的指针,即整型数据的地址。x和y是函数a的形参,为整型。
请注意在*a两侧没有括号,在a的两侧分别为* 运算符和()运算符。而()优先级高于*,因此a先与()结合,显然这是函数形式。这个函数前面有一个*,表示此函数是指针型函数(函数值是指针)。最前面的 int 表示返回的指针指向整型变量。

例题

#include<stdio.h>
int* getposperson(int pos,int(*pstu)[4])//函数指针,返回指针的函数
{
	int *p;
	p=pstu+pos;
	
	return p;
}
int main()
{
	
	int scores[3][4]={{12,657,56,534},{213,543,324,657},{432,543,765,845}};
	int *ppos;
	int pos;
	
	printf("请输入你想知道第几个学生的成绩");
	scanf("%d",&pos);
	
	ppos=getposperson(pos,scores);
	
	for(int i=0;i<4;i++)
	{
	printf("%d ",*ppos++);
	}

	return 0;
} 
二级指针

写法 int **p

#include<stdio.h>
int main()
{
	int data=100;
	int *p=&data;
	printf("data的地址是:%p\n",&data);
	printf("p保存data的地址是:%p,内容是%d\n",p,*p);
	
	printf("p的地址是:%p\n",&p);
	
	int *pp=&p;
	printf("pp保存的p地址是:%p\n",pp);
	printf("*pp是%p\n",*pp);
	
	int **p2;
	p2=&p;
	printf("p2保存的p地址是:%p\n",p2);
	printf("*p2是%p\n",*p2);
	printf("**p2来访问data:%d\n",**p2);
	return 0;
}

和一级指针一样 区别就是:保存的是指针的地址

上一个题目用二级指针的写法

#include<stdio.h>
void getposperson(int pos,int(*pstu)[4],int **ppos)//函数指针,返回指针的函数
{
	*ppos=(int *)(pstu+pos);
	
}
int main()
{
	
	int scores[3][4]={{12,657,56,534},{213,543,324,657},{432,543,765,845}};
	int *ppos;
	int pos;
	
	printf("请输入你想知道第几个学生的成绩");
	scanf("%d",&pos);
	
	getposperson(pos,scores,&ppos);
	
	for(int i=0;i<4;i++)
	{
	printf("%d ",*ppos++);
	}
	
	return 0;
} 

二级指针和二维数组的关联

二级指针不能简单粗暴的指向二维数组

#include<stdio.h>

int main()
{
	
	int scores[3][4]={{12,657,56,534},{213,543,324,657},{432,543,765,845}};//int (*p)[4]
	
	int **p;
	p =scores;
	
	printf("scores:%p\n",scores);
	printf("p=%p\n",p);
	printf("*p=%p\n",*p);//*p是野指针不是认为的会编程列地址
	printf("*scores:%p\n",*scores);
	
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值