c语言-指针

什么是指针和指针变量

指针就是地址:

#include<stdio.h>

int main()
{
	int a=10;
	printf("a=%d\n",a);
	printf("a的地址是%p\n",&a);
	printf("a=%d\n",*(&a));//*是取值运算符,把内存中的数据取出来
}

*int a=10;
变量四要素:变量名,变量的类型,变量的值,地址
&是取地址运算符
将地址内的值读出运算符
变量访问有两种方式:
1.通过变量名访问;
2.通过地址访问(指针就是地址),可以说成通过指针访问。

什么是指针变量
指针变量就是存放别人地址的变量,而指针变量本身也有地址

#include<stdio.h>

int main()
{
	//什么是整型变量,存放整数型的变量
	//什么是字符变量,存放字符型数据的变量
	//什么是指针变量,存放指针的变量
	//什么是指针变量,存放地址的变量
	int a=10;
	int *p;//这里的*是告诉系统我是一个指针变量,是用来保存别人地址的我,与下方的运算符不同
	p=&a;
	printf("a=%d\n",a);
	printf("a的地址是%p\n",&a);
	printf("a=%d\n",*(&a));//*是取值运算符,把后面内存中的数据取出来
	printf("指针变量访问a=%d\n",*p);
}

*的作用:标识作用——只产生于指针变量定义或声明的时候;
运算作用:体现在如何使用一个指针变量
变量访问有两种方式:直接访问:通过变量名
间接访问:通过指针变量
为什么指针变量要区分类型?指针变量都是存放别人地址的变量?
int pint和char pchar
第一点:决定指向空间的大小:不同的类型,跨度是不同的;
第二点:决定增量。++p和++c的时候不同

#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("c=%x\n",*c);
	
	printf("++p=%p\n",++p);
	printf("++c=%p\n",++c);
	return 0;
}

为什么要用指针

1.封装一个函数,实现两个数的互换

#include<stdio.h>

int chageData(int *pdata1,int *pdata2)
{
	int temp;
	temp=*pdata1;
	*pdata1=*pdata2;
	*pdata2=temp;
}


int main()
{
	int data1=10;
	int data2=20;
	
	printf("交换前data1=%d,data2=%d\n",data1,data2);
	
	chageData(&data1,&data2);
	
	printf("交换后data1=%d,data2=%d\n",data1,data2);
	
	return 0;
}

如果不使用指针,直接这样交换,交换是无效的,因为交换只发生在chageData函数里,在局部变量里交换,无法转递到main主函数里,因为函数是转递值,所以必须使用指针不冲突,那么传递地址之后,在函数里交换的数就是主函数里的数,这样两个数就能成功交换。
2.指针指向固定的区域:

#include<stdio.h>

int main()
{
	int a=10;
	printf("address of a is 0x%p\n",&a);
	volatile unsigned int *p=(volatile unsigned int *)0x000000000061FE33;
	
	printf("p=0x%p\n",p);
	return 0;
}

3.输入三个数,无论怎么输入,都由小到大输出

#include<stdio.h>

int max(int *pa,int*pb)
{
	int temp;
	*pa=temp;
	*pa=*pb;
	*pb=temp;
}


int main()
{
	int a;
	int b;
	int c;
	printf("请输入三个数a,b,c:\n");
	scanf("%d%d%d",&a,&b,&c);
	
	if(a>b)
	max(&a,&b);

    if(a>c)
	max(&a,&c);

    if(b>c)
	max(&b,&c);
    
    printf("a,b,c从小到大排列:%d,%d,%d\n",a,b,c);
	return 0;
}

说明:原理与逻辑与两个数交换相同。

指针与数组,指针与二维数组

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

#include<stdio.h>

int main()
{
	int arr[3]={1,2,3};
	int *p;
	//p=&arr[0];//数组的首地址就是首个元素的地址
	p=arr;//数组名就是数组的首地址
	for(int i=0;i<3;i++){
        	//printf("address:0x%p,%d\n",(p+i),*(p+i));
			printf("%d ",*p++);
	}

*数组名就是数组的首地址:p=arr;
也可以指向数组首元素的地址:int p;p=&arr[0];

指针增量和数组的关系:
像游标卡尺一样。

通过指针引用数组元素:
1.下标法:
2.指针法:1.偏移
2.取内容:
指针当作数组名,下标法访问

#include<stdio.h>

int main()
{
	int arr[3]={1,2,3};
	int *p;
	//p=&arr[0];//数组的首地址就是首个元素的地址
	p=arr;//数组名就是数组的首地址
	for(int i=0;i<3;i++){
        	//printf("address:0x%p,%d\n",(p+i),*(p+i));
			printf("%d ",*p++);
	}
	p=arr;
	for(int i=0;i<3;i++){
        	//printf("address:0x%p,%d\n",(p+i),*(p+i));
			printf("%d ",*p++);
	}
	return 0;
}

数组名拿来加;
数组和指针的区别:*arr++是常量指针;
*p++是指针变量;
sizeof:表示8个字节


int main()
{
	int arr[3]={1,2,3};
	int *p=arr;
	
	printf("sizeof arr is %d\n",sizeof(arr));//3*4=12个字节
	printf("sizeof arr is %d\n",sizeof(p));//os 用8个字节表示一个地址
	printf("sizeof int is %d\n",sizeof(int));
	printf("sizeof pointer is %d\n",sizeof(int*));//os 用8个字节表示一个地址
	printf("sizeof pointer is %d\n",sizeof(char *));//os 用8个字节表示一个地址
	
	//printf("%d ",p[2]);
	printf("%d\n",*arr);
	for(int i=0;i<3;i++){
		printf("%d",p[i]);
	}
	putchar('\n');
	for(int i=0;i<3;i++){
		printf("%d",*(arr+i));
	}
	putchar('\n');
	/*for(int i=0;i<3;i++){
		printf("%d",*arr++);//编译不过,指针常量
	}*/
	putchar('\n');
	return 0;
}

练习:
1.函数封装数组初始化,遍历

#include<stdio.h>

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

void printArry(int *parr,int size)
{
	for(int i=0;i<size;i++){
		printf("%d ",*parr++);
	}
}

int main()
{
	int arr[5];
	int size=sizeof(arr)/sizeof(arr[0]);
	
	initArry(arr,size);
	printArry(arr,size);
	
	return 0;
}

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

#include<stdio.h>

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

void printArry(int *parr,int size)
{
	for(int i=0;i<size;i++){
		printf("%d ",*parr++);
	}
	putchar('\n');
}

void revange(int *parr,int size)
{
	int i,j;
	int temp;
	for(i=0;i<size/2;i++){
		j=size-1-i;
		temp=*(parr+i);
		*(parr+i)=*(parr+j);
		*(parr+j)=temp;
	}
}

int main()
{
	int arr[5];
	int size=sizeof(arr)/sizeof(arr[0]);
	
	initArry(arr,size);
	printArry(arr,size);
	revange(arr,size);
	printArry(arr,size);
	return 0;
}

指针与二维数组
二维数组可以说成父子数组;父数组——行数组
子数组——列数组
二维数组本质还是数组,不同的是数组元素是子数组。
思考:
a是谁的地址,a[0]又是谁的地址;a和(a+0)
a是父数组的地址
a[0],*a表示子数组的地址

#include<stdio.h>

int main()
{
	int arr[3][4]={{11,22,33,44},{12,13,15,16},{22,66,77,88}};
	
	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);
	return 0;
}

a[0]+1第0行第一列的地址,是地址的意思——*(a+0)+1
也是第0个子数组的第1个元素的地址
第0个子数组的第一个元素表示方式是a[0][1] 在这里插入图片描述

数组指针和指针数组

数组指针
概念:是指一个指向数组的指针,它其实还是一个指针,只不过是指向数组
写法:*int (p)[4];——4是代表列
指向一个含有4个元素的数组

#include<stdio.h>

int main()
{
	int arr[3][4]={{11,22,33,44},{12,13,15,16},{22,66,77,88}};
	
	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);
	return 0;
}

输出二维数组任意行列的数

#include<stdio.h>

void tishiInputHangle(int *pm,int *pn)
{
	printf("请输入行列值:\n");
	scanf("%d%d",pm,pn);
}

int getThedata(int (*p)[4],int hang,int lie)
{
	int data;
	data=*(*(p+hang)+lie);
	return data;
	//return p[hang][lie];
}

int main()
{
	int arr[3][4]={{11,22,33,44},{12,13,15,16},{22,66,77,88}};
	int ihang;
	int ilie;
	int data;
	//提示用户输入
	tishiInputHangle(&ihang,&ilie);
	//获取行列值	
	data=getThedata(arr,ihang,ilie);
	//打印结果
	printf("%d行%d列的值是%d",ihang,ilie,data);
}

指针数组
概念:是一个数组里装着指针,也就是指针数组是一个数组。
写法:int*a[10]——有一个优先级;a先与[10]结合
在这里插入图片描述
注意区分

#include<stdio.h>

int main()
{
	int a=10;
	int b=20;
	int c=30;
	int d=40;
	
	int *p[4]={&a,&b,&c,&d};
	for(int i=0;i<4;i++){
	    printf("%d ",*p[i]);
	}
	return 0;
}

函数指针数组

#include<stdio.h>
#include <stdlib.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 main()
{
	int a=10;
	int b=20;

	int ret;
	
	int (*func[3])(int data1,int data2)={getmax,getmin,getsum};//函数指针数组
	

    for(int i=0;i<3;i++){
		ret=(*func[i])(a,b);
		printf("%d ",ret);
	}
	return 0;
}
函数指针和指针函数

函数指针:
定义:如果在程序中定义了一个函数,在编译时,编译系统为函数代码分配一段存储空间,这段存储空间的起始地址(又称入口地址)称为这个函数的指针
指向函数的指针变量,本质就是个指针。
函数指针是一个指针变量
函数名就是地址
写法:**int (p)(int a,int b);——int (p)[4]一样写法

使用函数指针

#include<stdio.h>

int inCData(int data)
{
	return ++data;
}


void printWelcome()
{
	puts("程序启动,欢迎使用\n");
}

int main()
{
	void (*p)();//定义一个函数指针变量
	p=printWelcome;//指向函数
	(*p)();//调用
	int (*p2)(int data);
	p2=inCData;
	(*p2)(10);
	printf("p2测试:%d\n",(*p2)(10));
	return 0;
}

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

#include<stdio.h>
#include <stdlib.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 (*func)(int data1,int data2))
{
	int ret;
	ret=(*func)(data1,data2);
	return ret;
}

int main()
{
	int a=10;
	int b=10;
	int cmd;
	int ret;
	
	int (*func)(int data1,int data2);
	
	printf("请输入1(取大值),2(取小值),3(求和)\n");
	scanf("%d",&cmd);
	switch(cmd){
		case 1:
		      func=getmax;
		break;
		case 2:
		      func=getmin;
		break;
		case 3:
		      func=getsum;
		break;
		default:
		      printf("输入错误!@请输入1(取大值),2(取小值),3(求和)\n");
			  exit(-1);
		break;
	}
	ret=dataHandler(a,b,func);
	printf("ret=%d\n",ret);
	return 0;
}

指针函数:
返回指针值的函数
有a个学生,每个学生有b门课程的成绩,要求在用户输入学生序号以后能输出该学生的全部成绩,用指针函数。

#include<stdio.h>

int* getPosPerson(int pos,int (*pstu)[4])
{
	int *p;
	p=(int*)(pstu+pos);
	return p;
}

int main()
{
	int scores[3][4]={
		{55,66,77,88},
			{66,55,99,100},
				{11,22,33,59},
	};
	int *ppos;
	int pos;
	printf("请输入你需要看的学生号数:0,1,2\n");
	scanf("%d",&pos);
	
	ppos=getPosPerson(pos,scores);
	for(int i=0;i<4;i++){
		printf("%d ",*ppos++);
	}
	return 0;
}
二级指针

与一级指针一样,二级指针是保存指针变量的地址
写法:**int p
通过函数调用来修改函数指针指向

#include<stdio.h>

void getPosPerson(int pos,int (*pstu)[4],int **ppos)
{
    
	*ppos=(int*)(pstu+pos);

}

int main()
{
	int scores[3][4]={
		{55,66,77,88},
			{66,55,99,100},
				{11,22,33,59},
	};
	int *ppos;
	int pos;
	printf("请输入你需要看的学生号数:0,1,2\n");
	scanf("%d",&pos);
	
	getPosPerson(pos,scores,&ppos);
	for(int i=0;i<4;i++){
		printf("%d ",*ppos++);
	}
	return 0;
}

二级指针与二维数组

在这里插入图片描述

总结:在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值