if(x==a[i])returni;
return-1;
};
教材P239的6.3程序填空题,需要认真理解。
其中的(3)如果改为统计某一个字母出现的次数,可以作怎样的简化?
(2)指针类型:
定义形式为:
数据类型*指针变量名,例:
int*p;注意p与*p的区别。
指针变量若未赋值,不能对*p操作,若对指针赋值为空值,也不能对*p操作。
例如:
1、int*f=NULL;scanf("%d",f)或*f=10.5;都不正确
2、intt='A',*f;f=&t或*f=t均正确;f=t,*f=&t都不正确
3、int*f;f=NULL;正确
练习:
1、已知:
char*s="student";则printf("%s\n",c+3)输出为____
2、若有说明:
inta,b=9,*p=&a;,则能完成a=b赋值功能的语句是____
A、a=*p;B、*p=*&b;C、a=&b;D、*p=&*b;
指针与数组的关系:
对指针操作一维数组要熟练掌握,理解数组名是地址常量的概念,指针指向数组的时候执行p++、p--的意义,以及数组元素的下标法访问及指针运算符访问方法:
例:
inta[4]={1,2,3,4},*p=a ;++p;p[2]或*(p+2)都是表示元素a[3],但是p+1或a+2都是表示地址概念的,都等于&a[2]
各种指针的含义:
int*p ;//一级指针,可等于普通int变量地址、一维数组名、二维数组中的列地址
int(*p)[3];//一个行指针,指向具有3个整型元素的一维数组,与二维数组一起使用,用于获得行指针值,例inta[2][3] ;p=a;
int*p[3];//含3个整型指针元素的一维指针数组p
int(*p)();//函数指针,指向返回值为int型的函数入口
int*p(形式参数表);//返回值为int指针的函数p
int**p ;//二级指针p,用来获得一级指针的地址,必须两次间接寻址才能访问int值,例如:
inta,int*r=&a,**p=&r ;则下列三句等效:
(1)a=1 ;
(2)*r=1 ;(3)**p=1 ;
这里,有几种访问是不正确的:
(1)r=1 ;
(2)p=&a ;(3)p=r ;(4)*p=1 ;
二维数组中元素的表示:
例:
inta[3][4];
元素a[i][j]的正确表示:
a[i][j]、*(a[i]+j)、*(*(a+i)+j)、*(*a+i*4+j),但是*(a+i*4+j)不正确,这里需要正确理解行指针与列指针的表示及它们执行算术运算每次移动的字节数
用字符指针操作字符串:
比用字符数组操作字符串具有更大的灵活性,注意二者的区别
例:
char*s=“ABC”;char*s;s=”ABC”;都是正确的
charp[4]=“ABC”;正确,但是charp[4];p=”ABC”;却错误
s=p;是正确的赋值,但是s=*p,*s=”AB”都是错误的
练习:
下面的函数代码是否都能正确实现字符串的拷贝(将p1串拷贝到p2串中?
)
代码段一:
voidMyStrcpy(char*p2,char*p1)
{
while((*p2=*p1)!
='\0')//此处换成......!
=’\n’呢?
{
p1++;
p2++;
}
}
代码段二:
voidMyStrcpy(char*p2,char*p1)
{
while(*p1!
='\0')
{
*p2=*p1
p1++;
p2++;
}
}
(3)结构体类型:
会正确定义结构体类型,掌握三种变量定义的方式及变量的初始化方式,理解结构体变量内存占用的情况(各成分依次存放,故结构体变量所占空间至少为所有成员需要的空间之和),会正确访问结构体变量的成员(用点运算符或是箭头运算符),结合结构体数组及指针会正确访问结构体的元素。
练习:
1、定义structPoint{intx,y;}pos[]={{1,2},{3,4},{5,6}},*pt=pos;则表达式(++pt)->y的值为______,++(pt->x)的值为_________,++pt->x的值为______、(*pt).y的值为_____。
2、以下对结构体变量stu中成员的非法引用是______。
structPoint
{
intx;
inty;
}pos,*p=&pos;
A、pos.xB、(*p).yC、p->xD、Point.y
作为函数参数,通常定义结构体的指针作为形式参数,将实参结构体变量的地址传入,这样省时效率高,而且可在被调函数中修改对应实参结构体成员的值
练习:
下列程序的运行结果是?
#include
typedefstructStudent
{charname[10];
doublescore;
}STU;
voidf(STU*s)
{(*s).score*=20;
printf("%s%.1f\n",s->name,(*s).score);
}
voidmain()
{STUstu[]={{"LiuBo",4.5},{"JiWei",4.6},{"Lijie",5.0}};
f(stu+1);
printf("%s%.1f\n",stu->name,(*stu).score);
}
利用结构体和指针的递归定义可以实现单链表
例:
structnode{
intdata;
structnode*next;
}*head;
在单链表中,最重要的是头指针的信息,头指针用于指向单链表的第一个结点处,顺着链依次寻找其它的结点,单链表不可随机访问其中的结点,最后一个结点的指针域置为空
理解单链表的遍历、插入一个结点、删除一个结点等方法。
练习:
1、设以下程序的所有的指针均为上面structnode*变量,已知head为头指针,指针p指向了单链表中的某一个结点处,但肯定不是指向第一个结点和最后一个结点,指针q指向了某一个结点处,该结点不在链表中,下面的代码实现的功能是___?
(方法提示:
根据描述先画出单链表示意图来)
p=p->next;s->next=p->next;p->next=s;
如果p指向的是链表中倒数第二个结点处,则上面代码实现的功能为______,这时代码还可以写成______?
下面的代码的功能是___?
p->next=p->next->next;deletep->next;
下面的代码的功能是___?
for(p=head;p;p=q){q=p->next;deletep;}
下面的代码的功能是___?
p=(structnode*)malloc(sizeof(structnode));
p->data=x;
p->next=head;
head=p;
2、链表中的结点的形成可以有两种方式,一种是静态的,即定义了结构体变量,只是将不同变量的next域作了连接,另一种是利用malloc()函数逐个申请动态空间,再进行指针间的连接。
下面程序代码的运行结果是:
voidmain()
{
structnode{
intdata;
structnode*next
}*head,*p,a,b,c;
intj;
a.data=10;b.data=20;c.data=30;
b.next=&c;c.next=&a;a.next=0;
head=&b;
p=head->next;
printf("%d\n",p->data);
}
动态申请一个结点空间:
p=(structnode*)malloc(sizeof(structnode)),然后才能执行:
p->data=…;p->next=…;
可以利用指针生成动态数组空间,例如:
int*p;
p=(int*)malloc(sizeof(int));/*申请一个int空间*/
p=(int*)malloc(2*sizeof(int));/*申请2个连续的int空间,实现动态一维数组*/
p=(int*)calloc(2,sizeof(int));/*申请2个连续的int空间,实现动态一维数组*/