当前位置:首页 > C语言课件
该语句表明func是一个带有两个int参数的函数。而最前面的int和*表明func将返回一个指向一个int变量的指针。有时函数可能无法成功返回一个地址,那么此时将返回一个特殊的值,即NULL。 10.7.1 指针数组
指针数组包含的元素均为指向相同数据类型的指针。
int * ptrArr[ 10 ];
由于方括弧的优先级比星号高,此语句的作用是声明一个有10个元素的数组ptrArr。而int和*则表明数组元素均为指向int的指针。
使用指针数组的好处之一在于,可以对指针进行任意排序而不移动指向的对象数据。 10.7.3 main函数的参数
带参数的main函数可以这样声明:
int main( int argc, char *argv[ ] ); 该语句表明main函数返回一个整数。在像DOS或UNIX这样的主机环境中,其返回值或曰退出状态被传回命令行解释器来表明程序是运行成功(为零)还是发生了错误(非零)。按照标准C采用的惯例,使用exit( 0 )来返回“成功”给主机环境,其它值则表示出现错误。
main函数至少有两个参数:argc和argv。第一个参数提供程序的参数个数,第二个则是一个指针数组,其元素分别指向作为参数的各字符串,亦即其类型是“指向char的指针数组”。
还需记住,当作为参数传递给函数时,数组名将被转换成其首元素的地址。这意味着我们也可以将argv这样声明:char **argv。此处两种声明是等价的。 10.7.4 类型限定词restrict
关键字restrict通过允许编译器优化某几种代码增强了计算支持。它只可用于指针,并表明该指针是在整个作用域内访问一个数据对象的唯一且初始的方式。也就是说同一个值在其作用域内不能被任何其它指针或变量引用。为了弄清为何这样做有用,我们需要看一些例子。考虑下面的例子:
int ar[10];
int * restrict restar=( int * )malloc( 10*sizeof( int ) ); int * par = ar;
这里,指针restar是访问由malloc( )分配的内存的唯一且初始的方式。因此,它可以由关键字restrict限定。然而,指针par既不是初始的,也不是访问数组ar中数据的唯一方式,因此不可以把它限定为restrict。
现在考虑下面这个精心设计的例子,其中n是一个int: for ( n = 0; n < 10; n++ ) { par[ n ] += 5; restar[ n ] += 5; ar[ n ] *= 2; par[ n ] += 3; restar[ n ] += 3; }
知道了restar是访问它所指向数据块的唯一初始方式,编译器就可以用具有同样效果的一条语句来代替包含restar的两条语句:
restar[n] += 8; /* 可以进行替换 */
然而,将两个包含par的语句精简为一条语句将导致计算错误:
par[n] += 8; /* 给出错误结果 */
出现错误结果的原因是循环在par两次访问同一个数据之间,使用ar改变了该数据的值。
可以将关键字restrict作为指针型函数参数的限定词使用,这意味着编译器可以假定在函数体内没有其他标识符修改指针指向的数据,因而可以试着优化代码,反之则不然。另一方面,下面两行:
int * restrict intPtrA; int * restrict intPtrB;
告诉编译器,在intPtrA和intPtrB定义的作用域的存储期内,它们不能访问同一个值。如果它们都指向同一个数组内的整型元素,那它们之间就是互斥的。 10.8.3 void 指针类型
C总是会确保每一个指针的类型且通常不允许在同一个表达式中使用不同类型的指针。例如一个指向char的指针和指向int的指针是不同类型的,二者不可相互赋值,不可做比较,作为函数参数时不可相互替代……事实上,可能它们在内存中的存储方式都不同而且可能具有不同的长度。
解决办法就是使用一种专门为此目的而引入的特殊类型——void 指针类型。这样一种类型——void *实际上不指向任何对象,除了增加代码可读性外别无它用。一个void *类型的指针可以被赋予其它任何类型指针的值,或者反过来,赋值给任意其它指针。
13.2.1 检查命令行参数
首先,程序count.c检查argc的值查看是否有命令行参数,如果没有,程序显示一条用法提示然后退出。字符串argv[0]是该程序的名字。使用argv[0]而不是显式地使用程序名可以保证在改变了可执行文件名后错误消息也会随之自动改变。
exit( )函数关闭所有打开的文件并中止程序。exit( )函数的参数会被传回操作系统以供其它程序使用。通常的约定是正常终止的程序传递值0,非正常终止的则传递非零值。
按照ANSI C,在最初调用的main( )中使用return和调用exit( )的效果相同。所以在main( )中我们一直使用的语句return 0;和这个语句的作用相同:exit( 0 );
但要注意我们所说的是“最初调用”。如果main( ) 在一个递归程序中,exit( )仍然会终止程序,但return将控制权移交给递归的前一级,直到最初的那一级,此时return才会终止程序。return和exit( )的另一个区别在于,即使在除main( )之外的函数中调用exit( ) ,它也将终止程序。
13.2.2 fopen( )函数
fopen( )这一函数在stdio.h中声明。它的第一个参数是要打开的文件名;更确切地说,是包含该文件名的字符串的地址。第二个参数是用于指定文件打开模式的一个字符串。 \\\\\打开一个文本文件用于读取 打开一个文本文件用于写入,先将文件的长度截为0,若文件不存在则创建之 打开一个文本文件用于写入,向文件尾部追加内容,若文件不存在则创建之 打开一个文本文件用于更新(即可以读和写) 打开一个文本文件用于更新(读和写),若该文件存在则首先将其长度截为0,若不存在则创建之 打开一个文本文件用于更新(读和写),向已有文件的尾部追加内容,若不存在则创建之;可以读取整个文件,但写入时只能追加 与前面的模式相似,只是使用二进制模式而非文本模式打开文件 \\\\\如果不能打开文件,fopen( )函数返回空指针(也是在stdio.h中定义的)。如果fp为NULL,程序将退出。磁盘已满、文件名非法、存取权限不够或者硬件问题等都会导致fopen( )函数执行失败。
13.2.3 getc( )和putc( )函数
getc( )和putc( ) 这两个函数的工作方式与getchar( )和putchar( )非常相似,不同之处在于你需要告诉它们要使用的文件。所以下面的方法从标准输入获得一个字符:
ch = getchar( );
但下面的语句表示从指针fp指定的文件中获得一个字符:
ch = getc( fp );
类似地,一下语句表示将字符ch写入到FILE指针fpout指定的文件中:
putc( ch, fpout );
在putc( )的参数表中,首先是字符,然后是文件指针。
程序count.c把stdout作为putc( )的第二个参数。stdout也是在stdio.h中定义的与标准输出相关联的指针,所以putc( ch, stdout )和putchar( ch )的作用是一样的。
既然如此,为何这个例子中要使用putc( )代替putchar( )呢?一个原因是为了介绍putc( )函数,另一个原因是通过使用stdout之外的参数,可以很容易地将这段程序改写为向文件进行输出。
13.2.6 标准文件指针 标准文件 标准输入 标准输出 标准错误输出 文件指针 stdin stdout stderr 一般使用设备 键盘 显示器 显示器 13.4.1 fprintf( )和fscanf( )函数
13.4.2 fgets( )和fputs( )函数
gets( )函数只接受一个参数,而fgets( )函数接受3个。其第一个参数和gets( )一样,用于存储输入的地址(char *类型);第二个参数为整数,表示输入字符串的最大长度;最后一个参数是文件指针,指向要读取的文件。下面是一个函数调用的例子:
fgets( buf, MAX, fp );
这里,buf 是一个char数组,MAX是字符串的最大长度,fp是一个FILE指针。 fgets( )函数读取到它所遇到的第一个换行字符的后面,或者读取比字符串的最大长度少一个的字符,或者读取到文件尾。然后fgets( )向末尾添加一个终止用的空字符以构成一个字符串。所以字符串的最大长度代表字符的最大数目再加上一个空字符。如果fgets( )在达到字符最大数目前读完了一整行,它将在字符串的空字符之前添加一个换行符以标识一行结束。这是它和gets( )之间的不同之处,后者读取换行符后将其丢弃。
与gets( )类似,fgets( )遇到EOF的时候会返回NULL值,可以据此检查文件尾。否则它返回传递给它的地址值。
fputs( )函数接受两个参数:第一个是一个字符串的地址,第二个是一个文件指针。它把字符串地址指针所指的字符串写入指定的文件。和puts( )不同,fputs( ) 列印的时候不会添加一个换行符,下面是一个函数调用的例子:
fputs( buf, fp );
这里buf是字符串地址,fp指定目标文件。 13.5.1 fseek( )和ftell( )如何工作
在fseek( ) 的3个参数中,第一个是一个指向被搜索文件的FILE指针,该文件应已被fopen( )打开。
fseek( )的第二个参数成为偏移量,表示从出发点开始要移动的距离。该参数必须是一个long类型的值,可以为正(前移)、负(后移)或者零(保持不动)。
第三个参数是模式,用来标识出发点。在ANSI下,stdio.h头文件指定了下列模式常量:
模式 SEEK_SET(0) SEEK_CUR(1) SEEK_END(2) 偏移量的起始点 文件起始 当前位置 文件结尾 ftell( )函数为long类型,它返回文件的当前位置。在ANSI下,它在stdio.h中被声明。像最初在Unix中实现的那样,ftell( ) 通过返回距文件开始处的字节数目来确定文件的位置。文件的第一个字节距离为0,依此类推。在ANSI C下,这种定义适用于以二进制模式打开的文件。但是对于文本模式打开的文件来讲,不一定是这样。 13.7.1 int ungetc( int c, FILE *fp )函数
int ungetc( )函数将c指定的字符放回输入流中。如果向输入流中放入了一个字符,下一次调用标准输入函数就会读入该字符。例如,假定需要一个函数读取下一个冒号前的全部字符,但不包括冒号。可以使用getchar( )或getc( )读取直到将冒号读入为止,然后使用ungetc( )将冒号放回输入流中。ANSI C标准保证每次只会放回一个字符。如果一个C实现允许将一行里的多个字符放回输入流,那么输入函数就会以与放回时相反的顺序来读入。 13.7.2 int fflush( )函数
fflush( )的原型是:
int fflush( FILE *fp );
调用fflush( )函数可以将缓冲区中任何未写的数据发送到一个由fp指定的输出文件中去。这个过程称为刷新缓冲区。如果fp是一个空指针,将刷新掉所有的输出缓冲。对一个输入流使用fflush( )的效果没有定义。只要最近一次使用流的操作不是输入操作,就可以对一个更新流(任何读-写模式的流)使用这个函数。 13.7.3 int setvbuf( )函数
setvbuf( )的原型是:
int setvbuf( FILE * restrict fp, char * restrict buf, int mode, size_t size );
setvbuf( )函数建立了一个供标准I/O函数使用的替换缓冲区。打开文件以后,在没有对流进行任何操作以前,可以调用这个函数。由指针fp来指定流,buf指向将使用的缓冲区。如果buf的值不是NULL,就意味着缓冲区必须由你来创建。例如,可以声明一个1,024个字符的数组,然后传递该数组的地址。但是,如果buf的值为NULL,函数会自动为自己分配一个缓冲区。
size变量为setvbuf( )指定数组的大小。size_t类型是根据标准C类型定义的,它是sizeof运算符返回的类型,通常是unsigned int类型,不过具体的实现中可以选择其它类型。
共分享92篇相关文档