C语言第六章之指针

一、指针变量

1、指针=地址

指针变量:存放地址的变量

int main()
{
	int a=10;
	int *p;
	p=&a;
	printf("变量名访问a:%d\n",a);
	printf("a的地址是:0x%p\n",&a);
	printf("地址访问a:%d\n",*(&a));
	printf("指针变量的方式访问a:%d\n",*p);
	return 0;
}

2、指针需要要求类型

int main()
{
	int a=0x1234;
	int *p=&a;
	char *c=&a;
	
	printf("p=%p\n",p);
	printf("p=%p\n",c);
	
	printf("a=%x\n",*p);//取值出了问题,取值运算符会根据指针变量类型,访问不同大小的的空间
	printf("a=%x\n",*c);
	
	printf("++p=%p\n",++p);
	printf("++p=%p\n",++c);
	return 0;
}

3、使用指针的场景


//为什么使用指针,通过函数封装来修改被调函数的值,指针间接访问
void changeData(int *data1,int *data2)
{
	int temp;
	temp=*data1;
	*data1=*data2;
	*data2=temp;
}

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

//为什么使用指针,指针指向固定的区域
int main()
{
	int a=10;
	printf("address of a is 0x%p\n",&a);
	
	volatile unsigned  int *p=(volatile unsigned int *)0x000000000061FE2C;
	
	printf("p=0x%p\n",p);	
	return 0;
}

4、小练手:输入三个数,由大到小输出

void changeData(int *a,int *b,int *c)
{
	int t;
	if(*a<*b)
	{
		t=*a;*a=*b;*b=t;
	}
	if(*a<*c)
	{
		t=*a;*a=*c;*c=t;
	}
	if(*b<*c)
	{
		t=*b;*b=*c;*c=t;
	}

}

int main()
{
	int a,b,c,t;
	printf("请输入a的值:\n");
	scanf("%d",&a);
	printf("请输入b的值:\n");
	scanf("%d",&b);
	printf("请输入c的值:\n");
	scanf("%d",&c);
	
	printf("交换前:a=%d b=%d c=%d\n",a,b,c);

	changeData(&a,&b,&c);
	
	printf("排序之后的结果由大到小为:%d>%d>%d",a,b,c);

	return 0;
}

二、通过指针引用数组

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

2、指针增量和数组的关系

3、通过指针引用数组元素

(1)下标法

(2)指针法

a、偏移
b、取内容
指针当做数组名,下标法访问
int main()
{
	int arr[3]={1,2,3};
	int *p=arr;
	
	printf("%d  ",*p);
	return 0;
}

int main()
{
	int arr[3]={1,2,3};
	int *p=arr;
	
	printf("%d  ",p[2]);
	return 0;
}

数组名拿来加
int main()
{
	int arr[3]={1,2,3};
	int *p=arr;
	
	
	for(int i=0;i<3;i++)
	{
		printf("%d  ",*(p+i));
        printf("%d  ",*(arr+i));
	}
	
	return 0;
}

数组名和指针的区别:
arr++是否可行?不可行!

p是指针变量,是一个保存地址的变量,保存的地址是可改的

arr是个常量,地址定了就是定了,

sizeof:
printf("sizeof arr is %d\n",sizeof(arr));//3*4=12
printf("sizeof arr is %d\n",sizeof(p);//os用八个字节表示一个地址

(3)两种方法效率对比

4、小练习1:

//函数封装数组初始化,遍历,指针加数组加函数封装
void initArray(int *parr,int size)
{
	for(int i=0;i<size;i++)
	{
		printf("请输入第%i个元素的值:\n",i+1);
		scanf("%d",parr++);
	}
}
void printArray(int *parr,int size)
{
	for(int i=0;i<size;i++)
	{
		printf("第%d个元素的值:%d\n",i+1,*parr++);
	}
}

int main()
{
	int arr[5];
	int size=sizeof(arr)/sizeof(arr[0]);
	
	initArray(arr,size);//实际参数,数组首地址,首个元素的地址
	printArray(&arr[0],size);



	return 0;
}

5、小练习2:逆序输出

//将数组中的n个元素按逆序存放
void initArray(int *parr,int size)
{
	for(int i=0;i<size;i++)
	{
		printf("请输入第%i个元素的值:\n",i+1);
		scanf("%d",parr++);
	}
}
void printArray(int *parr,int size)
{
	for(int i=0;i<size;i++)
	{
		printf("第%d个元素的值:%d\n",i+1,*parr++);
	}
	putchar('\n');
}
void revangeArry(int *parr,int size)
{
	int i,j,t;
	for(i=0;i<size/2;i++)
	{	
		j=size-1-i;
		t=*(parr+i);
		*(parr+i)=*(parr+j);
		*(parr+j)=t;
	}
	
}

int main()
{
	int x;
	printf("几个数?");
	scanf("%d",&x);
	int arr[x];
	int size=sizeof(arr)/sizeof(arr[0]);

	initArray(arr,size);
	printArray(&arr[0],size);
	revangeArry(arr,size);
	printArray(&arr[0],size);

	return 0;
}

三、指针和二维数组

二维数组中上官特有说法:父子数组
为了研究清楚地址的概念,把二维回归到一维数组

二维数组本质还是数组,不同点是数组元素还是个数组(子数组)

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

书立认知

总结

四、数组指针

int main()
{
	int arr[3][4]={{11,22,33,44},{12,13,15,17},{22,44,66,88}};
	int i,j;
	int *p;
//	p=&arr[0][0];
	//p=arr;
	//能不能定义一个指针,让指针偏移的时候,也偏移对应大小的数组?
	//数组指针,定义一个指针,指向一个数组!
	//数组指针才是真正等同于二维数组名
	int (*p2)[4];
	p2=arr;
	//printf("p2=%p\n",p2);
	//printf("p2=%p\n",++p2);
	for(i=0;i<3;i++)
	{
		for(j=0;j<4;j++)
		{
			printf("0x%p    ",arr[i]+j);
			printf("%d\n",*(*(p2+i)+j));
		}
		//putchar('\n');
	}
	return 0;
}

五、函数指针

1、定义:

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

函数名就是地址,数组名就是地址

2、如何定义

3、使用

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


int main()
{
	void (*p)();//定义一个函数指针
	p=printWelcome;
	printWelcome();
	(*p)();//调用
	
	return 0;
}

直接访问:变量名(函数名)

间接访问:指针(函数指针)

六、指针数组

注意与数组指针的区别

//指针数组
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;
}

它是数组,数组的每一项都是一个指针变量

七、指针函数

返回指针的函数


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,70},
		{11,22,33,44}	};
	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

差别就是保存的是指针变量的地址

当你通过函数调用来修改调用函数指针指向的时候,

就像通过函数调用修改某变量的值的时候一样

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

九、总结

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值