传智播客C提高讲义.docx
- 文档编号:12812672
- 上传时间:2023-04-22
- 格式:DOCX
- 页数:42
- 大小:1.51MB
传智播客C提高讲义.docx
《传智播客C提高讲义.docx》由会员分享,可在线阅读,更多相关《传智播客C提高讲义.docx(42页珍藏版)》请在冰豆网上搜索。
传智播客C提高讲义
传智播客C提高讲义
传智扫地僧
1程序内存模型
就业班引言
问题引出
企业需要能干活的人
C学到什么程度可以找工作
对于C/C++初级开发者,怎么达到企业的用人标准
就业问题
问:
老师,有没有一个框框
有没有一个标准啊
我们学什么哪
C工程开发需要什么(培养什么能力)
成熟的、商业化的信息系统在分区、分层
信息系统的技术模型在分层
找出对我们初学者最近的那一层(哪些能力是你入行前,必须要掌握的)
C项目开发的套路(一套接口)
...\n");
getchar();
return0;
}
sizeof是操作符,不是函数;sizeof测量的实体大小为编译期间就已确定
数据类型别名
数据类型可以理解为固定大小内存块的别名,请问数据类型可以起别名吗
intmain()
{
...\n");
getchar();
return0;
}
数据类型的封装
1、void的字面意思是“无类型”,void*则为“无类型指针”,void*可以指向任何类型的数据。
2、用法1:
数据类型的封装
intInitHardEnv(void**handle);
典型的如内存操作函数memcpy和memset的函数原型分别为
void*memcpy(void*dest,constvoid*src,size_tlen);
void*memset(void*buffer,intc,size_tnum);
3、用法2:
void修饰函数返回值和参数,仅表示无。
如果函数没有返回值,那么应该将其声明为void型
如果函数没有参数,应该声明其参数为void
intfunction(void)
{return1;}
4、void指针的意义
C语言规定只有相同类型的指针才可以相互赋值
void*指针作为左值用于“接收”任意类型的指针
void*指针作为右值赋值给其它指针时需要强制类型转换
int*p1=NULL;
char*p2=(char*)malloc(sizoeof(char)*20);
5、不存在void类型的变量
C语言没有定义void究竟是多大内存的别名
6、扩展阅读《void类型详解.doc》
数据类型总结与扩展
1、数据类型本质是固定内存大小的别名;是个模具,c语言规定:
通过数据类型定义变量。
2、数据类型大小计算(sizeof)
3、可以给已存在的数据类型起别名typedef
4、数据类型封装概念(void万能类型)
思考1:
C一维数组、二维数组有数据类型吗intarray[10]。
若有,数组类型又如何表达又如定义
若没有,也请说明原因。
抛砖:
数组类型,压死初学者的三座大山
1、数组类型
2、数组指针
3、数组类型和数组指针的关系
思考2:
C语言中,函数是可以看做一种数据类型吗
a)若是,请说明原因
并进一步思考:
函数这种数据类型,能再重定义吗
b)若不是,也请说明原因。
抛砖:
变量本质分析
变量概念
概念:
既能读又能写的内存对象,称为变量;若一旦初始化后不能修改的对象则称为常量。
变量定义形式:
类型标识符,标识符,…,标识符;
例如:
intx;
intwordCut,Radius,Height;
doubleFlightTime,Mileage,Speed;
变量本质
1、程序通过变量来申请和命名内存空间inta=0
2、通过变量名访问内存空间
(一段连续)内存空间的别名(是一个门牌号)
3、修改变量有几种方法
1、直接
2、间接。
内存有地址编号,拿到地址编号也可以修改内存;于是横空出世了!
(编程案例)
3、内存空间可以再取给别名吗
4、数据类型和变量的关系
通过数据类型定义变量
5、总结及思考题
1对内存,可读可写;2通过变量往内存读写数据;3不是向变量读写数据,而是向变量所代表的内存空间中写数据。
问:
变量跑哪去了
思考1:
变量三要素(名称、大小、作用域),变量的生命周期
思考2:
C++编译器是如何管理函数1,函数2变量之间的关系的
====》引出两个重要话题:
内存四区模型
函数调用模型
重要实验:
intmain333()
{
..\n");
getchar();
return0;
}
程序的内存四区模型
内存四区的建立流程
流程说明
1、操作系统把物理硬盘代码load到内存
2、操作系统把c代码分成四个区
3、操作系统找到main函数入口执行
各区元素分析
函数调用模型
基本原理
内存四区模型和函数调用模型变量传递分析
1、一个主程序有n函数组成,c++编译器会建立有几个堆区有几个栈区
2、函数嵌套调用时,实参地址传给形参后,C++编译器如何管理变量的生命周期
分析:
函数A,调用函数B,通过参数传递的变量(内存空间能用吗)
提示学好C语言的关键
如何建立正确的程序运行内存布局图
内存四区模型&函数调用模型
函数内元素
深入理解数据类型和变量“内存”属性
一级指针内存布局图(int*,char*)
二级指针内存布局图(int**char**)
函数间
主调函数分配内存,还是被调用函数分配内存
主调函数如何使用被调用函数分配的内存(技术关键点:
指针做函数参数)
======》学习指针的技术路线图
内存四区强化训练
01全局区训练
char*p1=“abcdefg”;
02堆栈区生命周期训练
Charp1[]=“abcdefg”;
返回基本类型
返回非基本类型
03堆栈属性训练
测试heap生长方向
测试stack生长方向
Heap、stack生长方向和内存存放方向是两个不同概念
野指针
Malloc得到指针释放问题测试
free(p)
free(p+1),深入理解
作业强化
训练1划出内存四区
voidmain26()
{
charbuf[100];
(from==NULL||to==NULL)\n");
return-1;
}
while((*to++=*from++)!
='\0')
{
;
}
return0;
}
典型错误知多少
char*str_cnct(char*x,char*y)/*简化算法*/
{
charstr3[80];
char*z=str3;/*指针z指向数组str3*/
while(*z++=*x++);
z--;/*去掉串尾结束标志*/
while(*z++=*y++);
z=str3;/*将str3地址赋给指针变量z*/
return(z);
}
修改字符常量结果会如何
Char*p=“abcdefg”;
Modifyp[1]=‘1’;
04字符串操作易错
1、
结构体变量的指针->
02、结构体做函数参数
结构体赋值编译器行为研究
结构体变量做函数参数PK结构体指针做函数参数
结构体做函数参数(
..\n");
getchar();
return0;
}
结构体做函数参数及结构体数组
ame,"aaaaa");
ame);
tmp=&teaArray[i];
printf("%s",tmp->name);
}
getchar();
return0;
}
例子
从键盘接受数据。
。
。
。
并排序
intprintfArray(struct_MyTeacher*teaArray,intcount)
{
inti=0;
ame);
printf("\n教师年龄:
");
printf("%d",teaArray[i].age);
}
}
intmain23()
{
inti=0,j=0;
struct_MyTeacherteaArray[3];
struct_MyTeachertmp;
for(i=0;i<3;i++)
{
printf("\n请键入教师名字:
");
scanf("%s",teaArray[i].name);
printf("\n请键入教师年龄:
");
scanf("%d",&teaArray[i].age);
}
for(i=0;i<3;i++)
{
for(j=i+1;j<3;j++)
{
if(teaArray[i].age>teaArray[j].age)
{
tmp=teaArray[i];
teaArray[i]=teaArray[j];
teaArray[j]=tmp;
}
}
}
ame);
printf("\n教师年龄:
");
printf("%d",teaArray[i].age);
}
printf("ddddd\n");
printfArray(teaArray,3);
system("pause");
}
结构体在工程开发中的应用
ame,"aaaaa");
ame);
tmp=&teaArray[i];
printf("%s",tmp->name);
}
getchar();
return0;
}
件的打开fopen()
文件的打开操作表示将给用户指定的文件在内存分配一个FILE结构区,并将该结构的指针返回给用户程序,以后用户程序就可用此FILE指针来实现对指定文件的存取操作了。
当使用打开函数时,必须给出文件名、文件操作方式(读、写或读写),如果该文件名不存在,就意味着建立(只对写文件而言,对读文件则出错),并将文件指针指向文件开头。
若已有一个同名文件存在,则删除该文件,若无同名文件,则建立该文件,并将文件指针指向文件开头。
fopen(char*filename,char*type);
其中*filename是要打开文件的文件名指针,一般用双引号括起来的文件名表示,也可使用双反斜杠隔开的路径名。
而*type参数表示了对打开文件的操作方式。
其可采用的操作方式如下:
方式含义
"r"打开,只读
"w"打开,文件指针指到头,只写
"a"打开,指向文件尾,在已存在文件中追加
"rb"打开一个二进制文件,只读
"wb"打开一个二进制文件,只写
"ab"打开一个二进制文件,进行追加
"r+"以读/写方式打开一个已存在的文件
"w+"以读/写方式建立一个新的文本文件
"a+"以读/写方式打开一个文件文件进行追加
"rb+"以读/写方式打开一个二进制文件
"wb+"以读/写方式建立一个新的二进制文件
"ab+"以读/写方式打开一个二进制文件进行追加
当用fopen(0成功的打开一个文件时,该函数将返回一个FILE指针,如果文件打开失败,将返回一个NULL指针。
如想打开test文件,进行写:
FILE*fp;
if((fp=fopen("test","w"))==NULL)
{
printf("Filecannotbeopened\n");
exit();
}
else
printf("Fileopenedforwriting\n");
……
fclose(fp);
DOS操作系统对同时打开的文件数目是有限制的,缺省值为5,可以通过修改文件改变这个设置。
2.关闭文件函数fclose()
文件操作完成后,必须要用fclose()函数进行关闭,这是因为对打开的文件进行写入时,若文件缓冲区的空间未被写入的内容填满,这些内容不会写到打开的文件中去而丢失。
只有对打开的文件进行关闭操作时,停留在文件缓冲区的内容才能写到该文件中去,从而使文件完整。
再者一旦关闭了文件,该文件对应的FILE结构将被释放,从而使关闭的文件得到保护,因为这时对该文件的存取操作将不会进行。
文件的关闭也意味着释放了该文件的缓冲区。
intfclose(FILE*stream);
它表示该函数将关闭FILE指针对应的文件,并返回一个整数值。
若成功地关闭了文件,则返回一个0值,否则返回一个非0值。
常用以下方法进行测试:
if(fclose(fp)!
=0)
{
printf("Filecannotbeclosed\n");
exit
(1);
}
else
printf("Fileisnowclosed\n");
当打开多个文件进行操作,而又要同时关闭时,可采用fcloseall()函数,它将关闭所有在程序中打开的文件。
intfcloseall();
该函数将关闭所有已打开的文件,将各文件缓冲区未装满的内容写到相应的文件中去,接着释放这些缓冲区,并返回关闭文件的数目。
如关闭了4个文件,则当执行:
n=fcloseall();时,n应为4。
3.文件的读写
(1).读写文件中字符的函数(一次只读写文件中的一个字符):
intfgetc(FILE*stream);
intfgetchar(void);
intfputc(intch,FILE*stream);
intfputchar(intch);
intgetc(FILE*stream);
intputc(intch,FILE*stream);
其中fgetc()函数将把由流指针指向的文件中的一个字符读出,例如:
ch=fgetc(fp);
将把流指针fp指向的文件中的一个字符读出,并赋给ch,当执行fgetc()函数时,若当时文件指针指到文件尾,即遇到文件结束标志EOF(其对应值为-1),该函数返回一个-1给ch,在程序中常用检查该函数返回值是否为-1来判断是否已读到文件尾,从而决定是否继续。
#include""
main()
{
FILE*fp;
chch;
if((fp=fopen("","r"))==NULL)
{
printf("filecannotbeopened\n");
exit
(1);
}
while((ch=fgetc(fp))!
=EOF)fputc(ch,stdout);
fclose(fp);
}
该程序以只读方式打开文件,在执行while循环时,文件指针每循环一次后移一个字符位置。
用fgetc()函数将文件指针指定的字符读到ch变量中,然后用fputc()函数在屏幕上显示,当读到文件结束标志EOF时,变关闭该文件。
上面的程序用到了fputc()函数,该函数将字符变量ch的值写到流指针指定的文件中去,由于流指针用的是标准输出(显示器)的FILE指针stdout,故读出的字符将在显示器上显示。
又比如:
putc(ch,fp);
该函数执行结构,将把ch表示的字符送到流指针fp指向的文件中去。
在TC中,putc()等价于fput(),getc()等价于fgetc()。
putchar(c)相当于fputc(c,stdout);getchar()相当于fgetc(stdin)。
注意,这里使用charch,其实是不科学的,因为最后判断结束标志时,是看ch!
=EOF,而EOF的值为-1,这显然和char是不能比较的。
所以,某些使用,我们都定义成intch。
(2).读写文件中字符串的函数
char*fgets(char*string,intn,FILE*stream);
char*gets(char*s);
intfprintf(FILE*stream,char*format,variable-list);
intfputs(char*string,FILE*stream);
intfscanf(FILE*stream,char*format,variable-list);
其中fgets()函数将把由流指针指定的文件中n-1个字符,读到由指针stream指向的字符数组中去,例如:
fgets(buffer,9,fp);
将把fp指向的文件中的8个字符读到buffer内存区,buffer可以是定义的字符数组,也可以是动态分配的内存区。
注意,fgets()函数读到'\n'就停止,而不管是否达到数目要求。
同时在读取字符串的最后加上'\0'。
fgets()函数执行完以后,返回一个指向该串的指针。
如果读到文件尾或出错,则均返回一个空指针NULL,所以长用feof()函数来测定是否到了文件尾或者是ferror()函数来测试是否出错,例如下面的程序用fgets()函数读文件中的第一行并显示出来:
#include""
main()
{
FILE*fp;
charstr[128];
if((fp=fopen("","r"))==NULL)
{
printf("cannotopenfile\n");
exit
(1);
}
while(!
feof(fp))
{
if(fgets(str,128,fp)!
=NULL)printf("%s",str);
}
fclose(fp);
}
gets()函数执行时,只要未遇到换行符或文件结束标志,将一直读下去。
因此读到什么时候为止,需要用户进行控制,否则可能造成存储区的溢出。
fputs()函数想指定文件写入一个由string指向的字符串,'\0'不写入文件。
fprintf()和fscanf()同printf()和scanf()函数类似,不同之处就是printf()函数是想显示器输出,fprintf()则是向流指针指向的文件输出;fscanf()是从文件输入。
下面程序是向文件里输入一些字符:
#include<>
main()
{
char*s="That'sgoodnews";
inti=617;
FILE*fp;
fp=fopne("","w");
fputs("YourscoreofTOEFLis",fp);
fputc(':
',fp);
fprintf(fp,"%d\n",i);
fprintf(fp,"%s",s);
fclose(fp);
}
用DOS的TYPE命令显示的内容如下所示:
屏幕显示
YourscoreofTOEFLis:
617
That'sgoodnews
下面的程序是把上面的文件里的内容在屏幕上显示出来:
#include<>
main()
{
char*s,m[20];
inti;
FILE*fp;
fp=fopen("","r");
fgets(s,24,fp);
printf("%s",s);
fscanf(fp,"%d",&i);
printf("%d",i);
putchar(fgetc(fp));
fgets(m,17,fp);
puts(m);
fclose(fp);
getch();
}
运行后屏幕显示:
YourscoreofTOEFLis:
617
That'sgoodnews
4.清除和设置文件缓冲区
(1).清除文件缓冲区函数:
intfflush(FILE*stream);
intflushall();
fflush()函数将清除由stream指向的文件缓冲区里的内容,常用于写完一些数据后,立即用该函数清除缓冲区,以免误操作时,破坏原来的数据。
flushall()将清除所有打开文件所对应的文件缓冲区。
(2).设置文件缓冲区函数
voidsetbuf(FILE*stream,char*buf);
voidsetvbuf(FILE*stream,char*buf,inttype,unsignedsize);
这两个函数将使得打开文件后,用户可建立自己的文件缓冲区,而不使用fopen()函数打开文件设定的默认缓冲区。
对于setbuf()函数,buf指出的缓冲区长度由头文件中定义的宏BUFSIZE的值决定,缺省值为512字节。
当选定buf为空时,setbuf函数将使的文件I/O不带缓冲。
而对setvbuf函数,则由malloc函数来分配缓冲区。
参数size指明了缓冲区的长度(必须大于0),而参数type则表示了缓冲的类型,其值可以取如下值:
type值含义
_IOFBF文件全部缓冲,即缓冲区装满后,才能对文件读写
_IOLBF文件行缓冲,即缓冲区接收到一个换行符时,才能对文件读写
_IONBF文件不缓冲,此时忽略buf,size的值,直接读写文件,不再经过文件缓冲区缓冲
5.文件的随机读写函数
前面介绍的文件的字符/字符串读写,均是进行文件的顺序读写,即总是从文件的开头开始进行读写。
这显然不能满足我们的要求,C语言提供了移动文件指针和随机读写的函数,它们是:
(1).移动文件指针函数:
longftell(FILE*stream);
intrewind(FILE*stream);
fseek(FILE*stream,longoffset,intorigin);
函数ftell()用来得到文件指针离文件开头的偏移量。
当返回值是-1时表示出错。
rewind()函数用于文件指针移到文件的开头,当移动成功时,返回0,否则返回一个非0值。
fseek()函数用于把文件指针以origin为起点移动offset个字节,其中origin指出的位置可有以下几种:
origin数值代表的具体位置
SEEK_SET0文件开头
SEEK_CUR1文件指针当前位置
SEEK_END2文件尾
例如:
fseek(fp,10L,0);
把文件指针从文件开头移到第10字节处,由于offset参数要求是长整型数,故其数后带L。
fseek(fp,-15L,2);
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 传智播客 提高 讲义