C语言学习笔记

一、 标准I\0函数

1, printf(format,arg)按给定的format显示arg的值,就是强制将arg的类型转为format所标示的。注意:在用作printf的参数时float会被转换成double。若执行成功printf返回打印的字符串的数目,否则返回负数。

printf("a b c\n"); ///打印a b c

printf("a" "b" "c\n");///打印abc---也就是说在打印的时候会忽略字符之间的空格

printf("a b"

"c\n"); ///打印a bc

如下代码演示:

float n1=3.0;

double n2=3.0;

long n3=2000000;

long n4=1234567890;

printf(“%ld,%ld,%ld,%ld\n”,n1,n2,n3,n4);会打印0,1074266112,0,1074266112

因为它会告诉计算机把变量n1,n2,n3,n4的值传递给计算机,计算机把它们放置到被称为堆栈(stack)的一块内存区域中来实现。计算机会根据变量的类型而非转换说明符把这些值放到堆栈中。所以n1在堆栈中占8个字节(float被转成double),同样n2占用8个字节,而n3,n4分别占用4字节。然后控制权转移到printf函数中,该函数从堆栈中把值读取出来,但读取时是根据转换说明符来的。%ld转换说明符指出,printf应该读取4字节,所以printf在堆栈中读取前4字节作为它的第一个值,这就是n1的前半部分,它被解释成一个长整数,第二个说明符%ld再读取4字节,这就是n1的后半部分,它被解释成第二个长整数。同样第三个和第四个%ld使得n2的前半部分和后半部分被读出并被解释成两个长整型,所以尽管n3,n4的说明符正确但printf仍然读取了错误的字节。

printf打印字符串时需要一个字符串的地址作为arg参数(同puts)。

2, scanf(format,&v ar)将输入的字符串转换成format指定的格式,它使用空格、换行、制表符将输入分成几段,依次对应着相应的format转换说明符(%c例外,它可以接受一个空白字符作为输入)。

以%d为例说明:scanf每次读取一个输入字符将会跳过空白字符直接到遇到一个非空白字符,因为它试图读取一个整数,所以当它发现一个数字或者符号就保存下来并读取下一个字符,再发现一个数字也同样保存并读取下一个字符,直到遇到一个非数字字符时它就得出结论已读取整数的尾部,并把这个非数字字符放回输入。所以当程序下一次开始读取输入时它将从前面被放弃的那个非数字字符开始,最后scanf计算读取的数字的值并把它放到指定的变量里。若第一个非空白字符非数字而是一个字母A,这时scanf停在那里并把A放回输入,并没有赋给指定的变量任何值,下一次读取输入时就从A开始,这时程序会停止读取输入。

%s说明符会读取一个单词,可以接受除了空白字符以外的任何字符直到遇到一个空白字符为止,当它把字符串放到指定的数组中时会添加终止符’\0’使数组成为一个字符串。

%c说明符会读取包括空白符在内的一切字符,但当使用” %c”之类的format时scanf会跳到空白字符去读取一个非空白字符。

如果使用了字符宽度,则在宽度或者第一个空白字符二者中最先到达的一个字符终止。

若scanf成功时返回读取的项目的个数,没有读取任何字符时返回0,检测到结尾时返回EOF值。

Scanf(“%d,%d”,&m,&n);会被解释为先输入一个数字,再输入一个逗号,再输入一个数字。在两个说明符之间放一空格如“%d %d”可以保证即使第一个读取的值溢出了也不会影响第二值的输入。

3, getchar()函数没有参数,它返回来自输入设备的下一个字符,如读取一个字符给ch=getchar(),它等同于scanf(“%c”,&ch);

4, putchar()用来输出一个字符,如putchar(ch)等同于printf(“%c”,ch);都接受空白字符(换行符、空格符等);

5, gets():返回一个指向char类型的指针,但不检查预留存储区是否能够容纳实际输入的字符串,遇到回车符即终止,此时会在接收的字符串(不包括换行符)的末尾添加一个空字符’\0’。

6, fgets(arr,length,fileHandle)是为文件I/O而设计的,返回一个指针,与gets不同的是可以用第二个参数控制接收字符的长度,会接收换行符,第三个参数控制读入字符串的来源,如stdin或者打开的文件句柄。

7, puts()接受一个指针,将该指针以后的字符串打印出来,直到遇到空字符’\0’,显示的时候自动在其后添加一个换行符。

8, fputs()函数跟puts差不多,但需要第二个参数来指明写入的文件,可使用stdout输出到显示器,不会为输出添加换行符。

9, 有关字符输入和输出的机制说明:

输入的字符立即回显是非缓冲或者直接输入的一个实例,它表示健入的字符对正在等待的程序立即变为可用。而延迟回显是缓冲输入的实例,在这种情况下健入的字符被收集在一个被称为缓冲区的临时存储区域内。

缓冲分为两类:完全缓冲I/O和行缓冲I/O。对完全缓冲输入来说,缓冲区满时被清空(内容被发送到目的地),常用于文件输入中,缓冲区的大小取决于系统,512字节或者4096字节较为常见。对行缓冲输入来说,遇到一个换行符时将清空缓冲区,健盘输入是行缓冲,按下回车即清空缓冲区。

二、 数组与指针

1, 声明数组:

float arr[20];

int arr[]={1,2,3,4,5,6};

int arr[30] = {31,28,[4]=27,24,[1]=13};

也可指定键值(只有初始化的时候才可以这么用,初始化之后只能单个单个的赋值,数组名即为数组首元素的地址,即int *ptr=&arr[0] 也等于 arr,++比*号的优先级高)。

2, 不要对未初始化的指针取值。

3, 有关const的用法:可以对传递给函数的数组、指针等参数提供保护,使其不被修改。还可以创建数组常量、指针常量以及指向常量的指针。

int sum( const int arr[], int n );原型

int sum( const int arr[], int a ){}定义

在sum函数中虽然传递的是数组,但其值是不能修改的。

也可对全局变量的定义时加上此关键字,此时起到了保护数据的作用,如:

const double PI=3.1415926;

const int arr[]={1,2,3};

这里PI和arr的值是不能修改的,跟#define定义的常量效果一样。

double rates[] = {};

double * const pc=rates;

指针pc的指向是不能修改,但数组rates是可以被修改的。

const double * const pc = rates;

指针pc的值不能修改,只能指向rates的第一个单元,而且数组rates的值也不能被修改,也可写为double const * const pc=。

总之:const位于*号左边任意位置使指针指向的数据不可变,若位于*右边的任意位置则使指针本身的值不可变。

在用于定义指针的时候表示数组的[]和表示函数的()具有同样的优先级,并且都比*高,结合的时候从左到右进行,如int *pax[2];为一指针数据。

指向函数的指针:函数名即为函数的首地址,如void (*fp)()可以指向函数void func();

void *func()则为返回指针的函数。

三、 字符串

1, 常符串常量属于静态存储类,静态存储类就是如果在一个函数中使用字符串常量,即使多次调用了这个函数该字符串在程序的整个运行过程中只存储一份,整个双引号中的内容作为指向该字符串第一个字符的存储位置的指针,如下:

sprint(“ %s, %p, %c”,”we”, “are”, *”space”);将打印如下结果we,0x0040c010,s,we作为%s的参数打印出,而are作为一个地址用%p打印出,*”space”是表示用*获取此地址的第一个内容,故打印出s字符。

若字符串之间没有间隔或者是空格符,会将期串连起来:

char tmp[] = “ab” “c”;

字符数组就比字符串在尾部少个’\0’符号。

2, 通常情况下被引用的字符串存储在可执行文件的数据段部分,当程序被加载到内存中时,字符串也一起被加载到内存中,位于静态存储区。只有在运行开始运行后才为数组分配存储空间,这时候才把被引用的字符串复制到数组中,此后编译器会把数组名arr看作是数组首元素的地址。在数组形式中,数组名arr是个地址常量始终指向字符串首并且不能被修改。可以用arr+1来标示下一个元素,但不能用++arr,即数组的元素是变量但数组名arr不是变量。而char (*ptr)[]形式的数组也存储在静态存储区,还要为指针ptr本身分配存储位置,这个指针初始化时指向字符串的第一个字符,但是它的值是可以改变的,如++ptr将指向第二个元素。

总之:数组初始化是从静态存储区把一个字符串复制给数组,而指针初始化只是复制字符串的地址,如下示例将打印:Klingon:Flingon

char *ptr = “Klingon”;///推荐使用const char *ptr=”s”;

ptr[0] = ‘F’;

printf(“Klingon”);

printf(“:%s”,”Klingon”);

再如下例所示:

char *msg=”wendao”;printf(“%s,%p,%p”,msg,&msg,msg);将打印:

wendao,0x0012ff48,0x0040a000

3, 读入字符串的时候要先分配足够大的存储空间,再读入字符串,如果char *name;scanf(“%s”,name);若输入超过了name的空间会将其他地址覆盖掉,所以尽量不要这么做。

4, 常用的字符串操作函数:

strlen返回字符串的长度。

strcat(str1,str2):将str2拷贝到str1的结尾使str1成为一个新的字符串,并返回str1的地址,str2不会改变。不会检查str1能否容纳下str2。

strncat(str1,str2,num):类似于strcat,但多了第三个参数指明最多允许添加的字符数目,或者遇到空字符为止。

strcmp(str1,str2):按ASCII比较两个字符串的内容,只比较空字符以前的部分。Str1>str2返回负数,<则返回正数,=返回0;

strncmp(str1,str2,num):只比较指定的字符数。

strcpy(str1,str2):将str2指针指向的字符串复制到str1指向的空间里,返回str1的指针,但不做溢出检查,str1也可以不是一个字符串的开始位置,中间位置也可以,将从str1指向的位置开始复制。

strncpy(str1,str2,num):类似于strcpy,但只拷贝指定数目的字符。

sprint(str,format,arg):将结果写到字符串里而不是像printf那样直接输出显示。

strchr(str,char c):返回c在字符串str的第一个位置,空字符’\0’也是str的一部分,因此也可以搜索它。【返回第一个位置的指针,可以用 result-str得出该字符在此字符串中的位置,如果没搜索到,返回NULL】

strrchr(str,charc):返回c在字符串str的最后一个位置。

strstr(str1,str2):返回字符串str2在str1中第一次出现的地方,没找到就返回空。

strpbrk(str1,str2):返回str2中任何一个字符在str1中的第一个位置,没找到就返回空。

5, 其他转换函数:

atoi:将字符串转为数字int型。

atof:将字符串转为double型。

atol:将字符串转为long类型。

四、 变量作用域

1、 概念说明

作用域:C变量的作用域共有代码块作用域、函数原型作用域、文件作用域。一个在所有函数之外定义的变量具有文件作用域。

链接:C变量的链接共有外部链接(external linkage)、内部链接(internal linkage)、空链接(no linkage)。具有代码块作用域或者函数原型作用域的变量为空链接,意味着它们是所在代码块私有的。具有文件作用域的变量可为外部或者内部链接,外部链接可在一个多文件程序的任何地方访问,内部链接则只能在所在的文件内访问。

存储时期:C变量共有静态存储时期和自动存储时期。具有静态存储时期的变量在程序运行期间一直都存在,具有文件作用域的变量都有静态存储时期(不管是内部链接还是外部链接)。对文件作用域的变量static表示其链接类型而非存储时期(表示为内部链接,若省略static表示为外部链接)。

2、 寄存器变量:

使用register关键字声明,存在CPU内,所以范围受到限制,也不能获取其地址。

3、 具有代码块作用域的变量:

自动变量:此类变量具有自动存储时期、代码块作用域和空链接,在该代码块执行完后自动消失。也可以使用auto显式的声明该变量(可省略,只起到使意途更明显的作用),若和代码块外层的变量重名时,将覆盖外层的变量。

静态变量:此类变量使用static关键字声明,从该代码块第一次执行时就一直存在。但不能对函数的参数使用此关键字,如int func(static int num)这是错误的。

4、 具有文件作用域的变量:

此类变量都在函数之外定义,都具有静态存储时期。若用static定义则该变量具有内部链接,即只能在该文件内访问。否则具有外部链接,其他文件也可以访问。若在本文件内使用具有外部链接的变量时可以用extern声明一下,但若在本文件使用其他文件的具有外部链接的变量必须用extern声明,引用外部变量时不得再次初始化,即外部变量只能在定义的时候初始化,若没有初始化则自动被赋值0。

int num;

extern int var;//var在其他文件定义,这里要使用必须这样声明,否则会再定义一个var

int func(){

extern int num;//可选声明

extern int num=0;///错误,不得再次初始化,只能在定义的时候初始化,这样的声明不改变变量的链接,即可以用于外部链接的变量也可以用于有内部链接的,

}

如果希望常量的链接性为外部的,则可以使用extern关键字来覆盖默认的内部的链接性,如:extern const int a=50;///必须在所有使用该常量的文件中使用extern来声明它

5、 函数跟变量一样也有链接的概念:

int func(){}///默认具有外部链接

static int func(){}///只能在本文件内访问

extern int func(){}显示声明外部链接,可以其他文件访问,主要是为了使程序更加清晰。

6、 其他关健字:

Volatile:表明即使程序没有对内存单元进行修改,其值也可能会变化,如硬件触发的变化,告诉编译器不要缓存此值。

Mutable:即使结构(或者类)变量为const,某个成员也可以被修改,如

Struct data{ char name[20]; mutable int num;}

Const data veep={…….};

此时veep中,name成员的值不可被修改,但num的值可以修改。

五、 文件输入/输出

1, 常用的文件输入和输出函数:

fopen(filename,style):filename是文件名,确切的说是一个包含文件名的字符串的地址。style是打开文件的模式,如r读取文件、w写入文件(存在就截为0不存在就创建)、a向文件中追加内容(不存在则创建之)、r+读取和写入文件、 w+读取和写入文件(存在则截为0不存在则创建之)、a+读取文件和追加内容。返回一个指向FILE结构的指针。

getc和putc:与getchar/putchar类似每次只读取一个字符,不同的是需要告诉getc/putc它们要使用的文件。如ch=getc(fp);putc(ch,fout);

fclose(fp):关闭由指针fp指定的文件,并根据需要刷新缓冲区,成功则返回0否则返回EOF。

fprintf()、fscanf():工作方式与printf/scanf相似,不过fprintf/fscanf需要第一个参数来指定合适的文件。如char word[]; fscanf(fp,”%s”,word)等。

fgets()、fputs():fgets(字符串指针,max,fp)从文件中读取数据到指定的字符串中,直到遇到换行符或者超过max,然后fgets向末尾添加一个空字符’\0’以构成一个字符串。如果在达到max之前读完了一行,它将在字符串的空字符之前添加一个换行符以标识一行的结束,遇到EOF返回NULL值。fputs(字符串地址,fp):将字符串地址所指的字符串写到文件fp里,并不添加换行符,所以要手动添加。

fseek()、ftell():fseek(文件指针,偏移量,起点位置标志:SEEK_SET文件开始、SEEK_CUR当前位置、SEEK_END文件结束),设置文件的当前位置,返回int值()。ftell(fp)返回距文件始处的字节数目来确定文件的位置,第一个字符为0。

fread(void * ptr,块大小,块数,fp)从文件中读数据到ptr所指的存储区里,如:

char buffer[255]; double num[255];

fread(buffer,256,2,fp); fread(num,256,1,fp);

fwrite(const void * restrict ptr,块大小,块数,fp)将ptr所指空间的数据写入到文件中,跟fread一样,ptr可以为字符串也可以为double型数组,可以不固定,这两个函数都是面向二进制的I/O函数。

feof(fp)和ferror(fp):检测文件是否到了结尾或者出错。

2, 标准文件输入和输出函数内部机制说明:

C自动打开三个文件,stdin标准输入、stdout标准输出、stderr标准错误输出。

低级I/O:使用操作系统提供的基本I/O服务,依赖于特定的操作系统,可移植性较差。

标准I/O:使用一个标准的C库函数包和stdio.h头文件中定义的各种函数,可移植到不同的系统上,并且还对输入输出进行了缓冲,大块的转移信息(通常每次不少于512字节)而不是每次一个字节的进行转移,当程序读取一个文件时会把一大块数据复制到缓冲区中,随后程序就可以分析缓冲区中的个别字节,缓冲过程是在后台处理的,这大大提高了数据传输率。

通常使用标准I/O的第一步是用fopen打开一个文件(stdin,stdout,stdout是自动打开的),fopen不仅打开一个文件而且建立一个缓冲区(在读写模式下建立两个缓冲区),还创建了一个包含文件和缓冲区相关数据的数据结构,同时返回一个指向该数据结构的指针,供其他函数知道如何找到该结构(如将此指针赋给fp),我们称fopen函数打开了一个流,如果文件以文本模式打开就可以得到一个文本流,如果以二进制模式打开就得到一个二进制流。

这个数据结构通常包含一个文件位置指示器,以确定在流中的当前位置,还包括错误指示器、文件结尾指示器、一个指向缓冲区起始处的指针、一个文件标识符和一个记录实际复制到缓冲区中的字节数的计数器。

当文件输入的时候,一般是调用stdio.h头文件中声明的某个输入函数,如fscanf、getc、gets等,调用这些函数中的任意一个都会把一块数据从文件复制到缓冲区中,缓冲区的大小依赖于具体的实现,通常是512字节的倍数。除了填充缓冲区外,初次函数调用还将fp指针所指数据结构中的值,如设置流的当前位置和复制到缓冲区中的字节数,通常当前字节从0开始。数据结构和缓冲区初始化以后输入函数将从缓冲区中读取所请求的数据,同时,文件位置指示器被设置为紧随最后一个被读取字符的位置。因为stdio.h定义的所有的输入函数都使用同一缓冲区,所以任何一个被调函数都将在前一次任何函数调用停止的地方继续开始。

当输入函数检测到已经读取了缓冲区中的全部字符时,它会请求系统将下块缓冲区大小的数据复制到缓冲区,通过这种方式,输入函数可以读入文件中的全部内容,直到文件结尾。函数在读入最后一缓冲区数据中的最后一个字符后,会将文件结尾指示器的值设置为真,于是下一个被调用的输入函数将返回EOF。

以类似的方式,输出函数将数据写入缓冲区,当缓冲区满时,就将数据复制到文件中。

六、 预处理器

1、 程序编译步骤:

首先编译器对程序进行几次翻译处理,如将源码中出现的字符映射到源字符集。

再次查找反斜线后紧跟换行符的实例并删除这些实例,如将

printf(“wendao\

liu\n”);

替换为printf(“wendaoliu”);

最后编译器将文本划分成预处理的语言符号序列和空白字符及注释序列。

最后进入预处理阶段,预处理指令是以#开头,到其后的第一个换行符为止,预处理过程不进行计算,只是简单的替换。

2、#define:明显常量,每个语句由三部分组成,即#define本身、选择的缩略语(也叫宏,要位于双引号之外)、替换部分。

#define TWO 2; ///定义的常量

#define SQURE(X) X*X;//函数宏,只是进行简单的替换,如SQURE(3+4)替换为3+4*3+4;

#define XNAME(n) x##n;///粘合剂,如XNAME(2)被替换成x2

3、#include:文件包含

#include <stdio.h> ///先找标准系统目录

#include “my.h” ///先找当前目录,找不到再找标准系统目录

4、#undef:取消某常量的定义,如之前定义过一个常量#define LIMIT 20;可以#undef LIMIT;取消定义。

5、#ifdef、#else、#endif、 #ifndef:条件编译指令,这块条件指令可以嵌套,但不能有{}

#ifdef MAVIS

include “horse.h”;

#else

include “monkey.h”;

#endif

6、#if、#elif:也是条件编译指令,支持关系和逻辑运算符。

#if SYS == 1

#include “windows.h”;

#elif SYS == 2

#include “ubuntu.h”;

#elif defined(VAX) ///defined是一个预处理器运算符,判断常量是否被定义过

#include “vax.h”;

#else

#include “mac.h”;

#endif

7、#line:用于重置由__LINE__和__FILE__宏报告的行号和文件名,用法如下:

#line 100 ///把当前行号设置为100

#line 10 “cool.c” ///把当前行号设为10,文件名设为“cool.c”

8、#error:使预处理器发出一条错误信息,该信息包含指令中的文本,编译过程应该中断。

#if __STDC_VERSION__ != 199901L

#error not C99

#endif

9、 #pragma:设置编译指令,#pragma c9X on ///打开C99标准

10、预定义宏:

__DATE__:预处理的日期,形如”mm dd yyyy”形式的字符串文字

__TIME__:源文件编译的时间,形如”hh:mm:ss”

__FILE__:当前源文件名的字符串文字

__LINE__:当前源文件中的行号的整型常量

__STDC__:设置为1时,表示该实现遵循C标准

__STDC_HOSTED__:为本机环境设置为1,否则为0

__STDC_VERSION__:为C99时设置为199901L

七、 其他

1, 赋值运算,左边必须是有内存区的。整数类型运算会得到整数类型,浮点型运算会得到浮点型娄值,混合运算则会发生类型转换,取模运算符只能用于整数,赋值语句是表达式语句的特例。

2, sizeof可以操作一个变量名如var或者一个数据类型如int,若操作的是一个类型操作数必须在小括号里,如sizeof(float)。

3, 自增、自运算符优先级较高仅次于小括号,后缀的自增和自减运算符只有当前面的变量被操作后才会执行加减操作。

4, 一个顺序点是程序执行中的一个点:在该点处所有的副作用(如自增、自减等)都会在进入下一步之前被计算。语句里的分号标志了一个顺序点,它意味着在一个语句中的赋值运算符、增量运算符、减量运算符所做的全部改变必须在程序进入下一个语句前发生。任何一个完整的表达式也是一个顺序点。所谓-完整的表达式包括一个表达式语句里的表达式和一个在while循环里做为判断条件的表达式,它不是一个更大表达式的子表达式。如while(var++<10)就是一个完整的表达式,它的结束就是一个顺序点,因为C保证所有的副作用在进入下一个循环前被计算出来。而y=(4+a++)+(6+a++);里的4+a++不是一个完整的表达式,所以C不能保证在计算引子表达式后立即使a自增。C在对逻辑表达式求值时是按从左到右的顺序来进行的,&&和||是序列的顺序点,因此程序在从一个操作符进入下一个操作符之前所有的副作用都会生效,而且C能保证当当发现一个操作符使整体表达式失效,就立即停止。

5, 类型转换朝着较高的级别进行。赋值语句里,计算的结果被转换成被赋值的那个变量的类型。作为函数的参数传递时,传给函数的实参自动转换为形参规定的类型。用(type)var可强制类型转换,如(int)a。

6, 关系运算符可以用于比较字符char类型,比的是机器码,一般是ASCII,但不能用来比较字符串,可用字符串操作的专用函数来比较。在浮点数中比较时只能用<或者>,不要使用等于来比较浮点数。

7, 字符数组就是元素被赋予字符值的数组,若字符数组中包含了’\0’那么此数组就构成了一个字符串。

8, 函数的实形传给形参的时候,如果类型不一致会发生类型的转换。参数是指针时可声明如下:

void func( int *, int * );

void func(int a[], int *);

void func( int [], int n );

void func(int *ptr,int);

但定义函数的时候名称不可省略。

9, 命令行参数:int main( int argc, char *argv )

10,exit()函数:退出程序并返回相应的状态值给操作系统,如失败exit(EXIT_FAILUER)或者成功exit(EXIT_SUCCESS)。

11,内存管理函数:

malloc( n * sizeof(double) )申请n块大小为sizeof(double)的内存空间,返回一个指向char类型的指针,可强制转换(double *)malloc(内存字节数)。

calloc(块数,块大小):返回一个指向char *的指针,它将申请的内存块中的位都置0,如

long *ptr=(long *)calloc(5,sizeof(long));

free释放掉由malloc或者calloc申请的内存空间。

12,结构体和联合体:

结构体定义如下,定义之后和普通的数据类型(如int,float)使用方法一样,

struct book{char name[200];}library;注:此处加个library是直接定义了,也可以不加等用的时候再定义struct book library。还可以省略book标记:struct {char name[200];}library但只能用这一次。

使用结构体:library.name跟普通变量一样,也可以用指针指向结构体,然后调用的时候

ptr->name,结构体里也可包含结构体,但除了指针类型外不能是自己本身的结构体类型,如:

struct book{ struct book *ptr;struct book name;}此处ptr的定义是可以的,但name就不能这么定义。定义结构体的时候不为里面的指针分配任何空间,所以要尽量初始化指针。

一个结构体的名字不是该结构体的地址,所以用的时候必须使用&运算符,如ptr=&library。

联合体:union uname{int digit;char letter;} you;使用方法跟结构体一样,如you.digit,联合体可以为结构体中的一个元素类型(PHP的弱变量类型就是这么弄的);

13,typedef给其他类型定义别名:

typedef unsigned char wendao;以后用wendao定义变量的时候相当于用unsigned char类型的。还可以用来定义指针:typedef char * wendao;使用wendao定义变量的时候该变量就是指向char类型的指针

用typedef来定义结构体时可省略标记,如下面两种定义方法是一样的效果:

typedef struct name{}wendao;可以用wendao代替struct name去定义其他的变量。也可以这样:typedef struct{}wendao;直接用wendao定义变量就是一个结构体。

14、C99标准中的内联函数,在函数声明中使用inline:

inline int eatline(){

printf(“ssssss”);

}

内联函数只是简单的语句替换,所有出现eatline()的地方都会被替换为printf(“sssss”);所以它的效率要比一般的函数高。

编译器没有预留给内联函数单独的代码块,所以无法获取内联函数的地址,也不会在调试器中显示。在优化内联函数时必须知道函数定义的内容,所以函数的定义和对函数的调用必须在同一个文件中,并且函数定义在调用的前面,内联函数通常具有内部链接,每个调用内部函数的文件都必须对该函数进行定义,但也可以将内联函数定义到头文件中,然后其他文件包含该头文件即可,头文件一般不应该包含可执行代码,但内联函数是个例外,所以内联函数一般比较短小。

posted @ 2012-07-25 08:52  奇葩文刀  Views(377)  Comments(0)    收藏  举报