目录
指针引入:
开胃小菜:
指针类型:
指针作用:
通过指针指向数组:
指针和二维数组:
数组指针:
函数指针:
指针数组:
指针函数:
二级(多级)指针(套娃):
二级指针:
总结:
指针引入: 开胃小菜:
定义一个变量,然后将其输出(新内容指针引入)
/*
定义一个变量,然后将其输出(新内容指针引入)
*/
#include
int main()
{
//什么是整型变量?存放整型数的变量
//什么是字符型变量?存放字符型数据的变量
//什么是指针型变量?存放指针的变量
int a = 10;
int *p = &a; //这里的*是标识符,用来定义指针变量
printf("打印a的地址:%p\n",&a);
printf("变量名访问输出:a = %d\n",a);
printf("地址访问输出:a = %d\n",*(&a)); //这里的*是取值运算符,把后面地址内的数据取出来
printf("指针变量访问输出:a = %d\n",*p); //这里的*是取值运算符,把后面地址内的数据取出来(作用同上)
return 0;
}
由此可见,指针 = 地址
指针变量和其他类型的变量一样,也有四要素:变量名、类型、(存储空间)地址、值
有关指针变量注意事项:
① 定义指针变量要区分类型(详情见下文);
② 定义指针变量时标识符*的应用(标识符只产生在指针变量定义或申明的时候,与运算符不同);
③ 取地址符号&;
④ 打印指针变量时取值运算符*的应用;
⑤ 指针变量作为一个变量,也有它自己的地址;
指针类型:代码验证:
#include
int main()
{
int a = 0x4567;
int *p = &a;
char *c = &a;
printf("a的地址是:%p\n",p);
printf("a的地址是:%p\n",c);
printf("a的值是:a = %x\n",*p);
printf("a的值是:a = %x\n",*c);
printf("a的地址加1是:%p\n",p+1);
printf("a的地址加1是:%p\n",c+1);
return 0;
}
因为定义是一个char型变量,所以在输出int型变量时高位被削掉了,只能输出1字节(8位)的数据,而且在进行地址加1时,int型变量加的是4位,而char型变量加的是1位。所以在定义指针变量时要区分类型。
由此可见:定义哪种类型的指针变量并不会影响变量的地址,但取值的时候出了问题,取值运算符会根据指针变量类型,访问不同大小的存储空间。区分指针变量类型不仅能够决定指向空间的大小,而且还能决定增量。
指针作用:编程练习:封装一个函数,实现两个数的交换
/*
从前的交换方式
#include
int main()
{
int data1 = 10;
int data2 = 20;
int temp;
puts("原样输出");
printf("data1 = %d data2 = %d\n",data1,data2);
temp = data1;
data1 = data2;
data2 = temp;
puts("交换后输出");
printf("data1 = %d data2 = %d\n",data1,data2);
return 0;
}
*/
/*
交换失败!!!原因:main函数将参数的值copy到ChangeData函数中,在ChangeData函数中,
发生交换的是该函数的data1,data2,与main函数中的data1,data2没有任何关系,因为两函数
中的地址不同,所以main函数中的data1,data2的值始终不会发生改变,自然交换失败。
*/
/*
将函数封装交换data1和data2的值
#include
void ChangeData(int data1,int data2)
{
int temp;
temp = data1;
data1 = data2;
data2 = temp;
}
int main()
{
int data1 = 10;
int data2 = 20;
puts("原样输出");
printf("data1 = %d data2 = %d\n",data1,data2);
ChangeData(data1,data2);
puts("排序后输出");
printf("data1 = %d data2 = %d\n",data1,data2);
return 0;
}
*/
//封装函数data1和data2交换,交换成功
#include
void ChangeData(int *data1,int *data2)
{
int temp;
temp = *data1;
*data1 = *data2;
*data2 = temp;
}
int main()
{
int data1 = 10;
int data2 = 20;
puts("原样输出");
printf("data1 = %d data2 = %d\n",data1,data2);
ChangeData(&data1,&data2);
puts("排序后输出");
printf("data1 = %d data2 = %d\n",data1,data2);
return 0;
}
编程练习:使用指针指向一个固定的地址
#include
int main()
{
int a;
printf("adderss of a is : 0x%p\n",&a); //获得一段可 *** 作的地址空间
int *p = (int *)0x000000000061FE1D;
printf("address of p is : 0x%p\n",p);
return 0;
}
作业: 输入三个数a,b,c; 要求不管怎么输入,在输出的时候,a,b,c就是由大到小的顺序输出,用函数封装实现
#include
void InitData(int *a,int *b,int *c )
{
puts("请输入三个整数");
scanf("%d%d%d",a,b,c);
puts("输入完毕");
}
void CompareData(int *a,int *b,int *c)
{
int temp;
if(*a<*b)
{
temp = *a;
*a = *b;
*b = temp;
}
if(*a<*c)
{
temp = *a;
*a = *c;
*c = temp;
}
if(*b<*c)
{
temp = *b;
*b = *c;
*c =temp;
}
}
int main()
{
int a;
int b;
int c;
InitData(&a,&b,&c);
printf("原样输出\n");
printf("a = %d,b = %d,c = %d\n",a,b,c);
CompareData(&a,&b,&c);
printf("排序后输出\n");
printf("a = %d,b = %d,c = %d\n",a,b,c);
return 0;
}
通过指针指向数组:
编程练习:
#include
int main()
{
int a[3] = {1,2,3};
int *p;
p = &a[0];
p = a;
printf("address of a[0] is %p,a[0] = %d\n",&a[0],*(&a[0]));
printf("address of a is %p,a = %d\n",&a,*a);
printf("address of a[0] is %p,a[0] = %d\n",p,*p); //数组的首地址就是首个元素的地址
printf("address of a is %p,a = %d\n",p,*p); //数组名就是数组的首地址
return 0;
}
指针偏移遍历数组:
#include
int main()
{
int a[3] = {1,2,3};
int *p;
p = a;
for(int i = 0;i<3;i++)
{
printf("%d ",a[i]);
printf("%d ",*(a+i));
}
return 0;
}
注意:
#include
int main()
{
int a[3] = {1,2,3};
int *p = a;
for(int i = 0;i<3;i++)
{
printf("%d ",*p++);
}
p = a; //数组初始化!!!当使用指针偏移来访问数组时,要注意指针是否越界
for(int i = 0;i<3;i++)
{
printf("%d ",*p++);
}
return 0;
}
见怪不怪的表达方法:
注意:当把数组名拿来++;sizeof地址大小不一样
#include
int main()
{
int a[3] = {1,2,3};
int *p = a;
printf("sizeof a is: %d\n",sizeof(a)); //代表数组a的大小,3*4个字节大小
printf("sizeof p is: %d\n",sizeof(p)); //代表OS *** 作系统存放一个地址所用的字节大小
printf("sizeof int* is: %d\n",sizeof(int *)); //代表OS *** 作系统存放一个地址所用的字节大小
printf("sizeof char* is: %d\n",sizeof(char *)); //代表OS *** 作系统存放一个地址所用的字节大小
for(int i = 0;i<3;i++)
{
printf("%d ",p[i]);
}
putchar('\n');
for(int i = 0;i<3;i++)
{
printf("%d ",a[i]);
}
putchar('\n');
for(int i = 0;i<3;i++)
{
printf("%d ",*p++);
}
/*for(int i = 0;i<3;i++)
{
printf("%d ",*a++); //a作为数组名代表a这个数组的地址空间,一旦确定就不能改变,所以不能拿来++
}*/
putchar('\n');
return 0;
}
练习函数指针结合:
#include
void InitArray(int *p,int len)
{
int i;
for(i=0;i
练习数组指针逆序输出:
#include
void InitArray(int *p,int len)
{
int i;
for(i=0;i
指针和二维数组:
将二维数组看成父子数组,其中a是父数组的数组名(面向行的地址),a[0],a[1],a[2]等是子数组的数组名(面向列的地址)。
此处的a[0],a[1],a[2]中的0,1,2并不代表数组的大小,而代表数组的名字。
数组名就是数组的首地址,因此数组的首地址就是首个元素的地址,即:a[0] = &a[0][0];
思考:a是谁的地址,a[0]又是什么,那*a或者*(a+0)呢?
答:a是父数组的地址(即面向二维数组的行地址);
a[0]是子数组的地址(即面向二维数组的列地址);
*a相当于a[0] (原因是*a相当于取数组a里的数,而二维数组里还有一维数组,c语言里没有直接 *** 作数组的概念, *** 作的是数组首地址, *** 作的实际上是列地址。所以*a = a[0])
*(a+0)相当于a[0] (原因是括号的优先级高于星号,所以先执行括号里的,即*(a+0) = *a = a[0])
a[0]+1第0行第一列的地址,是地址的意思(相当于*(a+0)+1),也可以说是第0个子数组的第1个元素的地址,而第0个子数组的第1个元素表示方式是a[0][1],不要乱
编程验证:
#include
int main()
{
int a[3][4] = {{11,22,33,44},{55,66,77,88},{99,100,12,18}};
printf("a的地址是:%p,偏移1后的地址是:%p\n",a,a+1);
printf("a[0]的地址是:%p,偏移1后的地址是:%p\n",a[0],a[0]+1);
printf("a[0]的地址是:%p,偏移1后的地址是:%p\n",*(a+0),*(a+0)+1);
return 0;
}
树立认知:
提示:
进阶:
有意思的思考:
虽然a+1和*(a+1)的地址相同,值相同,但它们所代表的意义不一样,a+1是面向行的地址,*(a+1)代表的是面向列的地址。
小总结:
代码验证:
#include
int main()
{
int a[3][4] = {{11,22,33,44},{55,66,77,88},{99,100,12,18}};
int i,j;
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf("address: %p,value: %d\n",&a[i][j],a[i][j]);
printf("address: %p,value: %d\n",a[i]+j,*(a[i]+j));
printf("address: %p,value: %d\n",*(a+i)+j,*(*(a+i)+j));
printf("=======================================\n");
}
}
return 0;
}
数组指针:
编程练习: 指向一个含有4个元素的数组
#include
int main()
{
int a[3][4] = {{11,22,33,44},{55,66,77,88},{99,100,12,18}};
int i,j;
/*
之前遍历数组的方法
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf("%d ",a[i][j]);
}
}
*/
/*
失去二维数组的意思(差点感觉)
int *p = &a[0][0];
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf("%d ",*p++);
}
}
*/
int (*p2)[4]; //定义一个数组指针,指向数组!
p2 = a; //数组指针才真正等同于二维数组名
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf("%d ",*(a[i]+j));
//printf("%d ",*(*(a+i)+j)); 作用同上
}
}
return 0;
}
编程练习:输出二维数组任意行列的数
#include
void Inputarray(int *line,int *list)
{
printf("请输入行列值\n");
scanf("%d%d",line,list);
}
int Printfarray(int (*p)[4],int line,int list)
{
int data;
data = *(*(p+line)+list);
return data;
}
int main()
{
int a[3][4] = {{11,22,33,44},{55,66,77,88},{99,100,12,18}};
int line;
int list;
int result;
int (*p)[4];
p = a;
Inputarray(&line,&list);
result = Printfarray(a,line,list);
printf("%d ",result);
return 0;
}
函数指针:
定义:如果在程序中定义了一个函数,在编译时,编译系统为函数分配一段存储空间,这段存储空间的起始地址(又称入口地址)称为这个函数的指针。
函数名就是地址,访问的时候能用函数名访问,也能通过函数指针访问(和数组指针一样)
优点:根据程序运行过程的不同情况,调用不同的函数。
如何定义一个函数指针变量:将函数整体复制下来,然后把函数名定义成指针变量。
例如:
定义有参数,有返回值类型的函数指针:int Getdata(int a,int b);定义函数指针为int (*p)(int a,int b)后p = Getdata;调用的时候直接调用(*p)(int a,int b);
定义无参数无返回值类型的函数指针:void Welcome()定义函数指针为void (*p)()后p = Welcome;调用的时候直接调用(*p)();
代码验证:
#include
void PrintWelcome()
{
printf("Welcome come to C World\n");
printf("=============================\n");
}
int ChangeData(int data)
{
return data * 2;
}
int main()
{
int data = 20;
int result;
PrintWelcome();
void (*p)();
int (*p2)(int data);
p = PrintWelcome;
p2 = ChangeData;
(*p)();
result = (*p2)(data);
printf("result = %d\n",result);
return 0;
}
编程练习:
#include
#include
int GetMaxData(int data1,int data2)
{
return data1>data2?data1:data2;
}
int GetMinData(int data1,int data2)
{
return data1
指针数组:
定义:
注意:指针数组(int * p[4])是一个数组,数组内存放的每一项都是一个指针变量;数组指针(int(*p)[4])是一个指针,它是定义一个指针变量指向一个数组。
编程小练习:遍历指针数组
#include
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;
}
编程练习:定义一个函数指针数组:
#include
#include
int GetMaxData(int data1,int data2)
{
return data1>data2?data1:data2;
}
int GetMinData(int data1,int data2)
{
return data1
指针函数:
定义:
注意:指针函数(int *p(int a,int b))是一个函数,它的返回值的类型是一个指针类型;函数指针
(int *p(int a,int b))是一个指针,它是定义一个指针变量指向一个函数。
编程练习:
#include
int *GetADDFrom(int position,int (*p)[4])
{
int *p2;
p2 = (int *)(position+p);
return p2;
}
int main()
{
int a[3][4] = {{57,64,68,56},{80,87,60,45},{78,65,30,45}};
int position;
int *p;
printf("请输入学生位号\n");
scanf("%d",&position);
p = GetADDFrom(position,a);
for(int i=0;i<4;i++)
{
printf("%d ",*p++);
}
return 0;
}
编程练习:
#include
int *GetAddFrom(int position,int (*p)[4])
{
int *p2;
p2 = (int *)(position+p);
return p2;
}
int main()
{
int a[3][4] = {{56,85,57,80},{58,90,78,69},{45,50,48,59}};
int position;
int *p;
printf("请输入学生号\n");
scanf("%d",&position);
p = GetAddFrom(position,a);
for(int i=0;i<4;i++)
{
printf("%d ",*p++);
}
putchar('\n');
for(int i=0;i<3;i++)
{
for(int j=0;j<4;j++)
{
if (a[i][j]<60)
{
printf("In the %d column,in the %d row is %d\n",i+1,j+1,*(a[i]+j));
}
}
}
return 0;
}
二级(多级)指针(套娃):
如何定义一个二级指针: int **p
编程验证:
#include
int main()
{
int a = 10;
int *p = &a;
printf("a的地址是%p\n",&a);
printf("p存放的是a的地址:%p,通过p访问a的值是 :%d\n",p,*p);
printf("p的地址是%p\n",&p);
/*int *p2 = &p;
printf("p2存放的是p的地址:%p\n",p2); //使用一级指针指向一级指针时,访问不到a地址中保存的数据!!!
printf("*p2访问的是:%p\n",*p2);
*/
int **p3 = &p;
printf("p3存放的是p的地址:%p\n",p3);
printf("*p3存放的是a的地址:%p\n",*p3);
printf("**p3存放的是a的值:%d\n",**p3);
int ***p4 = &p3;
printf("p3的地址是%p\n",&p3);
printf("p4存放的是p3的地址:%p\n",p4);
printf("*p4存放的是p的地址:%p\n",*p4);
printf("**p4存放的是a的地址:%p\n",**p4);
printf("***p4存放的是a的值:%d\n",***p4);
return 0;
}
编程练习:对例8.25的程序修改,不使用函数指针
#include
int *GetAddFrom(int position,int (*p)[4],int **p2)
{
*p2 = (int *)(p+position);
}
int main()
{
int a[3][4] = {{45,65,94,25},{81,56,63,58},{58,59,57,56}};
int position;
int *p;
printf("请输入学生号数\n");
scanf("%d",&position);
GetAddFrom(position,a,&p);
for(int i=0;i<4;i++)
{
printf("%d ",*p++);
}
return 0;
}
二级指针:
注意:二级指针并不等同于二维数组!!!
编程验证:
#include
int main()
{
int a[3][4] = {{45,65,94,25},{81,56,63,58},{58,59,57,56}};
int (*p)[4] = a;
int **p = a;
printf("p = %p\n",p);
printf("a = %p\n",a);
printf("*a = %p\n",*a);
printf("%p\n",*p); //*p是野指针,不是我们认为的列地址
**p = 100;
printf("%d ",a[0][0]);
/*
因为二级指针并不等同于二维数组,*p是一个野指针,所以当用**p访问二维数组时并不能改变里边的值,
它执行的结果是一个段错误
*/
return 0;
}
正确表达:
#include
int main()
{
int a[3][4] = {{45,65,94,25},{81,56,63,58},{58,59,57,56}};
int (*p)[4] = a; //先定义一个数组指针,然后再用二级指针承接数组指针的地址
/*int **p = a;
printf("p = %p\n",p);
printf("a = %p\n",a);
printf("*a = %p\n",*a);
printf("%p\n",*p); //*p是野指针,不是我们认为的列地址
**p = 100;
printf("%d ",a[0][0]);
/*
因为二级指针并不等同于二维数组,*p是一个野指针,所以当用**p访问二维数组时并不能改变里边的值,
它执行的结果是一个段错误
*/
int **p2 = &p;
**p2 = 100;
printf("%d\n",a[0][0]);
return 0;
}
总结:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)