C语言详细笔记完美整理 第四部分硬件操作和程序结构部分指针文件函数位运算.docx
《C语言详细笔记完美整理 第四部分硬件操作和程序结构部分指针文件函数位运算.docx》由会员分享,可在线阅读,更多相关《C语言详细笔记完美整理 第四部分硬件操作和程序结构部分指针文件函数位运算.docx(22页珍藏版)》请在冰点文库上搜索。
C语言详细笔记完美整理第四部分硬件操作和程序结构部分指针文件函数位运算
第10章指针
本章主要内容
◆理解指针的基本概念
◆熟练掌握指针变量的定义和使用
◆掌握数组和指针,字符串和指针
10.1指针的概念
我们知道,计算机的内存具有存贮数据的功能,它的每一个单元都可以存贮数据,因此称为“存贮单元”,计算机正是利用它进行数据的存贮操作。
那么如何在理论上定位这些“存贮单元”以实现数据的存贮呢?
不同的学科采用了不同的方法,常规的观点认为:
即然是“存贮单元”就应该有它的位置,就可以进行定位,因此就可以用“地址”这个概念来定位它进行数据的存贮操作。
地址:
事物所在的位置。
(这就是地址的概念)
在这个概念的基础上再推广一下:
地址具有“定位、指向”的意义,但是缺少了对定位对象“操作”的意义。
如果将地址的概念引申一步,使其即具有“定位、指向”的意义,又具有“操作”的意义,那么它的作用就会进一步扩大。
因此,人们就用一个全新的概念来表述这种引申的意义---指针。
指针:
指向事物的地址,并且可以引用其内容的操作体。
10.2指针变量
10.1.1指针变量的概念
当人们从地址的概念抽象出指针的概念后,又如何地使用这个概念?
这就需要一个概念
“量化”的过程,即用“量”来表述“概念”的过程。
只有这一过程完成了,才有可能对事物进行定性、定量的全面分析,指针变量就是对指针的量化。
指针变量:
具体、等效地表达指针,并且存放指针值的变量。
指针变量定义式:
指针基类型指针定义(标识)符指针变量名;
例:
type*name;
它定义了一个指针(变量),名称为name,指针变量(指针对象)的类型由type确定。
附属概念:
指针(变量)值:
指针(指针变量)表达的地址单元的值。
指针对象:
指针指出、表达的地址单元中的变量或函数。
指针类型:
指针所指的地址单元中变量或函数的类型。
指针属性:
指针所具有的特性。
为空--指针指向无确切内容的地址单元。
不为空--指针指向有确切内容的地址单元。
10.1.2指针变量的引用和初始化
指针变量的引用:
使用“指针变量”本身代表“指针指向的地址”、使用“*指针变量”
代表“指针对象。
指针初始化:
通过对指针变量的引用为指针(变量)赋初值。
表达式:
指针变量名=&指针对象名;
例:
intx;int*p1,*p2;
p1=&x;p2=p1;
它定义了一个整型变量x,两个整型指针*p1,*p2.然后将整型变量x的地址值赋
给指针变量p1,为其赋初值(初始化),再在指针变量之间赋值的方法为指针变量p2初始化。
例10.1
main()
{
inta,b;
intpointer_1,pointer_2;
a=100;b=10;
pointer_1=&a;
pointer_2=&b;
printf(%d,%d\n”,a,b);
printf(%d,%d\n”,*pointer_1,*pointer_2);
}
例10.2
main()
{
intvariable=1000;
int*pointer1,*pointer2;
pointer1=&variable;
*pointer1=1000;
pointer2=pointer1;
printf("\n%p%d\n",pointer1,*pointer1);
printf("\n%d%p\n",*pointer2,pointer2);
printf("\n%p%d%d\n",pointer2--,*(pointer2--));
}
例10.3
main()
{
int*p1,*p2,*p,a,b;
scanf(%d,%d”,&a,&b);
p1=&a;p2=&b;
if(a
p=p1;p1=p2;p2=p;
}
printf(“\na=%d,b=%d\n\n”,a,b);
printf(“max=%d,min=%d\n”,*p1,*p2);
}
10.3数组与指针
10.3.1指向数组元素的指针
利用“指针变量初始化的方法使指针指向数组元素”。
并且,C语言规定:
数组名代表
数组中的第一个元素的地址。
数组名可以作为指针(变量)使用。
例:
inta[10];int*p;
p=&a[0];p=a;
10.3.2通过指针引用数组元素
通过指向数组的指针所表达的指针对象实现对数组元素的引用。
注意指针变量的运算。
例10.4
main()
{
inta[10];
inti;
clrscr();
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("\n");
for(i=0;i<10;i++)
printf("%d",a[i]);
}
main()
{
inta[10];
inti;
clrscr();
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("\n");
for(i=0;i<10;i++)
printf("%d",*(a+i));
}
main()
{
inta[10];
int*p,i;
clrscr();
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("\n");
for(p=a;p<(a+10);p++)
printf("%d",*p);
}
_
10.4字符串与指针
字符串是字符数组的外延,指针可以指向数组,就可以指向字符数组,指向字符串。
也就可以使用指针引用字符串
例:
char*string;
string=“IloveChina!
”;
例10.5
main()
{
char*string;
string="IloveChina!
";
printf("%s",string);
}
_
10.5结构与指针
10.5.1结构体变量指针
结构指针:
指向结构体首地址,并且可以引用结构成员的指针。
structstudentstu_1;
structstudent*p;
p=&stu_1;
10.5.2结构指针对结构成员的引用
结构指针名->结构成员名;
例:
structstudentstu_1;
structstudent*p;
p=&stu_1;
p->num=8901;name_01=p->name;
P289例11.3
10.5.3结构体数组指针
结构数组指针:
指向结构体数组首地址,并且可以引用结构成员的指针。
struct结构体名*结构体指针名;
结构体指针名=结构体数组名
例10.6
structstudent{
intnum;
chaname[20];
charsex;
intage;
};
structstudentstu[3]={{10101,”LiLin”,’M’,18},
{10102,,”Zhangming”,’M’,19},
{10103,”WangMin”,’M’,20}};
main()
{
structstudent*p;
printf(“No.NameSexAge\n”);
for(p=stu;pprintf(“%5d%10s%2c%5d\n”,p->num,p->name,p->sex,p->age);
}
10.6指针数组和指向指针的指针
10.6.1指针数组
指针数组:
数组中的元素均为指针(变量)的数组。
定义式:
类型名*数组名[数组长度];
例:
int*p[10];
意义:
定义名称为p的整型指针数组,含有4个元素,即4个整型指针(变量)。
例10.7
main()
{
floata,b,c;
float*p[3];
a=10.2;b=9.8;c=1.3;
p[0]=&a;p[1]=&b;p[2]=&c;
printf(“%f%f%f\n”,*p[0],*p[1],*p[2]);
printf(“%p%p%p\n”,p[0],p[1],p[2]);
}
10.6.2指向指针的指针
指向指针的指针:
指针对象为“指针”的指针。
定义式:
基类型**指针(变量)名;
例:
int**q;
意义:
定义指向指针的指针q,其指针对象为整型指针。
P271例10.27
第12章文件
本章主要内容
◆理解文件的基本概念
◆熟练掌握文件的打开与关闭,读写操作
◆掌握文件的定位和出错检测
12.1文件的概念
文件是存贮(记录)在外部介质上的数据集合。
C语言中把文件分为“文本文件(ASCII文件)”和“二进制文件”。
并且规定了两种文件的输入/出方式(存取方式)。
顺序存取方式:
在进行文件的读/写操作时,总是从文件的头开始依次顺序地完成。
直接存取方式:
由编译系统中的库函数定位读/写位置和容量,然后进行读/写操作。
当操作一个文件时,总需要知道该文件的一些信息(文件名、位置、状态),系统提供了一个结构,其结构变量名为FILE,来存贮这些信息。
在程序中定义指向该结构的指针(文件指针)就可以存贮和利用这些信息了。
12.2文件的打开与关闭
12.2.1文件的打开(fopen函数)
在C语言中使用标准库函数fopen实现文件的打开。
即:
FILE*fp;
fp=fopen(文件名,使用文件方式);
例:
fp=fopen(“a1”,”r”);
意义:
以只读的方式打开名称为a1的文件,并返回指向a1的文件类型指针赋给定
义的文件类型指针fp。
12.2.2文件的关闭(fclose函数)
在C语言中使用标准库函数fclose实现文件的关闭。
即:
fclose(文件指针);
例:
fclose(fp);
意义:
关闭文件类型指针fp指向的打开文件。
12.3文件的读写操作
在C语言中使用标准库函数fputc(fgetc)、fputs(fgets)、fread(fwite)、fprintf(fscanf)函数实现文件的读/写操作。
12.3.1fputc函数
fputc(ch,fp);
例:
charch=”a”;
fputc(ch,fp);
意义:
定义字符变量ch并赋初值a,调用标准库函数fputc将字符变量ch表达的字符
写入文件类型指针fp表示的文件中。
12.3.2fgetc函数
ch=fgetc(fp);
例:
charch;
ch=fgetc(fp);
意义:
定义字符变量ch,调用标准库函数fgetc从文件类型指针fp表示的文件中读出一个字符并赋给字符变量ch。
[例12_1]
#include
main()
{
FILE*fp;
charch,filename[10];
scanf("%s",filename);
if((fp=fopen(filename,"w"))==NULL){
printf("cannotopenfile\n");exit(0);
}
ch=getchar();
ch=getchar();
while(ch!
='#'){
fputc(ch,fp);putchar(ch);
ch=getchar();
}
fclose(fp);
}
_本程序的作用是说明文件的打开、写入、显示和关闭。
12.3.3fread函数和fwite函数
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);
意义:
读/写由指针变量buffer指出的数据块,数据块的字节数为size,读/写数据块的个数
为count。
12.3.4fprintf函数和fscanf函数
fprintf(文件指针,格式字符串,输出表列);
fscanf(文件指针,格式字符串,输入表列);
意义:
它们的意义与printf和scanf类同,只是操作的对象是“文件”。
12.4文件的定位和出错检测
12.4.1rewind函数、fseek函数和ftell函数
rewind(fp);
意义:
使文件的位置指针返回到文件的开始处。
fseek(fp,offset,SEEK_SET||SEEKEND||SEEKCUR);
意义:
移动文件位置指针从起始点开始到偏移量表达的位置处。
ftell(fp);
意义:
返回当前文件位置指针值(相对于文件头的偏移字节值)。
12.4.2ferror函数、feof函数和clearerr函数
ferror(fp);
意义:
若函数的返回值不为0(真),文件操作错误。
否则,文件操作未出错。
feof(fp);
意义:
若检测到文件结束符(文件结束),返回非零值。
否则,返加0。
clearer(fp);
意义:
使fp指向的文件错误标志和文件结束标志置0。
第8章函数
本章主要内容
◆理解函数的基本概念
◆熟练掌握函数的形式参数、实际参数和函数的调用
8.1函数的概念
在前面的学习中,已经接触到了函数,明确了函数是构成C语言程序的最小单位。
实际上,一般的C语言程序是由一个主函数和若干个子函数构成的。
所有函数之间都是平行的、独立的、平等的关系,函数之间不存在从属定义关系,即:
函数不允许“嵌套”定义。
C语言中的主函数是由系统定义并调用执行,其它子函数由主函数调用或子函数之间相互调用。
函数的类型:
1.从使用角度:
标准(库)函数,自定义(用户)函数。
2.从函数形式:
无参函数、有参函数、空函数。
函数:
表达一定实际意义,具有独立功能的程序块.
8.2函数的定义
8.2.1有参函数
在定义函数时,函数名后面括号中含有若干个变量(形式参数)的函数。
定义式:
函数返回值类型函数名(参数类型形式参数1,参数类型形式参数2,。
。
。
)
{
函数体(说明部分;语句部分;)
}
函数名:
函数所具有的名称。
参数说明:
定义形式参数的数据类型和参数标识符.
函数体:
在大括号中的语句集合.
[例8_1]
voidadd(inta,intb)
{
intt;
t=a+b;
printf(“%d”,t);
}
意义:
定义名称为add的函数,含有整型形式参数a和b。
在函数中由形式参数进行求和计算并将结果输出。
8.2.2无参函数
在定义函数时,函数名后面括号中不含有若干个变量(形式参数)的函数。
定义式:
函数返回值类型函数名()
{
函数体(说明部分;语句部分;)
}
函数名:
函数所具有的名称。
函数体:
在大括号中的语句集合.
[例8_2]
voidadd()
{
inta,b,t;
scanf(“%d%d”,&a,&b);
t=a+b;
printf(“%d”,t);
}
意义:
定义名称为add的函数,没有参数。
在函数中从键盘上接收两个整型变量值,然后进行求和计算并将结果输出。
8.2.3空函数
在定义函数时,具有空函数(体)的函数。
函数返回值类型函数名(参数类型形式参数1,参数类型形式参数2,。
。
。
)
{
}
函数名:
函数所具有的名称。
参数说明:
定义形式参数的数据类型和参数标识符.
[例8_3]
voidadd(inta,intb)
{
}
意义:
定义名称为add的函数,含有整型形式参数a和b。
在函数体中没有定义语句。
定义一个“空函数(体)”框架,等以后扩充使用。
(这是C++中“重载”的理论基础)
8.3函数的调用
8.3.1形式参数和实际参数
每一个函数在定义后都要被系统或其它函数“使用”,称作“函数调用”。
一般情况下,调用函数与被调函数之间要发生数据的传递,其中,调用函数在调用时发出的参数为“实际参数”,而在被调函数中定义的接收参数为“形式参数”。
被调函数进行一系列的处理后,还要将结果返回给调用函数,使它得到的一个确定的结果值。
这就是“函数的返回值”,它通过return语句实现。
基本形式:
return表达式;return(表达式);return;
函数返回值类型:
在被调函数中定义,通过return语句返回的数据或数值的类型。
8.3.2函数的调用
函数调用的一般形式:
函数名(实参表列);
[例8_4]
intadd(int,int);
intadd(inta,intb)
{
intt;
t=a+b;
returnt;
}
main()
{
inttotal;
total=add(3,5);
printf(“\n%d”,total);
}
<1>函数定义后,在需要调用函数的地方,只要写出函数名及相关的参数,即引起了
函数的调用(执行)。
调用后,返回到调用语句的下一个语句上。
<2>函数返回:
return;或return(表达式);
函数执行到这里即结束,返回到调用它的函数,并返回相关类型的值。
若无该语句
则执行到闭括号处返回。
一类是返回控制,另一类即返回控制又返回值,无论
return在什么地方都返回到调用函数。
<3>对于被调函数,应给出函数原型(包括函数类型、函数名、参数及其类型)。
定义被
调函数时,也要说明其是否返回值,以及返回值的类型。
[例8_5]
intcompute(int,int);
main()
{
inti,tatol=0;
intn,k;
scanf("\n%d%d",&n,&k);
for(i=1;i<=n;++i)
tatol=tatol+compute(i,k);
printf("\n%d",tatol);
}
intcompute(intx,inty)
{
intj,result=1;
for(j=1;j<=y;++j)
result=result*x;
returnresult;
}
意义:
函数通过计算从1到任意整数的任意次幂和的值,说明函数的定义、结构、和基本
语句的使用方法。
函数的调用方法。
8.4函数的嵌套调用和递归调用
8.4.1函数的嵌套调用
函数的嵌套调用:
在调用一个函数的过程中,又调用另一个函数。
[例8_6]
floatrectangle(floatl2)
{
returnl2*l2;
}
floatcircle(floatr1,floatl1)
{
floatrectanglearea,circlearea;
rectanglearea=rectangle(l1);
circlearea=3.14*r1*r1;
returncirclearea-rectanglearea;
}
main()
{
floatr,l;
printf("EnteRandLvalue");
scanf("%f,%f",&r,&l);
printf("\nExtandearea=%f",circle(r,l));
}
意义:
此程序是使用函数嵌套调用的方法实现圆面积减去内嵌正方型面积后剩余面积的计
算。
8.4.2函数的递归调用
在调用一个函数的过程中又直接或间接地调用该函数本身。
[例8_7]
floatfac(intn)
{
floatf;
if(n<0){printf("n<0,dataerror!
");}
elseif(n==0||n==1)f=1;
elsef=fac(n-1)*n;
return(f);
}
main()
{
intn;
floaty;
printf("inputanintegernumber:
");
scanf("%d",&n);
y=fac(n);
printf("%d!
=%10.0f",n,y);
}
意义:
此程序是使用函数递归调用的方法实现n!
的计算。
8.5数组作为函数参数的调用
8.5.1数组元素作为“实参”的函数调用
函数的“形参”和“实参”都是以变量的形式定义和使用的。
数组中的元素作为变量的集合表达当然也可以作为“实参”完成函数调用时的“值传送”任务。
[例8_8]
floatcheck(int);
main()
{
intgroup1[10]={3,5,1,9,2,4,6};
intgroup2[3][3]={{4,6,7},
{11,2,6},
{6,2,10}};
printf("%f",check(group1[3]));
printf("%f",check(group2[1][2]));
}
floatcheck(intm)
{
returnm*2.119;
}
意义:
此程序是使用数组元素作为“实参”进行的函数调用。
8.5.2数组名作为“参数”的函数调用
即然数组元素可以作为参数在函数调用时传送,那么作为数组元素的集合----“数组”就可以作为参数在函数调用时传送。
数组名又代表了整个数组,数组作为参数的传送就是数组名作为参数的传送。
从物理的意义上讲,就是将一个数组的“地址”传送给了另一个数组,是函数调用时的“址传送”过程。
[例8_9]
floataverage(floatarray[10]);
voidmain()
{
floatscore[10],aver;
inti;
printf(“input10scores:
\n”);
for(i=0;i<10;i++)
scanf(“%f”,&score[i]);
printf(“\n”);
aver=average(score);
printf(“\naveragescoreis%f”,aver);
}
floataverage(floatarray[10])
{
inti;
floataver,sum=array[0];
for(i=1;i<10;i++)
sum=sum+array[i];
aver=sum/10;
return(aver);
}
8.5.3多维数组名作为“参数”的函数调用
实际上也是将数组名作为“参数”的函数调用过程,也是函数调用时的“址传送”过程。
[例8_10]P183例8.1