c语言—指针非常全面、详细

目录

一、初步认识指针(一级)

二、数组指针

1.一维数组与指针

2.二维数组与指针

三、函数指针

四、指针数组

2.函数指针数组

五、指针函数

六、二级(多级)指针

七、指针定义的归纳


一、初步认识指针(一级)

        1.指针变量: 指针变量是一个特殊的变量,这个变量存储的是一个地址,也可以说指针就是一个地址。

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

        3.说明符:int a = *P, 说明符,说明这个p是一个存放地址的整型指针变量

        定义格式:类型  *(说明符)  指针名    例如 int *a、char *b

#include<stdio.h>

int main()
{
	//指针变量 存放指针 地址的变量
	//指针变量==存放地址的变量
	int a  = 10;
	int *P;//(*标识符)标识作用声明与定义 整型的指针变量 保存别人地址
	p = &a;//p存放是地址,&a是a的地址
	printf("%d\n",a);
	printf("0x%p\n",&a);//0x  地址十六进制 
	printf("%d\n",*(&a));//取值(运算符)运算作用,他把后面跟的内存地址中的数据”取出来“
	printf("%d\n",*p);//取值运算符
	return 0;
}

      

         4.指针类型:既然存放的是地址那为什么要有类型呢?难道地址有类型?当然不是,不管什么类型,地址都是4个字节。取值运算符会根据指针变量类型,访问不同大小的空间。

        例如:int *P访问4个字节、char *p访问1个字节如果char *p存放int 类型的变量的地址,那么char类型指针只能访问int类型变量(int类型 四个字节)的一个字节,从而丢失了三个字节。

#include <stdio.h>

int main()
{
	int a = 1234;
	int *p = &a;
	char *c = &a;//char类型指针 存放int类型变量
	
	printf("p = %p\n",p);//输出地址
	printf("c = %p\n",c);
	
	printf("a = %d\n",*p);//类型相同,输出正确
	printf("a = %d\n",*c);//变量类型与存放地址指针类型不同,空间大小不匹配,输出错误数据
	
	printf("++p = %p\n",++p);//自加1 类型所以含有的空间大小为一(4个字节)
	printf("++c = %p\n",++c);//(一个字节)
	return 0;
}

      

         5.为什么需要指针:指针的使用使得不同区域的代码可以轻易的共享内存数据,因为操作的是同一个地址上的数据。

#including<stdio.h>

void chageData(int *pdata, int *pdata2)
//用指针 给到的是与main相同的地址 所以交换的数值是在同一个地址上的数据
//不用指针 操作的是在新的空间地址上
{
	int tmp;
	tmp   = *pdata;
	*pdata  = *pdata2;
	*pdata2 = tmp;
}

int main()
{
	int data  = 10;
	int data2 = 20;
	
	printf("why point\n");
	printf("交换前:data=%d,data2=%d\n",data,data2);
	
	chageData(&data,&data2);//操作的是同一个地址上的数据
	
	printf("交换后:data=%d,data2=%d\n",data,data2);
}

    

二、数组指针

        是一个指针,指向数组的指针。

    

1.一维数组与指针

        1.指针的增量与数组的关系

#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 \n",*p);
		p++;//指针偏移加1,指向下一个地址(下一个数组元素)
	}
	
	
	p = arr;//防止越界 p+4越界出错
	for(int i = 0; i<3; i++){//第二种输出各个指针
		//printf("address:0x%p,%d \n",(p+i),*(p+i));//输出地址与数值
		printf("%d ",*p++);
	}
	/*
	printf("0元素是:%d\n",*(p+0));// +i  地址偏移一个类型大小
	printf("1元素是:%d\n",*(p+1));
	printf("2元素是:%d\n",*(p+2));
	*/
	return 0;
}

       运行结果:

      

        2.指针与数组名的奇怪用法

#include <stdio.h>

int main()
{
	int arr[3] = {1,2,3};//数组
	int *p = arr;//指针变量
	
	//sizeof计算大小,单位字节
	printf("sizeof arr is %d\n",sizeof(arr));//3*4=12
	printf("sizeof arr is %d\n",sizeof(p));// 指针都用8个字节表示一个地址
	printf("sizeof int is %d\n",sizeof(int));//4个字节
	printf("sizeof pointer is %d\n",sizeof(int *));// 用8个字节表示一个地址
	printf("sizeof pointer is %d\n",sizeof(char *));// 用8个字节表示一个地址
	//printf("%d ",p[2]);
	
	printf("%d \n",*arr);//取首地址的元素
	for(int i = 0; i<3; i++){
		printf("%d ",p[i]);//(2)指针当作数组名用
	}
	
	putchar('\n');

	for(int i = 0; i<3; i++){//(3)数组拿来加
		printf("%d ",*(arr+i));
	}
	
	putchar('\n');
	/*
	for(int i = 0; i<3; i++){
		printf("%d ",*arr++);//编译不过,指针常量  数组为固定大小空间数值无法改变与指针不同
	}*/
	putchar('\n');
	return 0;
}

运行结果:

    

        3.指针代替数组函数分装

#include <stdio.h>

void initArray(int *parr, int size)//传递的数组用指针代替 parr为地址
//指针间接的在main空间里面操作
{
	int i;
	for(i=0;i<size;i++){
		printf("请输入第%i个元素的数据:\n",i+1);
		scanf("%d",parr++);//输完之后加(地址)
	}
}
void printArray(int *parr, int size)
{
	int i;
	for(i=0;i<size;i++){
		printf("%d ",*parr++);//取地址的值
	}
}

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

 运行结果:

     

        4.例:将输入数据按倒序输出

                想法:数字是数组下标

                 

#include <stdio.h>
//name , params, returnValue

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


void revangeArry(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;
	}
	
}

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

int main()
{
	int arry[5];
	int size = sizeof(arry)/sizeof(arry[0]);
	
	initArray(arry,size);//实际参数,数组的首地址: 名,首个元素的地址
	printArray(&arry[0],size);//输出数组
	revangeArry(arry,size);//把数组倒序
	printArray(&arry[0],size);//输出倒序数组
	return 0;
}

 运行结果:

      

2.二维数组与指针

          1.说明介绍

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

        a表示父数组的地址,a[0],*a表示子数组的地址

        各种表示形式的含义

    

         2.数组名与偏移与地址

#include <stdio.h>

int main()
{
	int arr[3][4] = {{11,22,33,44},{12,13,15,16},{22,66,77,88}};
	int arr1[4] = {11,22,33,44};
	
	//二维
	printf("1arr是父亲地址:%p,偏移1后是%p\n",arr, arr+1);//偏移4列*4字节=16
	
	printf("2arr[0]是子数组地址;%p,偏移1后是%p\n",arr[0],arr[0]+1);//4字节
	//对二维数组名取内容=数组的首地址
	printf("3arr[0]是子数组地址;%p,偏移1后是%p\n",*(arr+0),*(arr+0)+1);//4字节
	printf("4arr[0]是子数组地址;%P,偏移1后是%p\n",*arr,*(arr+1));
	printf("5arr[0]是子数组地址;%d,偏移1后是%d\n",*arr,*(arr+1));//不可取值
	
	//一维
	printf("6arr[0]是子数组地址;%p,偏移1后是%p\n",arr1[0],(arr1[0]+1));//错
	printf("7arr[0]是子数组地址;%p,偏移1后是%p\n",*(arr1+0),*((arr1+0)+1));
	printf("8arr[0]是子数组地址;%P,偏移1后是%P\n",*arr1,*(arr1+1));
	printf("9arr[0]是子数组地址;%d,偏移1后是%d\n",*arr1,*(arr1+1));//可取值
	
	return 0;
}

运行结果:

     

        3.输出数组地址数值

#include <stdio.h>

//arr,arr[0]
int main()
{
	int arr[3][2] = {{11,22},{32,44},{55,66}};
	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));//方式三 arr[i]地址==*(arr+i)地址
			printf("===========================================\n");
		}
		putchar('\n');
	}
	
}

运行结果:

      

        4. 数组指针   

数组指针定义:int (*p2)[i];

int 类型,p2是数组指针名,i是二维数组列数

#include <stdio.h>

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

运行结果:

       

        5.例:输入行列用指针取数组值

#include <stdio.h>

int getTheData(int (*p)[4],int hang,int lie)//了解二维数组对应的数组指针的用法
{
	int data;
	data = *(*(p+hang-1)+lie-1);
	return data;
	//return p[hang-1][lie-1];//把p当作数组名用
}
void tipsInputHangLie(int *pm, int *pn)
{
	printf("输入行列值:\n");
	scanf("%d%d",pm,pn);
	puts("done!");
}
//arr,arr[0]
int main()
{
	int arr[3][4] = {{11,22,33,44},{12,13,15,16},{22,66,77,88}};//arr+
	int ihang,ilie;
	int data;
	
	
	tipsInputHangLie(&ihang,&ilie);//输入行列值
	data = getTheData(arr,ihang,ilie);//找出对应行列值的那个数
	printf("%d行%d列的值是%d\n",ihang,ilie,data);//输出这个数
}

运行结果:

    

三、函数指针

        指向函数的指针,函数名就是地址。

 函数指针定义:int (*p2)(x);

int返回值类型,p2函数指针名,x是传递参数的类型与名(例如int data)

        1.函数指针定义与调用

#include<stdio.h>

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

void printwelcome()
{
	puts("欢迎来到地球");
}

int main()
{
	int a = 10;
	int *pa;
	pa = &a;
	printf("%d\n",*pa);
	
	int (*p2)(int data);//定义一个函数指针变量
	p2 = invdata;
	(*p2)(10);//调用传递实参
	printf("%d\n",(*p2)(10));
	
	void (*P)();//定义一个函数指针变量
	P = printwelcome;//对指针给地址
	//void (*P)(printwelcome);//定义
	printwelcome();//调用
	(*P)();//调用
	return 0;
}

运行结果:

     

四、指针数组

        是一个数组 ,数组里每一个元素都是一个地址(相当于由一群指针变量组成的数组)

     

         1.指针数组的定义及使用

#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;
}

运行结果:

     

        2.函数指针数组

        由函数指针组成的数组。

函数指针数组定义:int (*pfunc[ i ])(x)

int是类型,pfunc函数指针数组名称,i是元素个数,x是传递参数的类型与名

#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 (*pfunc[3])(int , int )={getMin,getMax,getSum};//定义函数指针数组
	
	for(int i=0;i<3;i++){//调用3个函数
		ret = (*pfunc[i])(a,b);
		printf("ret = %d\n",ret);
	}
	
	return 0;
}

运行结果:

    

五、指针函数

        返回值为指针的函数。

    

        1.例子

#include <stdio.h>

int *getPosPerson(int pos,int (*pstu)[4])//指针函数 返回一个指针
{
	int *p;
	p = (int *)(pos + pstu);//(int * )转成整型指针(ins)整型
	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;
}

运行结果:

    

六、二级(多级)指针

        二级指针内存存放的是下一个指针的地址,而下一个指针内存存放数据的地址。

        如同俄罗斯套娃下一个指针存放上一个指针的地址

    

        1.二级(多级)指针的定义及使用

#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);
	
	/*可以用一级指针变量存放指针变量的地址,但是使用有缺陷,无法获得最终地址内容
	printf("p的地址是:%p\n",&p);
	int *pp = &p;
	printf("pp保存p的地址:%p\n",pp);
	printf("*pp是%p\n",*pp);*///得到的是dara的地址不是data的值   *p存放的地址
	
	printf("\n");
	int **p2;//定义二级指针
	p2 = &p;//二层,二级指针存放一级指针的地址
	printf("p2保存p的地址:%p\n",p2);
	printf("*p2是%p\n",*p2);
	printf("**p2来访问data:%d\n",**p2);
	printf("p2的地址是:%p\n",&p2);
	
	printf("\n");
	int ***p3;//定义三级指针
	p3 = &p2;//三层,三级指针存放二级指针的地址
	printf("p3保存p2的地址:%p\n",p3);
	printf("*p3是%p2\n",*p3);
	printf("***p3来访问data:%d\n",***p3);
	return 0;
}

 运行结果:

    

        2.例子

#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.各种指针的定义

     

         2.各种指针变量的含义

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wlkq~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值