在谭浩强的C程序设计的第8章关于指针。
在刚开始学C语言的时候,对指针以及地址的理解非常的模糊。
当时认为指针是一种无形的,没什么变化规律的东西。
随着学习的不断深入,对地址知识的不断了解,
现在好像又理解了什么。
首先指针就是地址,
每一种数据类型的变量有者相应的字节数,数组也根据数组类型和长度占用相应的内存字节。
我们的内存空间就像一栋大楼,有着不同的层数和房间,我们的变量占据着不同的房间
如果1BYTE是一个房间的话,整形INT就是占4个房间,字符变量就是1个房间。
地址就是门牌号,对它们的访问也要通过地址进行。那么指针就是通往房间的钥匙。指针也是变量,也可以进行运算,从而通过地址和指向的变化完成很多的功能。
以数组来看,数组名就是数组的首地址,通过指针,我们可以直接完成对数组的输入和输出而不需对数组元素进行取地址,通过地址的运算就可以完成。
下面给出我的操作代码
#include <stdio.h>
int main()
{
int a[10],i,*p=a;
for(i=0;i<10;i++)
{
scanf("%d",p++); //因为p就是数组a的首地址,且p++根据循环不断的指向数组的下一个元素,完成数组的赋的值
// p++是加sizeof(int),历遍每一个数组元素的地址
}
p = a;//因为在上个循环的过程中,指针已经通过不断的p++指向了最后一个元素的地址,所以在这 个
// 地方,要重新把数组的首地址赋给指针,矫正指向,不然在下面的循环中就会指向数组之外的内存,输出地址或别的数据
for(;p<a+10;p++) //a+10不是在a的地址上加10,而是在地址上加sizeof(int)*10,即最后一个元素的地址
{
printf("%d",*p);
}
return 0;
}
当指针指向整形,浮点和字符的时候也如此
#include <stdio.h>
int main()
{
int a,*p1=&a; //3种类型3个类型指针分别指向a,b,c
char b,*p2=&b;
float c,*p3=&c;
printf("请输入a,b,c");
scanf("%d%c%f",p1,p2,p3); //放入指针之中//
printf("a的地址为%d\n值为%d",p1,*p1);
printf("\nb的地址为%d\n值为%c",p2,*p2);
printf("\nc的地址为%d\n值为%f",p3,*p3);
}
执行是这样的
要注意区分指针和指针指向的变量的值的区别在上面的程序中p3是指针而*p3就是指针指向的变量的值,也就是c的值
下面是指针在函数中的运用,学习了第7章的内容我们应该知道以下几点
1.数据的传递是由实参向形参单向传递的,是单向的。
2.一个子函数只能将一个返回值传递回主函数
我们不能带会多个返回值
3.我们不能在子函数里改变主函数的数据,因为形参在函数调用后的内存分配就释放了(存储在动态存储区中)
下面举一个栗子,
如果我们想要通过一个函数把1个数组进行倒置,
请同学们思考一下我写的下面一个程序
#include <stdio.h>
void paixu(int u[10]) //全局定义这个函数
int main()
{
int a[10],i,j,k; //请自动忽略我设的多余的变量(一个不好的习惯)
printf("请输入这个长度为10的数组");
for(i=0;i<10;i++) //赋值
{
scanf("%d",&a[i]);
}
paixu(a[10]);//调用这个排序函数
for(i=0;i<10;i++) //再输出这个这个数组
{
printf("%d",a[i]);
}
return 0;
}
void paixu(int u[10])//定义排序函数
{
int t,y,o;
for(t=0;t<(10/2);t++)//前后元素交换5次,完成数组的倒置
{
y = u[t];
u[t] = u[9-t];
u[9-t] = y;
}
}
请同学们先想一想;这个程序能不能实现数组的倒置呢?
答案倒数
5
4
3
2
1
0
下面贴出运行情况的截图
从结果可以看出,我们的排序函数并没能对数组进行倒置,
为什么呢?
就是上述的原因,子函数的数组(形参)是倒置了,但调用结束后就没有了,
并不能对主函数的数组(实参)进行改变。
这中情况下就要使用到我们的指针了,
下面给出我写的代码
#include <stdio.h>
void paixu(int *p,int n);//全局声明
int main()
{
int a[10],i,j,*p=a;
for(i=0;i<10;i++)
{
scanf("%d",p++); //从地址给数组a赋值
}
p = a; //矫正p的指向,使其从新指向数组的首地址
paixu(p,10); //调用倒置函数
for(i=0;i<10;i++)
{
printf("%d",a[i]);
}
return 0;
}
void paixu(int *p,int n) //定义倒置函数
{
int *x,m,temp,*i,*j;
m=(n-1)/2; //用于控制循环的次数
i = p;j = p+n-1;x= p+m;//把数组的首地址给i,尾地址给j,x是数组中间的元素的地址,要5次循环
for(;i<x;i++,j--) //首地址++,尾地址--并互换指向的的值;就完成了数组的倒置
{
temp = *i;
*i = *j;
*j = temp;
}
}
下面贴出运行截图
可以看到数组被倒置并成功的输出出来。
这个函数就完成对整个数组元素的改变。
上述代码我用指针来做函数的实参,前提是这个指针必需有确定的指向。
然后我用了*i和 *j来表示a[i]和a[j],要注意的是他们必须要有指向
i = p;j = p+n-1;x= p+m;
我们在数组中学过我们的数组名是数组的首地址;
老师曾给我们一道思考题;就是长度为0的数组是什么?
我用自己的电脑定义一个长度为0的数组,尝试给它赋值,但无论如何赋值,他输出的都
是一行很长的数字,同时我又输出数组名的地址,发现这两的值只差了几个数,才恍然意识
到这些都是内存中的地址
我才打开留有很多空白的指针,开始从新看,去从新正确的理解指针,不被畏难的情绪
蒙蔽双眼。
事实上数组名是一个指针变量你甚至可以用sizeof去求它的长度。
我现在做的归纳并不全面,主要在指针与数组和函数的方面。
那么上面的程序也可以用数组名作为函数的形参,如果能够
改变实参中的数据,便也证明数组名也是一个指针变量
下面照例给出操作代码和截图
#include <stdio.h>
void inv(int x[],int n);
int main()
{
int i,a[10]={1,2,3,4,5,6,7,8,9,10};
printf("The origan array is");
for(i=0;i<10;i++)
{
printf("%d",a[i]);
}
inv(a,10);
printf("\nThe sort array is");
for(i=0;i<10;i++)
{
printf("%4d",a[i]);
}
}
void inv(int x[],int n)
{
int temp,i,j,m=(n-1)/2;
for(i=0;i<m;i++)
{
j=n-1-i;
temp = x[i];
x[i] = x[j];
x[j] = temp;
}
return 0;
}
以下是运行截图
这篇帖子将继续不间断的跟新,直到我对指针有全面的理解。
下次将铺上以上代码的注释,和原理。
下次再见!