一.如何理解指针?
1. 首先指针是一个变量,既然是变量就有它的目的,变量的目的就是来存放数据。不同的是指针变量存放的数据是另一个变量的地址,其实不光可以存放变量的地址,还可以存放函数的地址,指针变量的地址。
指针既然是变量,就有它所属的数据类型。指针所存储变量的类型,就称为指针的类型。
例1,有三个不同的变量:
int A,*PI=&A; PI++;
Char B,*PC =&B; PC++;
Float C,*PF=&C; PF++;
请问右边的三个运算有何不同?
2.研究指针的三要素:指针本身的地址?指针指向的地址?指针指向的地址里面的内容?
3.指针本身的大小也就是指针变量占用的存储空间,与所用的CPU寻址空间和类型有关,而与指针类型无关。
8位CPU的指针长度一般为1~3个字节,16位CPU指针长度一般为2个字节,32位CPU指针长度一般为4个字节。
4.数组作为函数的形参时,会降为指针来用。
void arrayTest(char str[])
{
printf(“%d”, sizeof(str); //arrayTest(str)打印为4
}
Char str[] = ‘hello”;
5.空指针是特殊的指针,它可指向任何的指针类型。一个变量指向空指针,表示当前指针处于空闲状态,不指向任何地址。同时任何不用的指针一定要指向空指针,否则就会有野指针存在。
6.野指针不是NULL指针,是指向不明内存的指针。野指针的成因:
1).指针变量没有被初始化;
2).指针P被free或delete之后,没有置为NULL;
3).指针操作超越了变量的作用范围;
注:C标准承认指针在指向数组元素的时候,它所指向的元素可以大于数组元素的个数,发生指向越界的现象,而且编译器可能不会报错。
二.一维数组与指针
1.数组中每一个元素都可以被寻址,这是和能指针结合的关键。
2.数组中的地址有哪些表示方式?
例:int a[10];
int *p=a;
1).a是一个常量地址,等价于&a[0],&a[0],&a[1].....&a[i]等都是代表地址。但&a是错误的,这里相当于取地址的地址了。a是一个指针常量,在程序运行期间不能改变,所以a++,a--,是无法实现的。
2).C语言规定数组名(不包括形参数组名,形参数组并不占据实际的内存单元)代表数组中的首元素的地址。
3).指向数组的指针变量也可以带下标,如p[i]与*(p+i)等价。
4).根据以上的定义,有一下的等价概念:
p+i,a+i,&a[i]它们等价于同一个地址;
*(p+i),*(a+i),p[i],a[i]它们等价于同一个地址里面的内容;
5).*p++。由于++和*同优先级,结合性为自右而左,因此等价于*(p++),先得到*P的值,在自加1。
*(++p)作用是先p加1,在取*p的值。
++(*p)作用是p所指向的元素值加1,p的地址没有变过。
3.当用数组名做为形参时,如果形参数组中各元素发生变化,实参数组中元素的值随之也对应发生变化。常用这种方法通过调用一个函数来改变实参数组的值。实参数组名代表一个固定的地址,或者说是一个指针常量。而形参数组名并不是一个固定的地址,是一个指针变量,它的值等于实参数组首元素的地址,在函数执行期间,它可以被赋值改变。
4.如果两个指针Px和Py所指向的变量类型相同,Px-Py所执行的运算不是两指针所存的地址值相减,而是(Px-Py)/数据长度,即是一个整数。
5.可变长数组。我们知道数组的长度在程序运行时,是不能改变的,但我们可以通过指针的方式,来变相的实现一个可变长的数组。
例如:
int *variable_array;
variable_array=malloc(sizeof(int)*size);
三.程序举例
题目一:用指针变量输出一个数组所有的元素?
四种写法注意比较。
#include<stdio.h>
void main(void)
{
int a[10];
int *p,i;
for(i=0;i<10;i++)
scanf(" %d",&a[i])//注意不要丢掉了&取地址运算符
for(p=a;p<(a+10);p++)//留心指针与for循环的结合,不要写成for(p=a;p<10;p++)
printf("%d",*p)
}
#include<stdio.h>
void main(void)
{
int a[10];
int *p=a,i;
for(i=0;i<10;i++)
scanf(" %d",p++)//注意不需要& ,也不需要*
p=a;
for(i=0;i<10;i++,p++)//留心指针与for循环的结合,不要写成for(p=a;p<10;p++)
printf("%d",*p)
}
#include<stdio.h>
void main(void)
{
int a[10];
int *p=a,i;
for(i=0;i<10;i++)
scanf(" %d",p++)//注意不需要& ,也不需要*
p=a;
for(i=0;i<10;i++)//留心指针与for循环的结合,不要写成for(p=a;p<10;p++)
printf("%d",*p++)
}
#include<stdio.h>
void main(void)
{
int a[10];
int *p=a,i;
for(i=0;i<10;i++)
scanf(" %d",p++)//注意不需要& ,也不需要*
p=a;
while(p<a+10)
printf("%d",*p++)
}
题目二.编写一个函数,实行对数组a中n个整数按相反顺序存放?
比较两种写法。
void contrary(int a[ ],int n)
{
int i,temp;
for(i=0;i<=(n-1)/2;i++) //注意这里的循环次数
{
temp =a[i];
a[i] = a[n-i-1];
a[n-i-1] = temp;
}
}
void contrary(int *a,int n)
{
int *i,*j,temp;
for(i=a,j=a+n-1;i<=a+(n-1)/2;i++,j--) //注意这里的循环次数
{
temp =*i;
*i = *j;
*j = temp;
}
}
题目三.编写一个函数用选择法对给定的数组进行由大到小的排序?
比较两个程序,同时注意区别穷举法。
void sort(int x[ ],int n)
{
int i,j,k,t;
for(i=0;i<n-1;i++)
{
k=i;
for(j=i+1;j<n;j++)
if(x[j]>x[k]) k=j;
if(k!=i)
{t=x[i];x[i] =x[k];x[k]=t;}
}
}
void sort(int *x,int n)
{
int i,j,k,t;
for(i=0;i<n-1;i++)
{
k=i;
for(j=i+1;j<n;j++)
if(*(x+j)>*(x+k)) k=j;
if(k!=i)
{t=*(x+i);*(x+i) =*(x+k);*(x+k)=t;}
}
}